I asked before a question here, and I read this question/answers about multi-threading and I know those solutions. But today I get a new problem. When we are using commands (or where we can access the original code to manage and modify it) the async-decorator that suggested in above answers works. But when MVC creates a new thread itself, what can we do? e.g. I have a custom role provider (works with DbContext), and I get this error:
The operation cannot be completed because the DbContext has been disposed.
And here is stack trace:
[InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.]
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, Expression1 predicate) +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, Func2 predicate) +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 filters, ActionDescriptor actionDescriptor) +96
System.Web.Mvc.Async.<>c__DisplayClass25.b__1e(AsyncCallback asyncCallback, Object asyncState) +446
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +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 callback, Object state, Int32 timeout) +130
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +382
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +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 callback, Object state, Int32 timeout) +130
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +249
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +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
As you can see, MyProject.MyRoleProvider.IsUserInRole invoked asynchronously, which I did not start it and its invoking async by MVC itself. So I have not any control on it. My provider ctor is:
public MyRoleProvider() {
_context = MyIoCWrapper.GetService();
}
It seems when MyRoleProvider instantiated, HttpContext is not null, and when IsInRole called, HttpContext is null.
If I want to start a new life scope, it will be used just once, and if MVC starts a new thread, I will have a new DbContext too. I confused to finding a solution. Have you any one?
How can I start a new life scope for all background threads -I start them or MVC starts them?
Your problem is in fact unrelated to running controllers asynchronously, but is a general problem of controlling the lifetime of objects.
You probably registered your
MyRoleProviderin the web.config of the application, or perhaps registered it through code. Eitherway, theMyRoleProvideris a singleton, there is just a single instance of that class during the lifetime of the application.The
MyRoleProviderhowever depends on aDbContextwhich has a lifestyle that is shorter (Per Web Request or hybrid in your case), which means you can’t cache thatDbContextduring the lifetime of yourMyRoleProver, since that would ‘promote’ the lifestyle of thatDbContextto singleton as well. The_context = MyIoCWrapper.GetService();line seems to indicate that you are caching thatDbContext.In this case you will have to resolve the
DbContextinstance on each method call. So instead, yourIsUserInRolewould look something like this: