gpt4 book ai didi

asp.net - Usermanager.DbContext 已在中间件中处置

转载 作者:行者123 更新时间:2023-12-02 09:32:48 24 4
gpt4 key购买 nike

我在 Asp.Net Core 应用程序中有以下中间件,我需要在其中注入(inject) UserManager 。当我尝试查询用户 FindByIdAsync 时,出现以下异常:

ObjectDisposedException: 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 is 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: 'ApplicationDbContext'.
<小时/>

我的中间件:

namespace MyApp
{
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;

public class MyMiddleware<TUser, TRole>
where TUser : class where TRole : class
{
private readonly RequestDelegate _next;
private readonly UserManager<TUser> _userManager;
private readonly RoleManager<TRole> _roleManager;
private readonly IOptions<IdentityOptions> _optionsAccessor;

public UserIdentityMiddleware(RequestDelegate next, UserManager<TUser> userManager,
RoleManager<TRole> roleManager, IOptions<IdentityOptions> optionsAccessor)
{
_next = next;
_userManager = userManager;
_roleManager = roleManager;
_optionsAccessor = optionsAccessor;
}

public async Task Invoke(HttpContext context)
{
var user = await _userManager.FindByIdAsync("1");

var claimsPrincipal = await new UserClaimsPrincipalFactory<TUser, TRole>(
_userManager, _roleManager, _optionsAccessor).CreateAsync(user);

context.User.AddIdentities(claimsPrincipal.Identities);

await _next(context);
}
}
}

最佳答案

出现这个问题是因为中间件本身是单例的,所以它的内部依赖也需要是单例的,但是像 UserManager 这样的身份类默认是按请求限定范围的,这就是它们在 Startup.ConfigureServices 中注册的方式以及UserManager 的依赖项(例如 dbContext)也按请求限定范围。

通常,每个请求的作用域是您想要这些对象的范围,特别是如果它们也用于其他地方(例如 Controller )。

一种解决方案是不要让中间件采用对 UserManager 的构造函数依赖,您可以仅在需要时从 Invoke 方法内部进行访问,语法如下所示:

var userManager = context.RequestServices.GetService(UserManager<TUser>);

这可能不是完全正确的语法,您可能必须指定实际的用户类型

缺点是这将是服务定位器模式,但它可以解决问题,因为这样你会为每个请求获得一个 UserManager,这就是它应该如何确定范围的

实际上我认为您可以避免服务定位器模式,因为 Invoke 方法是可注入(inject)的,您可以向方法签名添加额外的依赖项,如下所示:

public async Task Invoke(HttpContext context, UserManager<TUser> userManager)
{
...
}

但可能再次需要提供实际类型而不是 TUser

关于asp.net - Usermanager.DbContext 已在中间件中处置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39369054/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com