OpenIddict 的依赖注入错误

Dependency Injection error with OpenIddict

我进行了大量搜索,但没有找到答案。我在使用 IOpenIddictScopeManagerIOpenIddictApplicationManager 时收到有关处理与依赖注入连接的连接的错误。

错误如下:

Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

堆栈跟踪:

System.ObjectDisposedException
  HResult=0x80131622
  Message=Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'IdentDbContext'.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__54.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at OpenIddict.EntityFrameworkCore.OpenIddictEntityFrameworkCoreScopeStore`3.<CreateAsync>d__14.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at OpenIddict.Core.OpenIddictScopeManager`1.<CreateAsync>d__15.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()
   at OpenIddict.Core.OpenIddictScopeManager`1.<CreateAsync>d__16.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at OpenIddict.Core.OpenIddictScopeManager`1.<OpenIddict-Abstractions-IOpenIddictScopeManager-CreateAsync>d__47.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at IdentityApi.WebApi.Controllers.OpenIDManagementController.<CreateScopeAsync>d__4.MoveNext() in E:\Source\Workspaces\Identity\IdentityApi\IdentityApi.WebApi\Controllers\OpenIDManagementController.cs:line 45

  This exception was originally thrown at this call stack:
    [External Code]
    IdentityApi.WebApi.Controllers.OpenIDManagementController.CreateScopeAsync(IdentityApi.WebApi.Models.AdministrationModels.ScopePostInputModel, System.Threading.CancellationToken) in OpenIDManagementController.cs

在我的控制器中,我有以下引发错误的构造函数和方法:

        private readonly IOpenIddictApplicationManager _applicationManager;
        private readonly IOpenIddictScopeManager _scopeManager;

        public OpenIDManagementController(IOpenIddictApplicationManager applicationManager, IOpenIddictScopeManager scopeManager)
        {
            _applicationManager = applicationManager;
            _scopeManager = scopeManager;
        }

        // Create a scope
        [HttpPost("CreateScopeAsync", Name = nameof(CreateScopeAsync))]        
        public async void CreateScopeAsync(ScopePostInputModel scopeInput, CancellationToken cancellationToken)
        {            
            if (await _scopeManager.FindByNameAsync(scopeInput.Name, cancellationToken) is null)
            {
                var scopeToAdd = new OpenIddictScopeDescriptor
                {
                    Name = scopeInput.Name,
                    Description = scopeInput.Description,
                    DisplayName = scopeInput.DisplayName
                };

                var createResult = await _scopeManager.CreateAsync(scopeToAdd, cancellationToken);  // This errors out for dependancy injection
            }
            else
            {
                // error here
            }
        }

这是我的 Statup.cs:

的配置部分
public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddRazorPages();

            services.AddDbContext<IdentDbContext>(options =>
            {
                options.UseSqlServer(
                    Configuration.GetConnectionString("IdentityDB"));

                options.UseOpenIddict();
            });
            services.AddIdentity<ApplicationUsers, ApplicationRoles>(config =>
            {
                config.SignIn.RequireConfirmedEmail = true;
                config.SignIn.RequireConfirmedAccount = true;
                config.User.RequireUniqueEmail = true;
                config.Lockout.MaxFailedAccessAttempts = 3;
            }).AddEntityFrameworkStores<IdentDbContext>()
            .AddUserStore<ApplicationUserStore>()
            .AddRoleStore<ApplicationRoleStore>()
            .AddRoleManager<ApplicationRoleManager>()
            .AddUserManager<ApplicationUserManager>()
            .AddErrorDescriber<ApplicationIdentityErrorDescriber>()
            .AddDefaultTokenProviders()
            .AddDefaultUI();

            services.AddDataLibrary();
            
            services.Configure<IdentityOptions>(options =>
            {
                options.ClaimsIdentity.UserNameClaimType = Claims.Name;
                options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
                options.ClaimsIdentity.RoleClaimType = Claims.Role;
            });

            services.AddOpenIddict()
                .AddCore(options =>
                {
                    options.UseEntityFrameworkCore()
                    .UseDbContext<IdentDbContext>();
                })
                .AddServer(options =>
                {
                    options.AllowClientCredentialsFlow()
                    .AllowAuthorizationCodeFlow()
                    .RequireProofKeyForCodeExchange();
                    options.SetAuthorizationEndpointUris("/api/Authorization/Authorize")
                    .SetTokenEndpointUris("/Token");
                    
                    options.RegisterScopes(Scopes.OpenId, Scopes.Email, Scopes.Profile, Scopes.Roles, "DatabaseName");

                    options.SetIssuer(new Uri(Configuration["Jwt:Issuer"]));

                    options.AcceptAnonymousClients();

                    options.DisableAccessTokenEncryption();

                    
                    options.AddDevelopmentEncryptionCertificate()
                          .AddDevelopmentSigningCertificate();

                    options.UseAspNetCore()
                           .EnableAuthorizationEndpointPassthrough()
                           .EnableTokenEndpointPassthrough();
                })
                .AddValidation(options =>
                {
                    options.UseLocalServer();

                    options.UseAspNetCore();
                });
            services.AddHostedService<TestData>();  // For development only.
        }

我不确定我错过了什么,但无论我做了什么更改,我仍然收到相同的错误。关于如何更正此错误的任何想法?

async void 似乎是这里的问题。不清楚您为什么使用那个 (async void) 而不是 return 操作结果。

框架不会等待请求得到正确处理,因此当您的代码到达注入依赖项的第二次调用时,操作已经超出范围,因为 async void 方法被调用为火忘了。

控制器操作应该return请求的相关操作结果

例如

[HttpPost("CreateScopeAsync", Name = nameof(CreateScopeAsync))]        
public async Task<IActionResult> CreateScopeAsync(ScopePostInputModel scopeInput, CancellationToken cancellationToken) { 
    if (await _scopeManager.FindByNameAsync(scopeInput.Name, cancellationToken) is null) {
        var scopeToAdd = new OpenIddictScopeDescriptor {
            Name = scopeInput.Name,
            Description = scopeInput.Description,
            DisplayName = scopeInput.DisplayName
        };

        var createResult = await _scopeManager.CreateAsync(scopeToAdd, cancellationToken);

        return Ok(); //Or some other appropriate response;
    } else {
        // error here

        return BadRequest(); //Or some other appropriate response;
    }
}