1

我在这里问了一个问题,我读了这个关于多线程的问题/答案,我知道这些解决方案。但是今天我遇到了一个新问题。当我们使用命令(或者我们可以访问原始代码来管理和修改它的地方)时,上面答案中建议的 async-decorator 工作。但是当 MVC 自己创建一个新线程时,我们能做什么呢?例如,我有一个自定义角色提供者(与 一起使用DbContext),我收到此错误:

操作无法完成,因为 DbContext 已被释放。

这是堆栈跟踪:

[InvalidOperationException:操作无法完成,因为 DbContext 已被释放。]

System.Data.Entity.Internal.InternalContext.CheckContextNotDisposed() +67

System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +34

System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(表达式表达式)+22

System.Linq.Queryable.Any(IQueryable 1 source, Expression1 谓词) +265

MyProject.MyRoleProvider.IsUserInRole(String username, String roleName) in ...

System.Web.Security.Roles.IsUserInRole(字符串用户名,字符串角色名称)+263

MyProject.MyPrincipal.IsInRole(字符串角色)在...

System.Linq.Enumerable.Any(IEnumerable 1 source, Func2 谓词)+146

System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +200

System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +159

System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext,IList`1过滤器,ActionDescriptor actionDescriptor)+96

System.Web.Mvc.Async。<>c__DisplayClass25.b__1e (AsyncCallback asyncCallback, Object asyncState) +446

System.Web.Mvc.Async。WrappedAsyncResult`1.Begin(AsyncCallback 回调,对象状态,Int32 超时)+130

System.Web.Mvc.Async。AsyncControllerActionInvoker.BeginInvokeAction (ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +302

系统.Web.Mvc。<>c__DisplayClass1d.b__17 (AsyncCallback asyncCallback, Object asyncState) +30

System.Web.Mvc.Async。WrappedAsyncResult`1.Begin(AsyncCallback 回调,对象状态,Int32 超时)+130

系统.Web.Mvc。Controller.BeginExecuteCore(AsyncCallback 回调,对象状态)+382

System.Web.Mvc.Async。WrappedAsyncResult`1.Begin(AsyncCallback 回调,对象状态,Int32 超时)+130

系统.Web.Mvc。Controller.BeginExecute(RequestContext requestContext,AsyncCallback 回调,对象状态)+317

System.Web.Mvc.Controller.System.Web.Mvc.Async。IAsyncController.BeginExecute(RequestContext requestContext,AsyncCallback 回调,对象状态)+15

系统.Web.Mvc。<>c__DisplayClass8.b__2 (AsyncCallback asyncCallback, Object asyncState) +71

System.Web.Mvc.Async。WrappedAsyncResult`1.Begin(AsyncCallback 回调,对象状态,Int32 超时)+130

系统.Web.Mvc。MvcHandler.BeginProcessRequest(HttpContextBase httpContext,AsyncCallback 回调,对象状态)+249

系统.Web.Mvc。MvcHandler.BeginProcessRequest (HttpContext httpContext, AsyncCallback 回调, 对象状态) +50

System.Web.Mvc.MvcHandler.System.Web。IHttpAsyncHandler.BeginProcessRequest(HttpContext上下文,AsyncCallback cb,对象extraData)+16

System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301

System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

如您所见,MyProject.MyRoleProvider.IsUserInRole异步调用,我没有启动它,它由 MVC 本身调用异步。所以我对此没有任何控制权。我的提供者 ctor 是:

公共 MyRoleProvider() { _context = MyIoCWrapper.GetService(); }

好像MyRoleProvider实例化HttpContext的时候不为null,IsInRole调用的时候好像HttpContext为null。如果我想开始一个新的生命范围,它只会被使用一次,如果 MVC 开始一个新线程,我也会有一个新的DbContext。我很困惑找不到解决方案。你有吗?如何为所有后台线程开始一个新的生命范围 - 我启动它们还是 MVC 启动它们?

4

1 回答 1

1

您的问题实际上与异步运行控制器无关,而是控制对象生命周期的一般问题。

您可能MyRoleProvider在应用程序的 web.config 中注册了您的,或者可能通过代码注册了它。无论哪种方式,MyRoleProvider都是一个单例,在应用程序的生命周期中只有该类的一个实例。

然而,这MyRoleProvider取决于DbContext生活方式较短(在您的情况下为每个 Web 请求或混合),这意味着您不能DbContext在您的生命周期内缓存它MyRoleProver,因为这会将其生活方式“提升”DbContext为单身好。该_context = MyIoCWrapper.GetService();行似乎表明您正在缓存该DbContext.

在这种情况下,您必须DbContext在每个方法调用上解析实例。因此,您IsUserInRole将看起来像这样:

public bool IsUserInRole(String username, String roleName)
{
    var context = MyIoCWrapper.GetService();
    return context.Roles
        .Any(r => r.Name == roleName && r.User.Name == username);
}
于 2012-11-04T18:28:51.830 回答