在同一项目整合Blazor与Web API时如何配置Entity Framework
混合Web API与Blazor Server场景下的EF Core配置与使用方案
1. 统一DbContext配置:改用工厂模式
不管是Web API的请求作用域,还是Blazor Server的电路作用域,统一通过IDbContextFactory<TContext>创建DbContext实例,替代直接注入DbContext的方式。这种配置能同时兼容两种场景,避免内存泄漏和数据库异常行为。
在Program.cs中配置:
builder.Services.AddDbContextFactory<YourDbContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")); // 按需添加其他EF配置(如日志、延迟加载等) });
注意:不要再使用
AddDbContext直接注入DbContext,全程采用工厂模式。
2. 业务服务改造:兼容双场景
业务服务依赖IDbContextFactory<YourDbContext>而非直接依赖DbContext,服务本身注册为作用域服务(符合.NET依赖注入最佳实践),在每次业务方法中创建独立的DbContext实例:
示例业务服务代码:
public class ProductService : IProductService { private readonly IDbContextFactory<YourDbContext> _dbContextFactory; public ProductService(IDbContextFactory<YourDbContext> dbContextFactory) { _dbContextFactory = dbContextFactory; } public async Task<List<Product>> GetAllProductsAsync() { using var context = _dbContextFactory.CreateDbContext(); return await context.Products.ToListAsync(); } public async Task<Product?> GetProductByIdAsync(int id) { using var context = _dbContextFactory.CreateDbContext(); return await context.Products.FindAsync(id); } public async Task<Product> CreateProductAsync(Product product) { using var context = _dbContextFactory.CreateDbContext(); context.Products.Add(product); await context.SaveChangesAsync(); return product; } }
在Program.cs中注册服务:
builder.Services.AddScoped<IProductService, ProductService>();
3. Web API端调用方式(无改动)
Web API控制器直接注入业务服务即可,服务内部通过工厂创建的DbContext会随请求结束自动释放,和原有请求作用域的行为完全一致:
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private readonly IProductService _productService; public ProductsController(IProductService productService) { _productService = productService; } [HttpGet] public async Task<IActionResult> GetAll() { var products = await _productService.GetAllProductsAsync(); return Ok(products); } }
4. Blazor Server端调用方式
Blazor组件中直接注入业务服务(作用域服务会绑定到Blazor电路作用域),调用服务方法即可——服务内部每次方法调用都会创建新的DbContext,用完自动释放,不会导致DbContext长期驻留在电路中:
示例Blazor组件代码:
@page "/products" @inject IProductService ProductService @using YourNamespace.Models <h3>产品列表</h3> @if (products == null) { <p><em>加载中...</em></p> } else { <table class="table"> <thead> <tr> <th>ID</th> <th>名称</th> <th>价格</th> </tr> </thead> <tbody> @foreach (var product in products) { <tr> <td>@product.Id</td> <td>@product.Name</td> <td>@product.Price</td> </tr> } </tbody> </table> } @code { private List<Product>? products; protected override async Task OnInitializedAsync() { products = await ProductService.GetAllProductsAsync(); } }
5. 关键注意事项
- 禁止在Blazor组件中直接注入DbContext,否则会因电路作用域的长期持有导致内存泄漏和并发问题
- 业务服务中必须用
using包裹DbContext实例,确保每次使用后及时释放 - 绝对不要在服务中缓存DbContext实例,每个业务方法都要创建新实例,保证数据操作的隔离性
内容的提问来源于stack exchange,提问作者devqon
相关产品推荐
相关产品推荐

