Note 2014-04-03 19:46 UTC: This post describes how to address various Dependency Injection issues with a Community Technical Preview (CTP) of ASP.NET Web API 1. Unless you're still using that 2012 CTP, it's no longer relevant. Instead, refer to my article about Dependency Injection with the final version of Web API 1 (which is also relevant for Web API 2).

Like the WCF Web API, the new ASP.NET Web API supports Dependency Injection (DI), but the approach is different and the resulting code you'll have to write is likely to be more complex. This post describes how to enable robust DI with the new Web API. Since this is based on the beta release, I hope that it will become easier in the final release.

At first glance, enabling DI on an ASP.NET Web API looks seductively simple. As always, though, the devil is in the details. Nikos Baxevanis has already provided a more thorough description, but it's even more tricky than that.

Protocol

To enable DI, all you have to do is to call the SetResolver method, right? It even has an overload that enables you to supply two code blocks instead of implementing an interface (although you can certainly also implement IDependencyResolver). Could it be any easier than that?

Yes, it most certainly could.

Imagine that you'd like to hook up your DI Container of choice. As a first attempt, you try something like this:

GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
    t => this.container.Resolve(t),
    t => this.container.ResolveAll(t).Cast<object>());

This compiles. Does it work? Yes, but in a rather scary manner. Although it satisfies the interface, it doesn't satisfy the protocol ("an interface describes whether two components will fit together, while a protocol describes whether they will work together." (GOOS, p. 58)).

The protocol, in this case, is that if you (or rather the container) can't resolve the type, you should return null. What's even worse is that if your code throws an exception (any exception, apparently), DependencyResolver will suppress it. In case you didn't know, this is strongly frowned upon in the .NET Framework Design Guidelines.

Even so, the official introduction article instead chooses to play along with the protocol and explicitly handle any exceptions. Something along the lines of this ugly code:

GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
    t =>
    {
        try
        {
            return this.container.Resolve(t);
        }
        catch (ComponentNotFoundException)
        {
            return null;
        }
    },
    t =>
    {
        try
        {
            return this.container.ResolveAll(t).Cast<object>();
        }
        catch (ComponentNotFoundException)
        {
            return new List<object>();
        }
    }
);

Notice how try/catch is used for control flow - another major no no in the .NET Framework Design Guidelines.

At least with a good DI Container, we can do something like this instead:

GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
    t => this.container.Kernel.HasComponent(t) ?
        this.container.Resolve(t) :
        null,
    t => this.container.ResolveAll(t).Cast<object>());

Still, first impressions don't exactly inspire trust in the implementation...

API Design Issues

Next, I would like to direct your attention to the DependencyResolver API. At its core, it looks like this:

public interface IDependencyResolver
{
    object GetService(Type serviceType);
    IEnumerable<object> GetServices(Type serviceType);
}

It can create objects, but what about decommissioning? What if, deep in a dependency graph, a Controller contains an IDisposable object? This is not a particularly exotic scenario - it might be an instance of an Entity Framework ObjectContext. While an ApiController itself implements IDisposable, it may not know that it contains an injected object graph with one or more IDisposable leaf nodes.

It's a fundamental rule of DI that you must Release what you Resolve. That's not possible with the DependencyResolver API. The result may be memory leaks.

Fortunately, it turns out that there's a fix for this (at least for Controllers). Unfortunately, this workaround leverages another design problem with DependencyResolver.

Mixed Responsibilities

It turns out that when you wire a custom resolver up with the SetResolver method, the ASP.NET Web API will query your custom resolver (such as a DI Container) for not only your application classes, but also for its own infrastructure components. That surprised me a bit because of the mixed responsibility, but at least this is a useful hook.

One of the first types the framework will ask for is an instance of IHttpControllerFactory, which looks like this:

public interface IHttpControllerFactory
{
    IHttpController CreateController(HttpControllerContext controllerContext,
        string controllerName);
    void ReleaseController(IHttpController controller);
}

Fortunately, this interface has a Release hook, so at least it's possible to release Controller instances, which is most important because there will be a lot of them (one per HTTP request).

Discoverability Issues

The IHttpControllerFactory looks a lot like the well-known ASP.NET MVC IControllerFactory interface, but there are subtle differences. In ASP.NET MVC, there's a DefaultControllerFactory with appropriate virtual methods one can overwrite (it follows the Template Method pattern).

There's also a DefaultControllerFactory in the Web API, but unfortunately no Template Methods to override. While I could write an algorithm that maps from the controllerName parameter to a type which can be passed to a DI Container, I'd rather prefer to be able to reuse the implementation which the DefaultControllerFactory contains.

In ASP.NET MVC, this is possible by overriding the GetControllerInstance method, but it turns out that the Web API (beta) does this slightly differently. It favors composition over inheritance (which is actually a good thing, so kudos for that), so after mapping controllerName to a Type instance, it invokes an instance of the IHttpControllerActivator interface (did I hear anyone say "FactoryFactory?"). Very loosely coupled (good), but not very discoverable (not so good). It would have been more discoverable if DefaultControllerFactory had used Constructor Injection to get its dependency, rather than relying on the Service Locator which DependencyResolver really is.

However, this is only an issue if you need to hook into the Controller creation process, e.g. in order to capture the HttpControllerContext for further use. In normal scenarios, despite what Nikos Baxevanis describes in his blog post, you don't have to override or implement IHttpControllerFactory.CreateController. The DependencyResolver infrastructure will automatically invoke your GetService implementation (or the corresponding code block) whenever a Controller instance is required.

Releasing Controllers

The easiest way to make sure that all Controller instances are being properly released is to derive a class from DefaultControllerFactory and override the ReleaseController method:

public class ReleasingControllerFactory : DefaultHttpControllerFactory
{
    private readonly Action<object> release;
 
    public ReleasingControllerFactory(Action<object> releaseCallback,
        HttpConfiguration configuration)
        : base(configuration)
    {
        this.release = releaseCallback;
    }
 
    public override void ReleaseController(IHttpController controller)
    {
        this.release(controller);
        base.ReleaseController(controller);
    }
}

Notice that it's not necessary to override the CreateController method, since the default implementation is good enough - it'll ask the DependencyResolver for an instance of IHttpControllerActivator, which will again ask the DependencyResolver for an instance of the Controller type, in the end invoking your custom GetObject implemention.

To keep the above example generic, I just injected an Action<object> into ReleasingControllerFactory - I really don't wish to turn this into a discussion about the merits and demerits of various DI Containers. In any case, I'll leave it as an exercise to you to wire up your favorite DI Container so that the releaseCallback is actually a call to the container's Release method.

Lifetime Cycles of Infrastructure Components

Before I conclude, I'd like to point out another POLA violation that hit me during my investigation.

The ASP.NET Web API utilizes DependencyResolver to resolve its own infrastructure types (such as IHttpControllerFactory, IHttpControllerActivator, etc.). Any custom DependencyResolver you supply will also be queried for these types. However:

When resolving infrastructure components, the Web API doesn't respect any custom lifecycle you may have defined for these components.

At a certain point while I investigated this, I wanted to configure a custom IHttpControllerActivator to have a Web Request Context (my book, section 8.3.4) - in other words, I wanted to create a new instance of IHttpControllerActivator for each incoming HTTP request.

This is not possible. The framework queries a custom DependencyResolver for an infrastructure type, but even when it receives an instance (i.e. not null), it doesn't trust the DependencyResolver to efficiently manage the lifetime of that instance. Instead, it caches this instance for ever, and never asks for it again. This is, in my opinion, a mistaken responsibility, and I hope it will be corrected in the final release.

Concluding Thoughts

Wiring up the ASP.NET Web API with robust DI is possible, but much harder than it ought to be. Suggestions for improvements are:

  • A Release hook in DependencyResolver.
  • The framework itself should trust the DependencyResolver to efficiently manage lifetime of all objects it create.

As I've described, there are other places were minor adjustments would be helpful, but these two suggestions are the most important ones.

Update (2012.03.21): I've posted this feedback to the product group on uservoice and Connect - if you agree, please visit those sites and vote up the issues.


Comments

"A Release hook in DependencyResolver."
Won't happen. The release issue was highlighted during the RCs and Beta releases and the feedback from Brad Wilson was they were not going to add a release mechanism :(

The same applies to the *Activators that where added (IViewPageActivator, etc.), they really need a release hook too
2012-03-21 14:29 UTC
Why not?
2012-03-21 14:46 UTC
Jaime Febres
That's the kind of problems when you use a framework that considers DI a second citizen and not really something that is bundled in the heart of it.
I know for some people is not an option whether use or not what MVC produces, if you are not one of them, I suggest you give a try to FubuMVC, a MVC framework built from the beginning with DI in mind.
It has its own shortcoming, but the advantages surpasses the problems.
The issue you had about not releasing disposable objects is simply non an issue in FubuMVC.
Kind regards,
Jaime.
2012-03-21 15:34 UTC
Jaime, yes, I'm aware of FubuMVC, but have never tried it for a couple of reasons.

First of all, right now I need a framework for building REST services, and not a web framework. FubuMVC might have gained REST features (such as conneg) since last I looked, but the ASP.NET Web API does have quite an attractive feature set for building REST APIs.

Secondly, last time I discussed the issue of releasing components, Jeremy Miller was very much against it. StructureMap doesn't have a Release hook, so I wonder whether FubuMVC does...

Personally, I'm not against trying other technologies, and I've previously looked a bit at OpenRasta and Nancy. However, many of my clients prefer Microsoft technologies.

I must also admit to be somewhat taken aback by the direction Microsoft has taken here. The WCF Web API was really good, so I also felt it was my duty to provide feedback to Microsoft as well as the community about this.
2012-03-21 16:02 UTC
Jaime Febres
Hi Mark,
Yes, SM does not have a built-in release hook, I agree on that, but fubumvc uses something called "NestedContainer".

This nested container shares the same settings of your top level container (often StructureMap.ObjectFactory.Container), but with one added bonus, on disposal, also disposes any disposable dependency it resolved during the request lifetime.

And all of this is controller by behaviors that wrap an action call at runtime (but configured at start-up), sorta a "Russian Doll Model" like fubu folks like to call to this.
So all these behaviors wrap each other, allowing you to effectively dispose resources.
To avoid giving wrong explanations, I better share a link which already does this in an effective way:
http://codebetter.com/jeremymiller/2011/01/09/fubumvcs-internal-runtime-the-russian-doll-model-and-how-it-compares-to-asp-net-mvc-and-openrasta/

And by no means, don't take my words as a harsh opinion against MS MVC, it just a matter of preferences, if to people out there MS MVC or ASP.Net Web API solves their needs, I will not try to convince you otherwise.

Kind regards,
Jaime.

2012-03-21 16:42 UTC
Jaime, it's good feedback - I'm receiving it in the most positive way :)
2012-03-21 16:45 UTC
Mark do you know if the Unity.WebAPI NuGet Package are releasing controllers in a proper manor?

Im currently using it to register my repository following this guidance: http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package

Thanks,
Vindberg.
2012-03-23 08:05 UTC
Anders, no I don't know, but I would be slightly surprised if it does. Unity (2.0) has several issues related to proper decommissioning. In section 14.2 in my book I describe those issues and how to overcome them.
2012-03-23 08:34 UTC
thomas
I've also experienced these problems that I descibed here : http://www.codedistillers.com/tja/2012/03/11/web-api-beta-and-castle-windsorwithout-idependencyresolver/. IDependencyResolver adds another layer of indirection and the API is not self describing about what parts you should implement if you want the "Release" method...
2012-03-26 10:18 UTC
Chelsea Taylor
@Anders - We are using Unity.WebAPI and it is certainly decommissioning components correctly in our projects. Internally it uses a child container per http request.
2012-03-26 15:38 UTC
Ethan J. Brown
I will take the opportunity here to plug ServiceStack for REST based .NET services. Hands down my framework of choice (after having used WCF for years). (Nancy is good too for other reasons, but ServiceStack has a more directly service oriented approach.)

https://github.com/ServiceStack


The ServiceStack philosophy on IoC - https://github.com/ServiceStack/ServiceStack/wiki/The-IoC-container

I'm sure you'll take issue with something in the stack, but keep in mind Demis iterates very quickly and the stack is a very pragmatic / results driven one. Unlike Microsoft, he's very willing to accept patches, etc where things may fall short of user reqs, so if you have feedback, he's always listening.
2012-03-30 00:04 UTC
Cristiano
Great post Mark, I'm 100% on your side.
Just beyond my understanding how you can design a support for IoC container with no decommissioning.
Hopefully MS will fix this issue/lackness before RTM
2012-04-11 10:12 UTC
JD
So I'm not really sure where this left off. I see it marked as "resolved" here: http://aspnetwebstack.codeplex.com/workitem/26

But I don't see an ASP.NET MVC release number assigned to it. There is no .Release() method in the ASP.NET MVC 4 release candidate...safe to say they aren't resolving this until the next release?
2012-06-05 18:20 UTC
Chris Paynter
Hey Mark, I cannot find DefaultHttpControllerFactory, and Resharper is unable to resolve it automatically. Googling for a namespace or information regarding it's inclusion in the RC of MVC 4 is unfruitful. Has the name of the class been changed since you authored this post?

I've found this article very useful in understanding the use of Windsor with Web API, and I am now wondering whether anything has changed in the RC of MVC 4 that would make any part of this method redundant? Would be great to get an update from you regarding the current status of the framework with regards to implementing an IOC with Web API.

Many Thanks

Chris
2012-08-07 10:02 UTC
The class may very well have changed since the beta.

In the future, I may add an update to this article, unless someone else beats me to it.
2012-08-13 12:20 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.

Published

Tuesday, 20 March 2012 16:02:51 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!