我asked before a question在这里,我读了关于多线程的这个问题/答案,我知道这些解决方案。但今天我遇到了一个新问题。当我们使用命令(或者我们可以访问原始代码来管理和修改它)时,上述答案中建议的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(Expression expression)+22
System.Linq.Queryable.Any(IQueryable
1 source, Expression
1个谓词)+265MyProject.MyRoleProvider.IsUserInRole(String username,String roleName)in ...
System.Web.Security.Roles.IsUserInRole(String username,String roleName)+263
MyProject.MyPrincipal.IsInRole(String role)in ...
System.Linq.Enumerable.Any(IEnumerable
1 source, Func
2谓词)+146System.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
System.Web.Mvc。 <> c__DisplayClass1d.b__17 (AsyncCallback asyncCallback,Object asyncState)+30
System.Web.Mvc.Async。 WrappedAsyncResult`1.Begin (AsyncCallback回调,对象状态,Int32超时)+130
System.Web.Mvc。 Controller.BeginExecuteCore (AsyncCallback回调,对象状态)+382
System.Web.Mvc.Async。 WrappedAsyncResult`1.Begin (AsyncCallback回调,对象状态,Int32超时)+130
System.Web.Mvc。 Controller.BeginExecute (RequestContext requestContext,AsyncCallback callback,Object state)+317
System.Web.Mvc.Controller.System.Web.Mvc.Async。 IAsyncController.BeginExecute (RequestContext requestContext,AsyncCallback callback,Object state)+15
System.Web.Mvc。 <> c__DisplayClass8.b__2 (AsyncCallback asyncCallback,Object asyncState)+71
System.Web.Mvc.Async。 WrappedAsyncResult`1.Begin (AsyncCallback回调,对象状态,Int32超时)+130
System.Web.Mvc。 MvcHandler.BeginProcessRequest (HttpContextBase httpContext,AsyncCallback回调,对象状态)+249
System.Web.Mvc。 MvcHandler.BeginProcessRequest (HttpContext httpContext,AsyncCallback回调,对象状态)+50
System.Web.Mvc.MvcHandler.System.Web。 IHttpAsyncHandler.BeginProcessRequest (HttpContext context,AsyncCallback cb,Object extraData)+16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean& completedSynchronously)+155
正如您所看到的,MyProject.MyRoleProvider.IsUserInRole
是异步调用的,我没有启动它,而是由MVC本身调用异步。所以我对它没有任何控制权。我的提供者是:
public MyRoleProvider(){ _context = MyIoCWrapper.GetService(); }
当MyRoleProvider
实例化时,HttpContext
不为空,并且当IsInRole
被调用时,HttpContext
为空。
如果我想开始一个新的生命范围,它将只使用一次,如果MVC启动一个新的线程,我也将有一个新的DbContext
。我很困惑找到一个解决方案。你有没有?
如何为所有后台线程启动新的生命范围 - 我启动它们或MVC启动它们?
答案 0 :(得分:1)
您的问题实际上与异步运行控制器无关,但是控制对象生命周期的一般问题。
您可能在应用程序的web.config中注册了MyRoleProvider
,或者可能通过代码注册了它。无论如何,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);
}
看起来像这样:
{{1}}