zcz527 / autofac

Automatically exported from code.google.com/p/autofac
Other
0 stars 0 forks source link

Autofac.Integration.Mvc fails when Glimpse.Mvc3 is installed #351

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
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__14`2.MoveNext() +238
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
   System.Linq.<GetEnumerator>d__0.MoveNext() +96
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
   System.Linq.<ReverseIterator>d__a0`1.MoveNext() +93
   System.Web.Mvc.<RemoveDuplicates>d__b.MoveNext() +120
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
   System.Linq.<ReverseIterator>d__a0`1.MoveNext() +93
   System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +87
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +327
   System.Linq.Enumerable.ToList(IEnumerable`1 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__DisplayClass8`1.<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.

Original issue reported on code.google.com by jrnai...@gmail.com on 29 Dec 2011 at 8:40

Attachments:

GoogleCodeExporter commented 8 years ago
Thanks 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.

Original comment by nicholas...@gmail.com on 23 Jan 2012 at 5:29

GoogleCodeExporter commented 8 years ago
The Glimpse team will also look into cleaning this up on our side if possible. 
Thank you for the excellent bug report.

Original comment by nikm...@gmail.com on 10 Feb 2012 at 9:33

GoogleCodeExporter commented 8 years ago
I 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:

  <glimpse enabled="true">
    <pluginBlacklist>
      <add plugin="Glimpse.Mvc3.Plugin.Execution" />
    </pluginBlacklist>
  </glimpse>

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<object> e)
{
    ((IController) e.Instance).TrySetActionInvoker();
}

Original comment by scull...@gmail.com on 10 Feb 2012 at 10:47

Attachments:

GoogleCodeExporter commented 8 years ago
Hi! Anyone know what the update is on this one? Cheers.

Original comment by andrewdu...@gmail.com on 31 May 2012 at 6:49

GoogleCodeExporter commented 8 years ago
Did 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

Original comment by kev.r.jo...@gmail.com on 5 Aug 2012 at 7:43

GoogleCodeExporter commented 8 years ago
I tried the workaround (removing execution) and it did NOT work.

Original comment by sean.hed...@gmail.com on 7 Aug 2012 at 5:33

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 21 Sep 2012 at 4:34

GoogleCodeExporter commented 8 years ago
Adding some indirection around AutofacDependencyResolver.Current seems to fix 
the issue.

Original comment by travis.illig on 13 Dec 2012 at 5:49

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 13 Dec 2012 at 5:49

GoogleCodeExporter commented 8 years ago
I 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<AutofacDependencyResolver>(), 
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.

Original comment by travis.illig on 13 Dec 2012 at 7:18

GoogleCodeExporter commented 8 years ago
This issue was closed by revision e553f3cd3ecd.

Original comment by travis.illig on 13 Dec 2012 at 7:26

GoogleCodeExporter commented 8 years ago
I'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.<GetFilters>b__6(IFilterProvider fp) +19
   System.Linq.<SelectManyIterator>d__14`2.MoveNext() +234
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +216
   System.Linq.<GetEnumerator>d__0.MoveNext() +110
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +216
   System.Linq.<ReverseIterator>d__a0`1.MoveNext() +92
   System.Web.Mvc.<RemoveDuplicates>d__b.MoveNext() +114
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +216
   System.Linq.<ReverseIterator>d__a0`1.MoveNext() +92
   System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +85
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +381
   System.Linq.Enumerable.ToList(IEnumerable`1 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.<BeginExecuteCore>b__19() +23
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +19
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<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.<MakeVoidDelegate>b__3(IAsyncResult ar) +23
   System.Web.Mvc.Async.WrappedAsyncResult`1.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

Original comment by rodolfog...@gmail.com on 22 Jul 2013 at 12:28

GoogleCodeExporter commented 8 years ago
I'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.

Original comment by travis.illig on 22 Jul 2013 at 4:15