38

How do I inject dependencies into the global.asax.cs, i.e. the MvcApplication class?

Having previously used the Service Locator (anti-)pattern for dependency injection, I am trying to follow best practice advice in my latest MVC application by using an IOC container (specifically Unity.Mvc3 because it comes with an implementation of the IDependencyResolver out of the box) and constructor injection.

Everything seems quite straight forward so far except for a couple of snags, one of which is in the global.asax.cs (the other is for custom attributes but there's aleady a question on SO covering that).

The HttpApplication event handlers in the MvcApplication class such as:

Application_Start()
Application_EndRequest(object sender, EventArgs e)
Application_AcquireRequestState(object sender, EventArgs e)

may require external dependencies, e.g. a dependency on an ILogService. So how do I inject them without resorting to the service locator (anti-)pattern of e.g.

private static ILogService LogService
{
    get
    {
        return DependencyResolver.Current.GetService<ILogService>();
    }
}

Any help/advice greatly appreciated!

magritte
  • 7,396
  • 10
  • 59
  • 79
  • Hi, interesting question! Why can't you inject dependencies within your global.asax in OnApplicationStarted? If application can't start you'll be aware of it as nothing will work... –  Oct 13 '11 at 09:32

2 Answers2

42

The class in your global.asax.cs is your Composition Root, so you can't (and shouldn't) inject anything into it from the outside.

However, there's only one instance of the MvcApplication class, so if you need a service in one of its methods, you can just declare it as a member field - e.g:

public class MvcApplication : System.Web.HttpApplication
{
    private readonly ILogService log;

    public MvcApplication()
    {
        this.log = new MyLogService();
    }

    protected void Application_Start()
    {
        // ...

        this.log.Log("Application started");
    }
}
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 1
    Thanks for the quick reply Mark. How do you unit test the methods though if you can't inject a mocked instance of e.g. the ILogService? – magritte Oct 13 '11 at 10:13
  • 4
    I don't. A Composition Root is an example of a Humble Object (http://xunitpatterns.com/Humble%20Object.html). If you need to invoke complex logic from it, you can delegate to another class which *can* be unit tested. – Mark Seemann Oct 13 '11 at 10:34
  • 3
    Hmm, you say on your blog post that "A DI Container should only be referenced from the Composition Root. All other modules should have no reference to the container.". Doesn't that give me the freedom to call resolve so long as it's within the composition root then, i.e. my code is fine as is? One thing that troubles me with your example here is your call to this.log = new MyLogService(). Since we have already intialised the container at this point, then why not use it? If we then want to swap the ILogService out for another one we only have to change it in one place, the container. – magritte Oct 13 '11 at 21:59
  • P.s. I should add, I have followed your advice and my global.asax.cs is massively streamlined now, thanks :-) – magritte Oct 13 '11 at 22:44
  • 1
    In my answer I made no assumption on whether or not you'd use a DI Container. If you use a container, you can resolve from that instead of instantiating it directly... – Mark Seemann Oct 14 '11 at 05:37
  • Ok, great. Thanks for the input Mark, appreciate it. – magritte Oct 14 '11 at 08:20
  • 3
    "there's only one instance of the MvcApplication class" is plain wrong - there is one HttpApplication instance for each request that is handled in parallel. Note that Application_Start is NOT called on each newly created instance but only once for per running web application. Excellent blog post about this: http://blog.andreloker.de/post/2008/05/HttpApplication-instances.aspx – blueling Sep 26 '13 at 21:11
  • creating instance manually like this sometimes is just impossible, there are a lot of other dependencies (in tree) involved :D – Hopeless Jun 12 '20 at 03:12
0

You must use AutofacConfig.Resolve<T>() instead using DependencyResolver.Current.GetService<T>() to get your services without errors.