Blazor 服务器:将 EF Core DbContextFactory 与 DbContext 混合
Posted
技术标签:
【中文标题】Blazor 服务器:将 EF Core DbContextFactory 与 DbContext 混合【英文标题】:Blazor Server: Mixing EF Core DbContextFactory with DbContext 【发布时间】:2021-05-03 19:24:33 【问题描述】:我正在为现有域层构建 Blazor 服务器前端。该层提供各种可注入服务来对 EF Core 存储库进行修改。为此,服务本身从(标准 Microsoft)DI 容器请求 DbContext。这适用于具有范围 DbContext 实例的常规 MVC.NET/Razor 页面,但作为 documented,这对于 Blazor 来说是有问题的。在 Blazor Server 应用程序中,我们希望使用 DbContextFactory 来生成用于操作的短期 DbContext 实例。
在同一个应用程序中同时拥有 DbContext 和 DbContextFactory 没有问题,但我很难理解如何调整我的服务。或者如果我什至需要?为了说明,这是当前代码:
我的页面:
@page “/items”
@inject ItemService ItemService
// somewhere in the code
ItemService.DoOperation(…)
我的服务
class ItemService
public ItemService(MyDbContext myDbContext)
…
public bool DoOperation(…)
…
_myDbContext.SaveChanges();
Startup.cs:
services.AddDbContext<MyDbContext>(options => …),
contextLifetime: ServiceLifetime.Transient,
optionsLifetime: ServiceLifetime.Singleton
);
services.AddDbContextFactory<MyDbContext>(options => …);
我已经根据this answer 中给出的示例更改了 DbContext 的生命周期,到目前为止,我还无法创建任何问题,但我并不完全理解这里的生命周期问题。如何设计我的服务以在 Blazor 和 MVC/Razor Pages 应用程序中以一种明显的方式良好运行?
【问题讨论】:
只是一个更新:在 EF Core 6 中,AddDbContextFactory 现在还注册了 DbContext,因此不再需要单独注入它们。 【参考方案1】:在典型的 MVC 应用程序中,一个请求代表一个工作单元。 DbContext 作为范围服务生成并通过构造函数注入。这很好。
另一方面,在 Blazor Server 中,一个请求不再代表单个工作单元。第一个请求创建了一个电路,这意味着注入的任何作用域服务都将具有如here 所述的生命周期。
在 Blazor Server 应用中,工作单元是 SignalR 消息。 (例如,单击按钮将新行添加到数据库)。因此,直接注入您的上下文is not the way to go。
这就是 Blazor Server 具有 IDbContextFactory<T>
的原因。像这样初始化它:
services.AddDbContextFactory<DbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("WebDB")));
在 Razor 组件(绑定到 Blazor 应用程序)中,您可以这样使用它:
private readonly IDbContextFactory<DbContext> factory;
public Component(IDbContextFactory<DbContext> f)
factory = f;
public void Click()
using(DbContext cnt = factory.CreateDbContext())
// Your code here
这将进一步解释here。
文档:ASP.NET Core Blazor Server with Entity Framework Core (EFCore)。
【讨论】:
是的,这就是我现在为从 Blazor 直接访问 EF Core 所做的事情。问题在于我使用的现有服务当前注入 DbContext 而不是 DbContextFactory。这一定是一个普遍的问题,但我看到没有人谈论它。 [礼貌] 为什么要通过 EF 从组件直接访问数据库?这将组件与 Blazor Server 联系在一起,在我的(个人)设计书中,这是不可以的。我知道 MS Docs 链接显示这样做,但是 .... @MrCakaShaunCurtis 我只是展示官方文档。就个人而言,我会为数据访问创建一个单独的服务,并在我需要的地方注入它。总而言之,取决于开发人员他们使用什么方法。 @Grizzlly - 很高兴听到。 :-) @martijn 使用服务的正确方法是什么【参考方案2】:问题是传递性的:您的服务依赖于应该是范围内的资源,并且仅当您将这些服务也注册为范围内时才有效。你不能。
正确的方法是将服务重写为 DbContext per Operation 模型,并注入 DbContextFactory。
看起来您已经有了一个混合模型(每个操作都有一个 SaveChanges,它们实际上是一个 UoW)。
当您不想进行这些更改时,您可以通过将 DbContext 注册为 Transient 来解决问题。这感觉很糟糕,但它旨在快速释放底层连接。所以看起来不像是资源泄漏。
【讨论】:
以上是关于Blazor 服务器:将 EF Core DbContextFactory 与 DbContext 混合的主要内容,如果未能解决你的问题,请参考以下文章
Blazor WebAssembly+Duende.IdentityServer+EF Core认证授权企业级实战
Blazor WebAssembly+Duende.IdentityServer+EF Core认证授权企业级实战
Blazor WASM+Duende.IdentityServer+EF Core认证授权企业级实战
Blazor WASM+Duende.IdentityServer+EF Core认证授权企业级实战