【问题标题】:Responsive UI design causing problems for Entity Framework in Blazor application [duplicate]响应式 UI 设计导致 Blazor 应用程序中的实体框架出现问题 [重复]
【发布时间】:2020-03-01 02:55:33
【问题描述】:

我熟悉编写响应迅速的 ASP.NET MVC 应用程序,我们在其中加载初始页面数据,然后触发多个 AJAX 调用以加载页面的“辅助”数据。所以在幕后,这些 AJAX 请求几乎同时到达 Web 服务器并从我们的 SQL 数据库中提取数据。

我设想使用 Blazor 应用程序做一些非常相似的事情。所以,我们会用一些数据加载页面,然后有多个组件,然后在页面上显示附加数据;这些组件的加载可以通过用户操作或页面上的某些其他事件来初始化。

这就是我看到一个问题的地方:事件处理程序对 razor 页面上的各种组件触发的事件都做出了非常好的反应,然后它们都点击了我们的 DataService(注入到页面中),这会导致很多线程击中我们的实体框架的上下文。

这是不允许的——任何时候只有一个线程可以调用上下文。

为了解决这个问题,我可以使用 SemaphoreSlip(1,1) 锁定上下文,以确保任何时候只有一个线程可以访问,但这对我来说似乎有点瓶颈。肯定锁定上下文不是微软希望我们做的事情......??

我在这里错过了什么?

我正在使用 Blazor-Server、.NET Core 3.1/EF Core 3.1。在我的应用启动时,我正在为 DI 设置 EF 上下文和服务:

services.AddDbContext<MyContext>();
services.AddScoped<MyService>();

Context 被注入到 Service 的构造函数中(根据 Microsoft 的 Blazor 示例),Service 被注入到 Page。

【问题讨论】:

标签: entity-framework entity-framework-core blazor blazor-server-side


【解决方案1】:

看起来 Blazor 中的“Scoped”服务的范围是客户端会话,而不是 HTTP 请求,就像在 ASP.NET 中一样。

Blazor 服务器托管模型支持 Scoped 生命周期。在 Blazor 服务器应用,范围服务注册的范围为 连接。

https://docs.microsoft.com/en-us/aspnet/core/blazor/dependency-injection?view=aspnetcore-3.0#add-services-to-an-app

因此,您可以为 DbContext 使用“瞬态”生命周期,或者简单地将 DbContext 实例创建为 using 块或语句中的局部变量。见

https://github.com/aspnet/AspNetCore/issues/10448

关于这个问题的扩展讨论。

【讨论】:

  • Transient 是不够的,create a new scope 或你的方法(使用using)是方法。
  • @David Browne:从上面更改为 ``services.AddTransient(); services.AddScoped();` 但这抛出了System.AggregateException: 'Some services are not able to be constructed'。使 MyService Transient 也出现同样的问题。在方法中创建上下文有效
  • 我对@9​​87654324@ 提出了关于新上下文与锁定现有上下文的进一步评论。我真的很想了解每种方法的优缺点。
  • 我将发布到 issue 10448 活动。
  • 最终解决方案是:Razor Page '@inherits OwningComponentBase' Startup services.AddDbContext&lt;MyContext&gt;(); services.AddScoped&lt;MyService&gt;();
【解决方案2】:

Blazor 与 MVC 的不同之处在于页面始终处于“活动状态”。想想“Windows 窗体”而不是“Web 窗体”。您不会进行“Ajax 调用”,因为无需避免回发。

见: Creating A Step-By-Step End-To-End Database Server-Side Blazor Application

public class MyService
{
    private readonly MyContext_context;
    public MyService(MyContext context)
    {
        _context = context;
    }
    public Task<List<WeatherForecast>>
        GetForecastAsync(string strCurrentUser)
    {
        List<WeatherForecast> colWeatherForcasts =
            new List<WeatherForecast>();
        // Get Weather Forecasts  
        colWeatherForcasts =
            (from weatherForecast in _context.WeatherForecast
                 // only get entries for the current logged in user
                 where weatherForecast.UserName == strCurrentUser
             select weatherForecast).ToList();
        return Task.FromResult(colWeatherForcasts);
    }
}

【讨论】:

  • 提供的链接表明我正在做我已经在做的事情。
  • 您没有说明您是如何使用它的,这部分很重要,因为虽然其他人建议将使用它的代码包装在“使用”中,但我发现这需要每个实例化连接时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多