简体   繁体   中英

Blazor Server - Circuit Error when using asynchronous UserManager methods

im currently working on a blazor server web app where is use identitycore to manage the users. I got a razor component where the user have to input the data for the user account. this page should use a service that get injected through dependency injection. but when i try to create the user, i got following exceptions:

[13:56:45 ERR] An exception occurred while iterating over the results of a query for context type 'ProjectName.Data.Context.DataContext'.
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
[13:56:45 WRN] Unhandled exception rendering component: Cannot access a disposed object.
System.ObjectDisposedException: Cannot access a disposed object.
   at Microsoft.AspNetCore.Components.RenderTree.ArrayBuilder`1.GrowBuffer(Int32 desiredCapacity)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
[13:56:45 WRN] Unhandled exception rendering component: Cannot access a disposed object.
Object name: 'UserManager`1'.
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'UserManager`1'.
   at Microsoft.AspNetCore.Identity.UserManager`1.ThrowIfDisposed()
   at Microsoft.AspNetCore.Identity.UserManager`1.get_SupportsUserLockout()
   at Microsoft.AspNetCore.Identity.UserManager`1.CreateAsync(TUser user)
   at ProjectName.Service.Services.UserService.CreateUser(AppUser user) in C:\Users\erikm\source\repos\ProjectName\ProjectName.Service\Services\UserService.cs:line 66
   at ProjectName.Web.Pages.Employee.CompanyEmployees.CreateHandler(GridCommandEventArgs arg) in C:\Users\erikm\source\repos\ProjectName\ProjectName.Web\Pages\Employee\CompanyEmployees.razor:line 67
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Telerik.Blazor.Components.Common.TableGridBase`2.InvokeEventAsync(EventCallback`1 event, TableCommandEventArgs args)
   at Telerik.Blazor.Components.Common.TableGridBase`2.InvokeCreateEventAsync(TableCommandEventArgs args)
   at Telerik.Blazor.Components.Common.TableGridBase`2.InvokeSaveEventAsync(TableCommandEventArgs args)
   at Telerik.Blazor.Components.Common.TableGridBase`2.ExecuteSaveCommandAsync(TableCommandEventArgs args)
   at Telerik.Blazor.Components.Common.TableGridBase`2.ExecuteValidatedCommand(TableCommandEventArgs args)
   at Telerik.Blazor.Components.TelerikGrid`1.ExecuteValidatedCommand(TableCommandEventArgs args)
   at Telerik.Blazor.Components.Common.TableGridBase`2.ExecuteCommand(Object commandArgs)
   at Telerik.Blazor.Components.Common.Grid.GridEditForm`1.FireCommand(String name)
   at Telerik.Blazor.Components.Common.Grid.GridEditForm`1.Update()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Telerik.Blazor.Components.TelerikForm.OnSubmitHandler()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

my code looks like that: Razor Page

    [Inject]
    private IUserService _userService { get; set; }

    private async Task CreateHandler(GridCommandEventArgs arg)
    {
        if (arg.Item is AppUser user)
        {
            user.CompanyId = Company.Id;
            user.UserName = user.Email;
            await _userService.CreateUser(user);
        }
    }

and the service layer:

    private readonly UserManager<AppUser> _userManager;
    private readonly IDbContextFactory<DataContext> _dataContextFactory;
    public UserService(UserManager<AppUser> userManager, IDbContextFactory<DataContext> dataContextFactory)
    {
        _userManager = userManager;
        _dataContextFactory = dataContextFactory;
    }
    public async Task<AppUser?> CreateUser(AppUser user)
    {
        IdentityResult result = await _userManager.CreateAsync(user);
        return result.Succeeded ? user : null;
    }

and also my Program.cs

            var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
            builder.Services.AddDbContextFactory<DataContext>(options =>
            {
                options.UseSqlServer(connectionString, sqlServerOptionsAction: sqlOptions =>
                {
                    sqlOptions.EnableRetryOnFailure();
                });
            });

            builder.Services.AddIdentity<AppUser, AppRole>(options =>
                {
                    options.SignIn.RequireConfirmedAccount = false;
                })
                .AddEntityFrameworkStores<DataContext>()
                .AddDefaultTokenProviders();

            builder.Services.AddTransient<IUserService, UserService>();

im expecting that i can create user asynchronously and in the service layer. Im using.net 7.0 with all relevant packages updated to the latest version (7.0.0 atm)

UserManager is based on EFCore,and you registed the dbcontext as below:

builder.Services.AddDbContextFactory<DataContext>(options =>
            {
                options.UseSqlServer(connectionString, sqlServerOptionsAction: sqlOptions =>
                {
                    sqlOptions.EnableRetryOnFailure();
                });
            });

if you didn't set the lifetime when you regist the context,it would be scoped by default,you could try regist it as transident as below:

services.AddDbContext<SomeContext>(options =>options.UseSqlServer(
                        Configuration.GetConnectionString("SomeContextConnection")),ServiceLifetime.Transient);

For more details,you could check this document

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM