Usermanager.DbContext已在中间件中处置 [英] Usermanager.DbContext already disposed in Middleware

查看:67
本文介绍了Usermanager.DbContext已在中间件中处置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the below Middleware in an Asp.Net Core application where I require a UserManager to be injected in it. When I try to query for a user FindByIdAsync, I get the following exception:

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'.


我的中间件:


My Middleware:

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);
        }
    }
}

推荐答案

发生此问题是因为中间件本身是Singleton,因此其内部依赖项也需要为singleton,但是默认情况下,像UserManager这样的身份类在每个请求中都作用域,这就是它们在Startup.ConfigureServices中的注册方式,以及UserManager的依赖项(如dbContext)也都针对每个请求进行了作用域.

The problem happens because the middleware itself is a Singleton, so its internal dependencies also need to be singleton, but the identity classes like UserManager are scoped per request by default, that is how they are registered in Startup.ConfigureServices and also the dependencies for UserManager such as dbContext are also scoped per request.

通常,每个请求的作用域是这些对象想要的,特别是如果它们也用于其他地方(例如控制器)的话.

Generally scoped per request is what you want for those objects, especially if they are also used in other places such as controllers.

一种解决方案是,您的中间件不必依赖UserManager的构造函数,而只能在需要时从Invoke方法内部访问,语法是这样的:

One solution is instead of having your middleware take a constructor dependency on UserManager, you could access only when needed from inside the Invoke method, the syntax would be something like this:

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

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

that might not be exactly right syntax and you probably have to specify the actual user type

不利之处在于,这将是servicelocator模式,但它将解决问题,因为随后您将为每个请求获得一个UserManager,这应该被认为是作用域

the downside is that this would be the servicelocator pattern but it would solve the problem because then you would get a UserManager per request which is how it is supposed to be scoped

实际上,我认为您可以避免使用服务定位器模式,因为Invoke方法是可注入的,您可以像这样向方法签名添加其他依赖项:

actually I think you can avoid the service locator pattern because the Invoke method is injectable, you can add additional dependencies to the method signature like this:

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

但同样可能必须提供实际类型而不是TUser

but again probably have to provide the actual type rather than TUser

这篇关于Usermanager.DbContext已在中间件中处置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆