Closed GoogleCodeExporter closed 8 years ago
Original comment by travis.illig
on 27 Nov 2012 at 12:03
Note that, ideally, part of the solution here might include an easier way to
register the invoker and turn on/off the action method injection. Currently
it's sort of painful:
builder
.RegisterType<ExtensibleActionInvoker>()
.As<IActionInvoker>()
.WithParameter(new NamedParameter("injectActionMethodParameters", true));
Original comment by travis.illig
on 27 Nov 2012 at 12:05
I added an integration test to the Remember.Web site that tests this exact
thing.
You can enable/disable parameter injection from web.config. Access the test by
visiting the home page and following the links.
To reproduce the behavior, enable parameter injection in web.config and visit
the test page - you'll get the lifetime disposed exception.
Original comment by travis.illig
on 27 Nov 2012 at 1:30
It appears to have something to do with the async nature of the invoker. If you
set a break point and watch as things get resolved in the GetParameterValue
method, everything is fine. Remove your breakpoints and hit reload a couple of
times, you'll end up with the error.
Here's the exception and call stack:
[ObjectDisposedException: Instances cannot be resolved and nested lifetimes
cannot be created from this LifetimeScope as it has already been disposed.]
Autofac.Core.Lifetime.LifetimeScope.CheckNotDisposed() in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Lifetime\LifetimeScope.cs:327
Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\Core\Lifetime\LifetimeScope.cs:224
Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:736
Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:604
Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:552
Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac\ResolutionExtensions.cs:536
Autofac.Integration.Mvc.ExtensibleActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) in c:\dev\opensource\autofac\trunk\Core\Source\Autofac.Integration.Mvc\ExtensibleActionInvoker.cs:135
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +117
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>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.<BeginExecuteCore>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.<BeginProcessRequest>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
Original comment by travis.illig
on 27 Nov 2012 at 10:49
Looking at HttpContext.Current.Items, the lifetime scope there is actually NOT
disposed. Only the context on the action invoker.
Both are tagged with "AutofacWebRequest" so I know they're both request scopes,
but it looks like the invoker was created with a DIFFERENT request scope to
determine the action filters than was being used in the resolution of action
parameters.
Original comment by travis.illig
on 27 Nov 2012 at 10:58
Further investigation shows that the ExtensibleActionInvoker is actually being
cached.
Looking at ASP.NET MVC 4 source, it appears the System.Web.Mvc.Controller class
has started using DependencyResolver.CurrentCache internally for the way it
resolves services.
Further looking into the DependencyResolver class, it appears this boils down
to a new mechanism - the
System.Web.Mvc.DependencyResolver+CacheDependencyResolver nested type, which is
specifically there to enforce a single instance per resolved service. It
automatically wraps any AutofacDependencyResolver (or other resolver) you set
and caches specific instances in a type/object dictionary. For the life of the
dependency resolver.
This is resulting in the ExtensibleActionInvoker being created on the first
request (getting a valid component context from which to resolve dependencies)
but having subsequent requests fail because they're not using the proper
instance of the invoker - they're using a stale one. That actually affects
filters, too, since fresh dependencies won't be injected.
Original comment by travis.illig
on 27 Nov 2012 at 11:29
Updating the title to accommodate the new findings. It's larger than just
parameter injection.
Original comment by travis.illig
on 27 Nov 2012 at 11:31
Original comment by travis.illig
on 3 Dec 2012 at 3:48
This issue was closed by revision aac55af83e08.
Original comment by alex.meyergleaves
on 9 Dec 2012 at 7:25
Original issue reported on code.google.com by
travis.illig
on 27 Nov 2012 at 12:03