Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net Usermanager.DbContext已在中间件中释放_Asp.net_Entity Framework_Asp.net Core - Fatal编程技术网

Asp.net Usermanager.DbContext已在中间件中释放

Asp.net Usermanager.DbContext已在中间件中释放,asp.net,entity-framework,asp.net-core,Asp.net,Entity Framework,Asp.net Core,我在Asp.Net核心应用程序中有以下中间件,我需要在其中注入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

我在Asp.Net核心应用程序中有以下中间件,我需要在其中注入
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);
        }
    }
}
名称空间MyApp
{
使用System.Threading.Tasks;
使用Microsoft.AspNetCore.Builder;
使用Microsoft.AspNetCore.Http;
使用Microsoft.AspNetCore.Identity;
使用Microsoft.Extensions.Options;
公共类中间件
where TUser:class where TRole:class
{
private readonly RequestDelegate\u next;
私有只读用户管理器_UserManager;
专用只读角色管理器(RoleManager);
专用只读IOPS _选项访问器;
public UserIdentityMiddleware(RequestDelegate-next,UserManager-UserManager,
角色管理器角色管理器,IOPS选项访问器)
{
_下一个=下一个;
_userManager=userManager;
_roleManager=roleManager;
_optionAccessor=optionAccessor;
}
公共异步任务调用(HttpContext上下文)
{
var user=await_userManager.FindByIdAsync(“1”);
var claimsPrincipal=等待新用户claimsPrincipal工厂(
_用户管理器,_角色管理器,_选项访问器).CreateAsync(用户);
context.User.AddIdentities(claimsPrincipal.Identities);
等待下一步(上下文);
}
}
}

之所以会出现问题,是因为中间件本身是单例的,所以它的内部依赖关系也需要是单例的,但是像UserManager这样的标识类在默认情况下是按请求确定范围的,这就是在Startup.ConfigureServices中注册它们的方式,并且UserManager的依赖项(如dbContext)也会根据请求确定作用域

通常情况下,每个请求的作用域是这些对象所需的,尤其是在控制器等其他位置也使用这些对象时

一种解决方案是,与让中间件在UserManager上建立构造函数依赖关系不同,您只能在需要时从Invoke方法内部进行访问,语法如下:

var userManager = context.RequestServices.GetService(UserManager<TUser>);
public async Task Invoke(HttpContext context, UserManager<TUser> userManager)
{
    ...
}
var userManager=context.RequestServices.GetService(userManager);
这可能不是完全正确的语法,您可能必须指定实际的用户类型

缺点是这将是servicelocator模式,但它将解决问题,因为这样,每个请求都会有一个UserManager,这就是它应该如何确定作用域的方式

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

var userManager = context.RequestServices.GetService(UserManager<TUser>);
public async Task Invoke(HttpContext context, UserManager<TUser> userManager)
{
    ...
}
公共异步任务调用(HttpContext上下文,UserManager UserManager)
{
...
}

不过,我还是要提供实际的类型,而不是TUser

非常感谢您的回答。一件奇怪的事情是,我尝试将
IServiceProvider
注入中间件,以完全按照您的建议执行操作,但问题是相同的,但当我从
上下文请求
UserManager
时,RequestServices
与您的回答类似,它工作了!!!你知道为什么吗?我刚刚更新了我的答案,以说明如何避免服务定位器模式。IServiceProvider有多个实现,因此通过在中间件中采用构造函数依赖关系,我认为它可以获得不适用于范围依赖关系的应用程序服务。有关更多信息,请参见此处: