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&lt;T&gt; 的原因。像这样初始化它:

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认证授权企业级实战

EF Core 在对现有查询添加查询时附加所有实体 [重复]

使用整数用户 ID 扩展 EF Core Identity UserStore