autofac / Autofac.Mvc

ASP.NET MVC integration for Autofac
MIT License
49 stars 23 forks source link

Glimpse interferes with ExtensibleActionInvoker on MVC5 #7

Closed tillig closed 8 years ago

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on July 23, 2013 02:14:11

When Glimpse is disabled, the ExtensibleActionInvoker is able to inject parameters into controller actions without issue. When it is enabled, injection fails.

This can be reproduced in the "Remember.Web" sample application in the Autofac solution:

An exception will appear; details below.

It appears that Glimpse is attempting to wrap/replace the action invoker as part of its debugging integration. Note the stack trace in the application never runs through Autofac the way it should if ExtensibleActionInvoker is in place.

Related: a similar issue has been reported (appended to Issue #351 ) where the AutofacFilterAttributeFilterProvider is also running into trouble, most likely for similar reasons.

Exception re: ExtensibleActionInvoker below:

Server Error in '/' Application.

Cannot create an instance of an interface. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.MissingMethodException: Cannot create an instance of an interface.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[MissingMethodException: Cannot create an instance of an interface.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +113 System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232 System.Activator.CreateInstance(Type type, Boolean nonPublic) +83 System.Activator.CreateInstance(Type type) +6 System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +183 System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +564 System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +416 Castle.Proxies.DefaultModelBinderProxy.BindModel_callback(ControllerContext controllerContext, ModelBindingContext bindingContext) +44 Castle.Proxies.Invocations.DefaultModelBinder_BindModel.InvokeMethodOnTarget() +191 Castle.DynamicProxy.AbstractInvocation.Proceed() +117 Glimpse.Core.Extensibility.CastleInvocationToAlternateMethodContextAdapter.Proceed() +48 Glimpse.Core.Extensibility.ExecutionTimer.Time(Action action) +195 Glimpse.Core.Extensions.AlternateMethodContextExtensions.TryProceedWithTimer(IAlternateMethodContext context, TimerResult& timerResult) +198 Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context) +45 Glimpse.Core.Extensibility.AlternateTypeToCastleInterceptorAdapter.Intercept(IInvocation invocation) +183 Castle.DynamicProxy.AbstractInvocation.Proceed() +483 Castle.Proxies.DefaultModelBinderProxy.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +219 System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +317 System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +117 System.Web.Mvc.Async.<>cDisplayClass25.b1e(AsyncCallback asyncCallback, Object asyncState) +446 System.Web.Mvc.Async.WrappedAsyncResult1.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.WrappedAsyncResult1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130 System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +382 System.Web.Mvc.Async.WrappedAsyncResult1.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.WrappedAsyncResult1.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


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18045

Original issue: http://code.google.com/p/autofac/issues/detail?id=451

Copied from original issue: autofac/Autofac#451

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on August 08, 2013 07:52:29

Status: Started
Owner: travis.illig

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on August 08, 2013 08:26:23

The trouble appears to be with the way Glimpse replaces the action invoker. The default mechanism to create the action invoker runs through the DependencyResolver, but with Glimpse in place it seems to be a proxy around the default version of the action invoker.

When Glimpse is enabled, the IActionInvoker in place at the point of Controller.BeginExecuteCore is a dynamic proxy Castle.Proxies.AsyncControllerActionInvokerProxy.

The base class for that proxy is System.Web.Mvc.Async.AsyncControllerActionInvoker and the __target on the proxy is correctly Autofac.Integration.Mvc.ExtensibleActionInvoker. There seem to also be two mixins:

What appears to be happening is the target of the dynamic proxy is getting bypassed in favor of calling the base AsyncControllerActionInvoker.GetParameterValue instead of the overridden one in the Autofac invoker.

Guessing this is something to do with the way the dynamic proxies in Glimpse get set up. I think I'm going to have to file something with Glimpse on this one; it doesn't appear to be something we can fix from our end.

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on August 08, 2013 08:30:54

It appears this has been an issue for a few months with Glimpse. Others have reported it - issue 328 for them: https://github.com/Glimpse/Glimpse/issues/328

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on August 08, 2013 13:59:05

Unfortunately, it looks like it may be a while until Glimpse can get a fix for this. See here for details: https://github.com/Glimpse/Glimpse/issues/328#issuecomment-22346241 The workaround right now is to turn off the Glimpse ActionInvoker functionality, which is outlined in that comment on the GitHub issue.

In the meantime, I'll keep this open and keep watching for a resolution, but again, there's nothing we can do from this end.

tillig commented 9 years ago

From @alexmg on January 22, 2014 14:27

From travis.illig on November 14, 2013 09:49:35

This continues to be a problem with Glimpse 1.8.0 and Glimpse.Mvc5 1.5.1.

Summary: Glimpse interferes with ExtensibleActionInvoker on MVC5 (was: Glimpse interferes with ExtensibleActionInvoker on MVC4)

tillig commented 8 years ago

It appears the Glimpse issue has rolled into a larger backlog-related issue: https://github.com/Glimpse/Glimpse/issues/226

tillig commented 8 years ago

This may be one we just document and call good. We're going on three years on this one and there's nothing that we in Autofac-land can do about it.

I'll leave this open as a reminder to add docs.

tillig commented 8 years ago

Docs added.

mwpowellhtx commented 7 years ago

@tillig I too have been bitten by this very strange error. Not for Glimpse, per se, but in general.

Under debug mode, I see instances to my ctor-injected interfaces just fine. However, the MME occurs nonetheless. Utterly frustrating. What's exactly is the workaround, or we live with broken services? That seems like an unacceptable path forward, if you ask me. In the meantime I'll have a closer look at the documentation, however, the links in the log here are pointing to the commit, not the docs. Hopefully I've got the link correct here.

Couple of observations, from the MVC documentation:

builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.InjectActionInvoker();

You don't InjectActionInvoker on the builder. You do so after type registration, presumably RegisterControllers(...).

Additionally, the comment "you can enable action method injection if you desire" is silly. I'm not sure what the interference is, but clearly something is interfering with a model binding expectation, which for me, as with so many others, yields the exceptions:

[MissingMethodException: Cannot create an instance of an interface.]
[MissingMethodException: Cannot create an instance of an interface. Object type 'IMyServiceInterface'.]

Apart from this, otherwise as revealed in debugger, the instances are resolved and presented to my Controller ctor just fine.

Conclusions, the key, I think is this: InjectActionInvoker. Either of the action invokers is probably fine. I am registering the ExtensibleActionInvoker, for example. After that, no MME.

Thank you!

tillig commented 7 years ago

http://autofac.readthedocs.io/en/latest/integration/mvc.html#glimpse-integration