Using the Web API Dependency Resolver

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

Using the Web API Dependency Resolver

Overview
Videos
Samples
Forum

By Mike Wasson|February 6, 2012

Your First Web API (C#)
Deep Dive into Web API
Creating a Web API that Supports CRUD Operations
Sample: Contact Manager
Using Web API with Entity Framework
Creating a Help Page for a Web API
Introducing the ASP.NET Web API Help Page (Preview)
Sample: Introduction to HttpClient
Calling a Web API From a .NET Client (C#)
Calling a Web API From a WPF Application (C#)
Routing in ASP.NET Web API
Routing and Action Selection
Exception Handling in ASP.NET Web API
HTTP Message Handlers
Sending HTML Form Data: Form-urlencoded Data
Sending HTML Form Data: File Upload and Multipart MIME
HTTP Cookies
Batching HTTP Messages
Media Formatters
JSON and XML Serialization
Content Negotiation
Model Validation
OData support in ASP.NET Web API [Preview]
Self-Host a Web API  (C#)
Sample: ASP.NET Web API Self-Host
Using Web API with ASP.NET Web Forms
Mobile-friendly REST service using ASP.NET Web API and SQL Database
Tracing in ASP.NET Web API
ASP.NET Web API Tracing (Preview)
Configuring ASP.NET Web API
Using the Web API Dependency Resolver 
Brad Wilson’s Blog
Henrik’s Blog
Hongmei’s Blog
Kiran’s Blog
Mike Stall’s Blog
Yao’s Blog

This tutorial shows how to inject dependencies into your ASP.NET Web API controller, using the Web API dependency resolver.

dependency is an object or interface that another object requires. For example, in the tutorial Creating a Web API that Supports CRUD Operations, we defined a ProductsController class that requires an IProductRepositoryinstance. The implementation looked like this:

public class ProductsController : ApiController
{
    private static IProductRepository repository = new ProductRepository();

    // Controller methods not shown.
}

This is not the best design, because the call to new the ProductRepository is hard-coded into the controller class. To use a different implementation of IProductRepository, we would need to change the code inProductRepository. It is better if the ProductsController is not tied to any concrete instance ofIProductRepository.

Dependency injection addresses this problem. With dependency injection, an object is not responsible for creating its own dependencies. Instead, you inject the dependency when you create the object, through a constructor parameter or a setter method.

Here is a revised implementation of ProductsController:

public class ProductsController : ApiController
{
    private readonly IProductRepository repository;

    public ProductsController(IProductRepository repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }
        this.repository = repository;
    }

This is better. Now can switch to another IProductRepository instance without touching the implementation ofProductsController.

But wait — in ASP.NET Web API, you do not create the controller directly. Instead, the framework creates the controller for you, and the framework does not know anything about IProductRepository. The framework can only create your controller by calling a parameterless constructor.

This is where the dependency resolver comes in. The job of the dependency resolver is to create objects that the framework requires at run time, including controllers. By providing a custom dependency resolver, you can create controller instances on behalf of the framework.

A Simple Dependency Resolver

The following code shows a simple dependency resolver. This code is mainly just to show how dependency injection works in Web API. Later, we’ll see how to incorporate an IoC container for a more general solution.

// A simple implementation of IDependencyResolver, for example purposes.
class SimpleContainer : IDependencyResolver
{
    static readonly IProductRepository respository = new ProductRepository();

    public IDependencyScope BeginScope()
    {
        // This example does not support child scopes, so we simply return 'this'.
        return this; 
    }

    public object GetService(Type serviceType)
    {
        if (serviceType == typeof(ProductsController))
        {
            return new ProductsController(respository);
        }
        else
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return new List<object>();
    }

    public void Dispose()
    {
        // When BeginScope returns 'this', the Dispose method must be a no-op.
    }
}

A dependency resolver implements the IDependencyResolver interface. The IDependencyResolver interface  inherits two other interfaces, IDependencyScope and IDisposable:

namespace System.Web.Http.Dependencies
{
    public interface IDependencyResolver : IDependencyScope, IDisposable
    {
        IDependencyScope BeginScope();
    }

    public interface IDependencyScope : IDisposable
    {
        object GetService(Type serviceType);
        IEnumerable<object> GetServices(Type serviceType);
    }
}

The IDependencyScope interface defines two methods:

  • GetService: Creates one instance of a specified type.
  • GetServices: Create a collection of objects of a specified type.

For controllers, the framework calls GetService to get a single instance of the controller. This is where our simple container creates the controller and injects the repository.

For any types that your dependency resolver does not handle, GetService should return null, and GetServicesshould return an empty collection object. In particular, don’t throw an exception for unknown types.

The IDependencyResolver interface inherits IDependencyScope and adds one method:

  • BeginScope: Creates a nested scope.

Later, we will discuss how nested scopes are used to manage object lifetimes. For now, our implementation ofBeginScope simply returns this.

Setting the Dependency Resolver

Now set the dependency resolver on the Web API global configuration object.

In Solution Explorer, double-click Global.asax. Visual Studio will open the file named Global.asax.cs file, which is the code-behind file for Global.asax. This file contains code for handling application-level and session-level events in ASP.NET.

Inside the Application_Start method, set GlobalConfiguration.Configuration.DependencyResolver to your dependency resolver:

public class WebApiApplication : System.Web.HttpApplication
{
    void ConfigureApi(HttpConfiguration config)
    {
        config.DependencyResolver = new SimpleContainer();
    }

    protected void Application_Start()
    {
        ConfigureApi(GlobalConfiguration.Configuration);

        // ...
    }
}

Scope and Object Lifetime

Controllers are created per request. To help manage object lifetimes, IDependencyResolver uses the IDisposableinterface.

The dependency resolver attached to the HttpConfiguration object has global scope. When the framework creates a new instance of a controller, it calls IDependencyResolver.BeginScope. This method returns anIDependencyScope. The framework calls GetService on the IDependencyScope instance to get the controller. When the framework is done processing the request, it calls Dispose on the child scope. You can use the Disposemethod to dispose of the controller’s dependencies.

Dependency Injection with IoC Containers

An IoC container is a software component that is responsible for creating dependencies. IoC containers provide a general framework for dependency injection. If you use an IoC container, then you don’t need to wire up objects directly in code. Several open-source .Net IoC containers are available, such as Autofac, Castle Windsor, Ninject, Spring.NET, StructureMap, and others.

The following example uses uses Unity, an IoC container developed by Microsoft patterns & practices.

namespace ProductStore
{
    using System;
    using System.Collections.Generic;
    using System.Web.Http;
    using System.Web.Http.Dependencies;
    using Microsoft.Practices.Unity;

    class ScopeContainer : IDependencyScope
    {
        protected IUnityContainer container;

        public ScopeContainer(IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }

        public object GetService(Type serviceType)
        {
            if (container.IsRegistered(serviceType))
            {
                return container.Resolve(serviceType);
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            if (container.IsRegistered(serviceType))
            {
                return container.ResolveAll(serviceType);
            }
            else
            {
                return new List<object>();
            }
        }

        public void Dispose()
        {
            container.Dispose();
        }
    }

    class IoCContainer : ScopeContainer, IDependencyResolver
    {
        public IoCContainer(IUnityContainer container)
            : base(container)
        {
        }

        public IDependencyScope BeginScope()
        {
            var child = container.CreateChildContainer();
            return new ScopeContainer(child);
        }
    }
}

The ScopeContainer class implements IDependencyScope and represents a child scope. The IoCContainer class implements the global-scope dependency resolver. In the BeginScope method, it creates a new ScopeContainerinstance. The Unity container also has the concept of a child container, so we initialize the child ScopeContainerwith a Unity child container. The ScopeContainer.Dispose method disposes of the Unity child container.

The following code registers the controller and the repository with Unity and then sets the dependency resolver:

void ConfigureApi(HttpConfiguration config)
{
    var unity = new UnityContainer();
    unity.RegisterType<ProductsController>();
    unity.RegisterType<IProductRepository, ProductRepository>(
        new HierarchicalLifetimeManager());
    config.DependencyResolver = new IoCContainer(unity);
}
Advertisements

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