You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在同一项目整合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:02:11