Blazor concurrency problem using Entity Framework Core

后端 未结 6 1574
半阙折子戏
半阙折子戏 2021-01-05 03:46

My goal

I want to create a new IdentityUser and show all the users already created through the same Blazor page. This page has:

  1. a form
6条回答
  •  孤独总比滥情好
    2021-01-05 04:39

    UPDATE (08/19/2020)

    Here you can find the documentation about how to use Blazor and EFCore together

    UPDATE (07/22/2020)

    EFCore team introduces DbContextFactory inside Entity Framework Core .NET 5 Preview 7

    [...] This decoupling is very useful for Blazor applications, where using IDbContextFactory is recommended, but may also be useful in other scenarios.

    If you are interested you can read more at Announcing Entity Framework Core EF Core 5.0 Preview 7

    UPDATE (07/06/2020)

    Microsoft released a new interesting video about Blazor (both models) and Entity Framework Core. Please take a look at 19:20, they are talking about how to manage concurrency problem with EFCore


    General solution

    I asked Daniel Roth BlazorDeskShow - 2:24:20 about this problem and it seems to be a Blazor Server-Side problem by design. DbContext default lifetime is set to Scoped. So if you have at least two components in the same page which are trying to execute an async query then we will encounter the exception:

    InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread-safe.

    There are two workaround about this problem:

    • (A) set DbContext's lifetime to Transient
    services.AddDbContext(opt =>
        opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Transient);
    
    • (B) as Carl Franklin suggested (after my question): create a singleton service with a static method which returns a new instance of DbContext.

    anyway, each solution works because they create a new instance of DbContext.

    About my problem

    My problem wasn't strictly related to DbContext but with UserManager which has a Scoped lifetime. Set DbContext's lifetime to Transient didn't solve my problem because ASP.NET Core creates a new instance of UserManager when I open the session for the first time and it lives until I don't close it. This UserManager is inside two components on the same page. Then we have the same problem described before:

    • two components that own the same UserManager instance which contains a transient DbContext.

    Currently, I solved this problem with another workaround:

    • I don't use UserManager directly instead, I create a new instance of it through IServiceProvider and then it works. I am still looking for a method to change the UserManager's lifetime instead of using IServiceProvider.

    tips: pay attention to services' lifetime

    This is what I learned. I don't know if it is all correct or not.

提交回复
热议问题