Integrating ASP.NET Web API with Castle Windsor

Currently ASP.NET Web API seems like the tool of choice for building RESTful APIs using the .NET framework . Overall it seems a lot better thought out than “vanilla” ASP.NET MVC with easier and more extensibility points. The fact that it is open source is awesome too. It is not perfect, but miles better than WCF for building any kind of lightweight web service at the moment. One of my favourite features are Delegating Handlers (which I might cover in a future article..) which in particular are very powerful.

For most real world applications that will be built using Web API, using Dependency Injection will generally be a good idea. I’ve always been a big Castle Windsor fan, and even though there are plenty of great IoC containers available, Castle has always been the old faithful for me, and I have yet to encounter a DI problem that I couldn’t solve using Castle.

There are a few different ways to integrate a container with Web API, however since Castle uses the Resolve-Release pattern, I was happiest with using the Dependency Scopes built in to WebAPI as it supports releasing dependencies in a graceful way and it works under both IIS and self-hosting.

The key interfaces are IDependencyResolver and IDependencyScope which serve as the main integration points into the Web API. Keep in mind the IDependencyResolver in Web API is not the same as the one in MVC, even though they share the same interface name. The namespaces are different, which can be a little confusing as a Web API application is also a MVC application at the same time. This seems to be a common theme throughout Web API as several key interfaces will have a Web API version and MVC version and things might get confusing sometimes.

The IDependencyResolver interface is used to resolve everything outside a request scope. This means all the infrastructural interfaces of WebApi (for example, IHttpControllerActivator) are resolved using the IDependencyResolver. If the resolver returns null, then the default implementation is used. The IDependencyResolver is never disposed by the framework, and it’s only ever used to resolve singletons so the Resolve / Release pattern does not apply to the IDependencyResolver itself.  A typical IDependencyResolver implementation using Windsor might look this:

internal class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IKernel container;

    public WindsorDependencyResolver(IKernel container)
    {
        this.container = container;
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(this.container);
    }

    public object GetService(Type serviceType)
    {
        return this.container.HasComponent(serviceType) ? this.container.Resolve(serviceType) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.container.ResolveAll(serviceType).Cast<object>();
    }

    public void Dispose() {}
}

Quite straightforward, except that it’s important that the GetService method should return null if the component was not available, this will ensure that the framework default implementation will be used instead. This is likely the behaviour you want most of the time.

During the life-cycle of a request, a dependency scope (implemented by IDependencyScope) is created on the request using the BeginScope method on the IDependencyResolver. At the end of the request, the dependency scope is disposed. This allow us to implement the Resolve / Release pattern using Castle Windsor.

public class WindsorDependencyScope : IDependencyScope
{
    private readonly IKernel container;
    private readonly IDisposable scope;

    public WindsorDependencyScope(IKernel container)
    {
        this.container = container;
        this.scope = container.BeginScope();
    }

    public object GetService(Type serviceType)
    {
        return this.container.HasComponent(serviceType) ? this.container.Resolve(serviceType) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.container.ResolveAll(serviceType).Cast<object>();
    }

    public void Dispose()
    {
        this.scope.Dispose();
    }
}

The Scoped Lifestyle is a new lifestyle in Castle.Windsor 3 that makes it possible to create an arbitrary scope bounded by the object returned from the Container.BeginScope call. When this object is disposed, the scope is ended and Castle will then release all the objects with Scoped lifestyle that have been resolved in the same call stack after the scope is generated.

As the top level object within the request scope will be the Controller, the Controllers need to be registered with a Scoped lifestyle to make sure that they will get released at the end of the request when the dependency scope ends.

public class WindsorWebApiInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes.FromThisAssembly().BasedOn<ApiController>().LifestyleScoped());
    }
}

Finally, we need to replace the default dependency resolver with the Windsor implementation in global.asax and install our dependencies:

protected void Application_Start()
{
    ...
    var container = new WindsorContainer();
    container.Install(FromAssembly.This());
    GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(container.Kernel);
    ...
}

A fully working sample application is also available on GitHub.

Advertisements

One thought on “Integrating ASP.NET Web API with Castle Windsor

  1. Thanks, I was able to resolve a memory leak in my application by using the scoped lifestyle you outline above. My previous attempt used a child container and for some reason even though I was disposing the child container, the parent container was hanging onto instances of my controllers, even though they had transient lifestyles.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s