ASP.NET Core Web API 结合 Entity Framework Core (EF Core) 的分层项目架构是一种常见的开发模式,旨在通过职责分离提高代码的可维护性、可测试性和扩展性。
分层架构将应用按功能划分为多个逻辑层,各层职责明确,通过接口或 DTO(Data Transfer Object)通信。
Presentation层 (Web API) - 处理 HTTP 请求/响应
Application层 - 业务逻辑和用例实现
Domain层 - 实体模型和仓储接口
Infrastructure层 - EFCore 实现和数据库配置
MyAspNetCoreWebApplication.sln
├─ MyAspNetCoreWebApplication.MyWebApplication(ASP.NET Core Web API)
├─ MyAspNetCoreWebApplication.ApplicationLibrary(Class Library)
├─ MyAspNetCoreWebApplication.DomainLibrary(Class Library)
└─ MyAspNetCoreWebApplication.InfrastructureLibrary(Class Library)
Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.Tools
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.EnvironmentVariables
public class Book
{
public long Id { get; set; }
public string Title { get; set; }
public double Price { get; set; }
public string AuthorId { get; set; }
public string AuthorName { get; set; }
}
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
}
public interface IBookRepository
{
Task<IEnumerable<Book>> GetAllAsync();
Task<Book> GetByIdAsync(long id);
Task AddAsync(Book book);
Task DeleteAsync(long id);
Task UpdateAsync(Book book);
}
public interface IProjectRepository
{
Task<IEnumerable<Product>> GetAllAsync();
Task<Product> GetByIdAsync(long id);
Task AddAsync(Product project);
Task DeleteAsync(long id);
Task UpdateAsync(Product project);
}
数据库上下文类
目录结构:InfrastructureLibrary-Data
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<Product> Projects { get; set; }
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
internal class MyDbContextDesignFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
// 手动构建配置(读取环境变量)
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables() // 添加环境变量作为配置源
.Build();
string connStr = configuration.GetSection("ConnStr").Value;
if (connStr == null)
{
throw new Exception("连接字符串为空");
}
DbContextOptionsBuilder<MyDbContext> opt = new DbContextOptionsBuilder<MyDbContext>();
opt.UseSqlServer(connStr);
return new MyDbContext(opt.Options);
}
}
配置类
目录结构:InfrastructureLibrary-Config
public class BookConfig : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder.ToTable("T_Books");
}
}
public class ProductConfig : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.ToTable("T_Products");
builder.Property(p => p.Name).HasMaxLength(100).IsRequired();
builder.Property(p => p.Price).HasColumnType("decimal(18,2)");
}
}
实现类Repositories
目录结构:InfrastructureLibrary-Repositories
public class BookRepository
{
private readonly MyDbContext _dbContext;
public BookRepository(MyDbContext context)
{
_dbContext = context;
}
public async Task<IEnumerable<Book>> GetAllAsync()
=> await _dbContext.Books.ToListAsync();
public async Task<Book> GetByIdAsync(long id)
=> await _dbContext.Books.FindAsync(id);
public async Task AddAsync(Book book)
{
if (book != null)
{
await _dbContext.Books.AddAsync(book);
await _dbContext.SaveChangesAsync();
}
}
public async Task DeleteAsync(long id)
{
Book p = await GetByIdAsync(id);
if (p != null)
{
_dbContext.Books.Remove(p);
await _dbContext.SaveChangesAsync();
}
}
public async Task UpdateAsync(Book book)
{
if (book != null)
{
_dbContext.Books.Update(book);
await _dbContext.SaveChangesAsync();
}
}
}
public class ProductRepository : IProjectRepository
{
private readonly MyDbContext _dbContext;
public ProductRepository(MyDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<IEnumerable<Product>> GetAllAsync()
=> await _dbContext.Projects.ToListAsync();
public async Task<Product> GetByIdAsync(long id)
=> await _dbContext.Projects.FindAsync(id);
public async Task AddAsync(Product project)
{
if (project!=null)
{
await _dbContext.Projects.AddAsync(project);
await _dbContext.SaveChangesAsync();
}
}
public async Task DeleteAsync(long id)
{
Product p=await GetByIdAsync(id);
if (p != null)
{
_dbContext.Projects.Remove(p);
await _dbContext.SaveChangesAsync();
}
}
public async Task UpdateAsync(Product project)
{
if (project != null)
{
_dbContext.Projects.Update(project);
await _dbContext.SaveChangesAsync();
}
}
}
public class BookService
{
private readonly IBookRepository bookRepository;
public BookService(IBookRepository bookRepository)
{
this.bookRepository = bookRepository;
}
public async Task<IEnumerable<Book>> GetAllBookAsync()
{
return await bookRepository.GetAllAsync();
}
public async Task<Book> GetBookById(long id)
{
return await bookRepository.GetByIdAsync(id);
}
public async Task AddBook(Book book)
=> await bookRepository.AddAsync(book);
public async Task UpdateBook(Book book)
=> await bookRepository.UpdateAsync(book);
public async Task DeleteBook(long id)
=> await bookRepository.DeleteAsync(id);
}
public class ProductService
{
private readonly IProjectRepository _repository;
public ProductService(IProjectRepository repository)
{
_repository = repository;
}
public async Task<IEnumerable<Product>> GetAllProjectAsync()
{
return await _repository.GetAllAsync();
}
public async Task<Product> GetProductById(long id)
{
return await _repository.GetByIdAsync(id);
}
public async Task AddProduct(Product product)
=>await _repository.AddAsync(product);
public async Task UpdateProject(Product product)
=> await _repository.UpdateAsync(product);
public async Task DeleteProduct(long id)
=> await _repository.DeleteAsync(id);
}
Program.cs 配置
using DomainLibrary.Repository;
using InfrastructureLibrary.Repositories;
using Microsoft.EntityFrameworkCore;
using ApplicationLibrary.Services;
using InfrastructureLibrary.Data;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
//配置数据库
builder.Services.AddDbContext<MyDbContext>(opt => {
string connStr = builder.Configuration.GetConnectionString("DefaultConnection");//GetSection("ConnStr").Value;
opt.UseSqlServer(connStr);
});
// 注册仓储
builder.Services.AddScoped<IProjectRepository, ProductRepository>();
//注册服务
builder.Services.AddScoped<ProductService>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 自动迁移数据库(可选)
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();
db.Database.Migrate();
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
appsettings.json配置
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=XXX;Database=XXX;User Id=sa;Password=XXX;TrustServerCertificate=True;Trusted_Connection=True;MultipleActiveResultSets=True"
}
}
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
private readonly MyDbContext _db;
private readonly ProductService _productService;
public TestController(MyDbContext db, ProductService productService)
{
_db = db;
_productService = productService;
}
[HttpGet]
public ActionResult<string> Get()
{
var count= _db.Books.Count();
return $"count={count}";
}
[HttpGet]
public async Task<IActionResult> GetAllProductsAsync()
{
var res=await _productService.GetAllProjectAsync();
return Ok(res);
}
}
Add-Migration Init
Update-Database
分层架构在 ASP.NET Core Web API + EF Core 项目中通过职责分离提升了代码质量,但需要权衡设计复杂度和实际需求。通过合理分层、依赖注入和接口抽象,可以构建高可维护、可测试的应用程序,同时避免过度设计。最终,架构选择应服务于业务需求,而非盲目追求分层形式。