I have done quite a bit of searching but have come up empty for an answer. I am getting a error when using the IOpenIddictScopeManager
and IOpenIddictApplicationManager
about the connection disposing a connection with Dependency Injection.
The following is the error:
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.
Stack trace:
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
In my controller I have the following constructor and method that is throwing the error:
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
}
}
Here is the configuration section of my 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.
}
I am not sure what I missed, but no matter what changes I have made I still receive the same error. Any thoughts on how to correct this error?
CodePudding user response:
async void
seems to be the problem here. It is not clear why you use that (async void
) instead of returning an action result.
The framework does not wait for the request to be properly handled so by the time your code reaches the second call of your injected dependency, the action has gone out of scope since async void
methods are invoked as fire and forget.
The controller action should return a relevant action result for the request
For example
[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;
}
}