Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac, MVC (with ActionFilters), Web.Forms - dependency resolution conflict

I've got a legacy Web.Forms app that been partially rewritten to MVC. MVC part uses autofac as a dependency injection container.

MVC part have custom filter defined:

public class CustomActionFilter : ActionFilterAttribute
{
    protected ILogger Logger { get; set; }
    public CustomActionFilter(ILogger logger) { Logger = logger; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Logger.Log("OnActionExecuting");
    }
}

It works fine when Web.Forms integration is disabled in web.config. Hovewer, when I try to use Web.Forms autofac integration, I've got the NullReferenceException related to AutofacFilterProvider somewhere in autofac internals (stack trace).

  • Global.asax.cs: http://pastebin.com/437Tnp0t
  • web.config: http://pastebin.com/5pU6SH6c

Note that CustomActionFilter is registered as global filter, thus it is registered with autofac:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(DependencyResolver.Current.GetService<CustomActionFilter>());
    }
}

I've tried:

  1. using separate containers for MVC and Web.Forms - same result
  2. Use property injection instead of constructor - same result
  3. Explicitly trigger dependencies resolution on web.forms pages (like this) - worked

So, the question is, are there any way to provide behind-the-scenes dependency resolution both to MVC and web.forms part. I'm new to autofac and somewhat new to dependency injection containers in general, so I might just miss something obvious.

Update: error has nothing to do with custom filters. If I remove all references to custom filters the bug behavior still the same, even the stack trace.

like image 510
J0HN Avatar asked Aug 20 '13 16:08

J0HN


1 Answers

Actually there are two bugs? in Autofac which causing this behavior:

Bug #1: As side effect of the fix of Issue 351 the AutofacDependencyResolver needs to registered in the created Request bound LifeTimeScopes. The MVC intergration does this but the Winforms integration of course does not.

Bug? #2: Both the RequestLifetimeScopeProvider and the ContainerProvider stores the created ILifetimeScope with the same key HttpContext.Current.Items:

static ILifetimeScope LifetimeScope
{
    get { return (ILifetimeScope)HttpContext.Current.Items[typeof(ILifetimeScope)]; }
    set { HttpContext.Current.Items[typeof(ILifetimeScope)] = value; }
}

So there is a little bit race condition here because depending on which module gets executed first the WebForms or the MVC intergartion ILifetimeScope wins. So if the WebForms module wins the AutofacDependencyResolver won't be registered and you get the nice non descriptive exception.

Fix/workaround:

But there is an simple workaround: you just need to register the AutofacDependencyResolver in the ContainerProvider requestLifetimeConfiguration so no matter which one wins (WebForm vs. MVC) the AutofacDependencyResolver will be always registered:

var autofacDependencyResolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(autofacDependencyResolver);
_containerProvider = new ContainerProvider(container, requestContainerBuilder => 
     requestContainerBuilder.RegisterInstance(autofacDependencyResolver)
     .As<AutofacDependencyResolver>());
like image 83
nemesv Avatar answered Nov 11 '22 10:11

nemesv