What steps will reproduce the problem? (complete failing example source code is attached) 1. Create a new empty MVC3 application, with a simple Home/Index view & HomeController with an Index method. -- starting app should work fine at this point 2. Setup & configure Autofac MVC3 Integration (including builder.RegisterFilterProvider()) -- starting app should work fine at this point 3. Install Glimpse.Mvc3 (version 0.86) via NuGet 4. Run app -- it will throw a NullReference exception
What is the expected output? What do you see instead?
-- Home/Index of App is expected to load with no problems, instead, the following exception is thrown:
System.NullReferenceException: Object reference not set to an instance of an object.
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
Autofac.Integration.Mvc.AutofacFilterAttributeFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +102
System.Web.Mvc.<>c__DisplayClass9.<GetFilters>b__6(IFilterProvider fp) +19
System.Linq.<SelectManyIterator>d__142.MoveNext() +238
System.Linq.Buffer
1..ctor(IEnumerable1 source) +217
System.Linq.<GetEnumerator>d__0.MoveNext() +96
System.Linq.Buffer
1..ctor(IEnumerable1 source) +217
System.Linq.<ReverseIterator>d__a0
1.MoveNext() +93
System.Web.Mvc.<RemoveDuplicates>d__b.MoveNext() +120
System.Linq.Buffer1..ctor(IEnumerable
1 source) +217
System.Linq.<ReverseIterator>d__a01.MoveNext() +93
System.Linq.WhereSelectEnumerableIterator
2.MoveNext() +87
System.Collections.Generic.List1..ctor(IEnumerable
1 collection) +327
System.Linq.Enumerable.ToList(IEnumerable1 source) +58
System.Web.Mvc.FilterInfo..ctor(IEnumerable
1 filters) +227
System.Web.Mvc.ControllerActionInvoker.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +46
Castle.Proxies.ControllerActionInvokerProxy.GetFilters_callback(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +8
Castle.Proxies.Invocations.ControllerActionInvoker_GetFilters.InvokeMethodOnTarget() +121
Castle.DynamicProxy.AbstractInvocation.Proceed() +96
Glimpse.Mvc3.Interceptor.GetFiltersInterceptor.Intercept(IInvocation invocation) +642
Castle.DynamicProxy.AbstractInvocation.Proceed() +461
Castle.Proxies.ControllerActionInvokerProxy.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +126
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +128
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass81.<BeginSynchronous>b__7(IAsyncResult _) +12
System.Web.Mvc.Async.WrappedAsyncResult
1.End() +62
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8920029
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
What version of Autofac are you using? On what version of .NET/Silverlight? Autofac.Integration.Mvc 2.5.2.830 .Net 4.0, System.Web.Mvc 3.0
Please provide any additional information below.
I tracked the exception down to the GetFilters() method of Autofac.Integration.Mvc.AutofacFilterAttributeFilterProvider -- it resolves the LifetimeScope like this: var lifetimeScope = AutofacDependencyResolver.Current.RequestLifetimeScope;
This throws the NullReferenceException, because AutofacDependencyResolver.Current tries to cast DependencyResolver.Current to AutofacDependencyResolver (DependencyResolver.Current as AutofacDependencyResolver). The reason it throws is that Glimpse replaces the implementation of DependencyResolver with its own implementation, which wraps whatever the configured implementation is. So AutofacDependencyResolver.Current returns null, as DependencyResolver.Current is now implemented by GlimpseDependencyResolver instead of AutofacDependencyResolver.
First, I wasn't sure whether to report this issue to Autofac or Glimpse, but once I found the source of the problem, it seems that Autofac's design is perhaps more responsible for the issue (or at least more easily resolved).
On one hand, the fact that Glimpse replaces the DependencyResolver impementation with its own non-public implementation is a bit troublesome. But on the other hand, the Autofac MVC integration facility depends on having AutofacDependencyResolver (including its RequestLifetimeScope property, which is not a member of IDependencyResolver interface) as the implementation type of DependencyResolver.Current, which suggests a violation of the spirit of the Liskov Substitution Principle.
My initial suggestion is to have the MVC integration register the AutofacDependencyResolver in the container itself (i.e., builder.RegisterType<AutofacDependencyResolver>().AsSelf()), then change AutofacDependencyResolver.Current to this (instead of casting DependencyResolver.Current to AutofacDependencyResolver):
public static AutofacDependencyResolver Current { get { return DependencyResolver.Current.GetService<AutofacDependencyResolver>(); } }
This way it would still work the same, but its usages would be less dependent on the implementation type of DependencyResolver.Current (i.e., Glimpse can still hijack the DependencyResolver without killing the Autofac MVC integration).
I'll probably also submit something to Glimpse, to suggest a different means of tracking service resolution than wrapping -- it's obviously a very invasive approach.
- AutofacMvcIssue.zip 634.46KB
Comment #1
Posted on Jan 23, 2012 by Happy MonkeyThanks very much for the report and repro - I think we can fix this fairly easily on the Autofac side of things by using DependencyResolver.Current in GetFilters() (calling through Glimpse is probably the right thing to do.) Time is a little tight right now but should be able to get this into the next release.
Comment #2
Posted on Feb 10, 2012 by Helpful WombatThe Glimpse team will also look into cleaning this up on our side if possible. Thank you for the excellent bug report.
Comment #3
Posted on Feb 10, 2012 by Helpful PandaI ran into this issue as well. I just wanted to call out a couple of workarounds. First, the simplest, is to blacklist the Execution Glimpse plugin since this is the one that wrappers the DependencyResolver. In your Glimpse config:
This allows you to continue using all the other Glimpse features, you just miss out on the Execution tab and the Controller/ActionFilter integration with the Timeline tab.
If you want to go crazy and get it working no matter what it takes, there are quite a few hoops to jump through.
1) You must create a custom build of Glimpse that doesn't do an ILMerge with Castle.Core (edit their default.ps1 merge task and remove Castle.Core from line 43), or simply do a Release solution build and reference the Glimpse.Mvc3.dll in your MVC application directly. See this bug for more detail on why this is required: https://github.com/Glimpse/Glimpse/issues/159 2) Install the Castle.Core NuGet package. I went with 2.5.2 since that's what both Glimpse and AutofacContrib.DynamicProxy use. 3) Add the attached GlimpseExecutionPlugin file to your solution which is simply the Execution plugin internal classes copied out of the Glimpse solution and made public (don't have to make them public). 4) When registering your controllers with Autofac, set the ActionInvoker OnActivating using the Glimpse extension method TrySetActionInvoker (included in one of the copied classes).
I already had a custom build of Glimpse in order to get some bug fixes sooner, so it wasn't much extra effort for me to get this working in my application. But it may be a high price if you don't already have a custom build.
Here's the code to set the action invoker:
builder.RegisterControllers(ThisAssembly).OnActivating(TrySetActionInvoker); ...
private void TrySetActionInvoker(IActivatingEventArgs e) { ((IController) e.Instance).TrySetActionInvoker(); }
- GlimpseExecutionPlugin.cs 24.82KB
Comment #4
Posted on May 31, 2012 by Grumpy MonkeyHi! Anyone know what the update is on this one? Cheers.
Comment #5
Posted on Aug 5, 2012 by Grumpy RhinoDid this ever get fixed? I've just hit exactly the same issue using Autofac.2.6.3.862 (this is the NuGet version). The fix outlined above (removing the Execution Plugin has worked) but I'm wondering if there's a planned release date for the fix.
Thanks
Comment #6
Posted on Aug 7, 2012 by Grumpy ElephantI tried the workaround (removing execution) and it did NOT work.
Comment #7
Posted on Sep 21, 2012 by Helpful Wombat(No comment was entered for this change.)
Comment #8
Posted on Dec 13, 2012 by Helpful WombatAdding some indirection around AutofacDependencyResolver.Current seems to fix the issue.
Comment #9
Posted on Dec 13, 2012 by Helpful Wombat(No comment was entered for this change.)
Comment #10
Posted on Dec 13, 2012 by Helpful WombatI think I have this fixed, but in order to do it there were a couple of design changes that had to happen in the MVC integration.
The AutofacDependencyResolver now registers itself on the fly with the request lifetime scope. AutofacDependencyResolver.Current can now be retrieved by using DependencyResolver.Current.GetService(), allowing systems like Glimpse to wrap/proxy but still allowing ADR.C to work right.
The ILifetimeScopeProvider interface changed to allow GetLifetimeScope to take a configuration action. This allows the AutofacDependencyResolver to build that registration of itself on the fly and configure the request scope.
The RequestLifetimeScopeProvider no longer holds a reference to its own configuration action. Since the actual request lifetime scope initiation is done through the AutofacDependencyResolver and the general use case is that ADR just passed the configuration action through to the lifetime scope provider, it didn't make sense that the lifetime scope provider be the "owner" for that. It also didn't allow other lifetime scope provider implementations to make use of that configuration action. Instead, the ADR is now the owner of the configuration action and it uses the ILifetimeScopeProvider.GetLifetimeScope method, passing in the configuration action as needed.
That interface change is a breaking one for people implementing custom request lifetime providers, but for the majority case this should be seamless.
Comment #11
Posted on Dec 13, 2012 by Helpful WombatThis issue was closed by revision e553f3cd3ecd.
Comment #12
Posted on Jul 22, 2013 by Massive RhinoI've just found this issue on the latest version of Autofac (3.1.1.0). As soon as I added Glimpse (Core=1.5.0.0, AspNet=1.3.1.0, Mvc4=1.3.2.0) to my project I got the following error message:
Server Error in '/' Application.
Object reference not set to an instance of an object.
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.NullReferenceException: Object reference not set to an instance of an object.
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:
[NullReferenceException: Object reference not set to an instance of an object.]
Autofac.Integration.Mvc.AutofacFilterAttributeFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +49
System.Web.Mvc.<>c__DisplayClass9.b__6(IFilterProvider fp) +19
System.Linq.d__142.MoveNext() +234
System.Linq.Buffer
1..ctor(IEnumerable1 source) +216
System.Linq.<GetEnumerator>d__0.MoveNext() +110
System.Linq.Buffer
1..ctor(IEnumerable1 source) +216
System.Linq.<ReverseIterator>d__a0
1.MoveNext() +92
System.Web.Mvc.d__b.MoveNext() +114
System.Linq.Buffer1..ctor(IEnumerable
1 source) +216
System.Linq.d__a01.MoveNext() +92
System.Linq.WhereSelectEnumerableIterator
2.MoveNext() +85
System.Collections.Generic.List1..ctor(IEnumerable
1 collection) +381
System.Linq.Enumerable.ToList(IEnumerable1 source) +58
System.Web.Mvc.FilterInfo..ctor(IEnumerable
1 filters) +289
System.Web.Mvc.ControllerActionInvoker.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +46
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +123
System.Web.Mvc.<>c__DisplayClass1d.b__19() +23
System.Web.Mvc.Async.<>c__DisplayClass1.b__0() +19
System.Web.Mvc.Async.<>c__DisplayClass81.<BeginSynchronous>b__7(IAsyncResult _) +10
System.Web.Mvc.Async.WrappedAsyncResult
1.End() +62
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +57
System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +23
System.Web.Mvc.Async.WrappedAsyncResult1.End() +62
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +47
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23
System.Web.Mvc.Async.WrappedAsyncResult
1.End() +62
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +47
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9630364
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929
Comment #13
Posted on Jul 22, 2013 by Helpful WombatI've added a new issue for the new failure - Issue #451 - since this issue is around MVC3 support (which was fixed) and the new issue, while related to Glimpse, has a different root cause/different failure going on.
Status: Fixed
Labels:
Type-Defect
Priority-Medium
Module-Integration-Mvc