autofac / Autofac.Mvc

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

RequestLifetimeScopeProvider.EndLifetimeScope throws NullReferenceException when both OWIN middleware and MVC integration #20

Closed craigfowler closed 7 years ago

craigfowler commented 7 years ago

Using the Autofac MVC integration coexisting with the OWIN integration in the same application can result in an exception raised from the MVC integration's RequestLifetimeScopeProvider class.

Reproduction

This can occur when an HTTP request uses only the OWIN middleware and does not make any use of the regular MVC5 stack. I experienced this when making use of OAuth functionality from OWIN.

I have only tried this with ASP.NET MVC5 and not the newer ASP.NET Core.

In my first reproduction case I was using an application which used both OWIN middleware (OAuth JWT bearer token auth in my case) which included some injected components and also ASP.NET MVC5 in the same app. I received the following exception when performing an HTTP request to the oauth JWT token endpoint:

[System.NullReferenceException]: Object reference not set to an instance of an object
  at Autofac.Integration.Mvc.RequestLifetimeScopeProvider.get_LifetimeScope () [0x00005] in <12b7e1f0a3c84261a70bb084357848f1>:0 
  at Autofac.Integration.Mvc.RequestLifetimeScopeProvider.EndLifetimeScope () [0x00000] in <12b7e1f0a3c84261a70bb084357848f1>:0 
  at Autofac.Integration.Mvc.RequestLifetimeHttpModule.OnEndRequest (System.Object sender, System.EventArgs e) [0x0000c] in <12b7e1f0a3c84261a70bb084357848f1>:0 
  at (wrapper delegate-invoke) <Module>:invoke_void_object_EventArgs (object,System.EventArgs)
  at System.Web.HttpApplication.PipelineDone () [0x0001c] in <e6ac3c4d7fe1491da2402c546c0c1c72>:0 

Root cause

Because the MVC stack is not used, HttpContext.Current is null. However, RequestLifetimeHttpModule triggers RequestLifetimeScopeProvider.EndLifetimeScope regardless as it's registered as an HTTP module. The lifetime scope provider has a hard dependency upon HttpContext.Current and crashes with an exception in this case.

Workaround

You may work around this by subclassing RequestLifetimeScopeProvider as follows.

public class OwinCompatibleLifetimeScopeProvider : RequestLifetimeScopeProvider, ILifetimeScopeProvider
{
  public new void EndLifetimeScope()
  {
    // No-op if HttpContext.Current is null
    if(HttpContext.Current != null)
    {
      base.EndLifetimeScope();
    }
  }

  void ILifetimeScopeProvider.EndLifetimeScope()
  {
    this.EndLifetimeScope();
  }

  public OwinCompatibleLifetimeScopeProvider(ILifetimeScope scope) : base(scope) {}
}

Then, when configuring Autofac for MVC, construct and use the alternative provider explicitly:

var container = GetContainer();
var provider = new OwinCompatibleLifetimeScopeProvider(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container, provider));
craigfowler commented 7 years ago

Discovered using v3.3.4 of the integration but still present in latest master at this point.

tillig commented 7 years ago

Nice catch, and thanks for the PR!

tillig commented 7 years ago

Published as 4.0.2

cmshawns commented 7 years ago

Has this fix also been applied to AutoFac.WebApi2? If not, can it be? I'm having the same issue, but in a WebApi project.

tillig commented 7 years ago

Web API works very differently than MVC when it comes to creating a request lifetime scope. If you're having a problem with Web API, please file an issue in that repository and include some details like exception call stack, link to a project where it's happening, etc. Thanks!