Tuesday, August 13, 2013

Dependency injection with Unity in ASP.NET Web API


Hello World,

I have this shiny new project that I'm working for that is based on the ASP.NET Web API and SPA architecture. Before I describe where Unity comes into picture, let be briefly outline the pieces in the setup.
If those technologies sound unfamiliar, here are a couple of getting started links for the uninitiated:
ASP.NET Web API
SPA (Single Page Application)

SPA? API - Say What Now?
                      The basic premise of this architecture setup (IMHO) is that you design your services as REST APIs exposed over HTTP and the SPA piece provides the view that calls into your API. Where SPA differs from a traditional ASP.NET MVC application is that you have a single view that renders itself from the data fetched via an Ajax request to the Web API. In a typical setup, for the SPA application, the routing and data binding is taken care of by client-side scripting (compare this to a standard MVC app where the view engine takes care of the model binding while the routing is taken care of by the server side MVC routing framework complete with mapping actions on controllers to routes on the route table.
                       There are mature, robust client side frameworks for the client side, typically known as MV* frameworks - called so because there is typically no server side controller/routing. The most popular ones (as per my research) are:

  1. Backbone.js
  2. Spine
  3. Durandal - This is one you would find if you install the (famous) Hot Towel SPA NuGet package.

These frameworks fit nicely with popular JavaScript frameworks like jQuery and clientside UI frameworks like KnockoutJS. It may sound like a steep learning curve at the outset, but believe me, once you dig in with an open mind, you'd be feeling "why wasn't I using all of this earlier?"

DI Anyone?
           When designing applications, the most common concerns are that there should be a clear separation between the domain logic and the infrastructure code - e.g. Logging, Authentication, Authorization etc. Your business object may require other components to do its job e.g. connect to a database or read configuration from a file or an LDAP server (like the Microsoft Active Directory). A good design would try to keep the domain objects loosely coupled with these dependencies so that the resulting code is more testable (dependencies like database or LDAP could be mocked) and extensible (you may swap out the actual concrete implementation by another without the client code being affected). This is where IoC (Inversion of Control) and hence Dependency Injection fit in.

Unity - thy friend 
           The Unity application block from Microsoft's Pattern and Practices team is one of the many choices for managing your dependencies. Since other products were already using it, we choose to go with Unity. To add Unity to your Web API project, the easiest way is through NuGet. Right click you project and choose Manage NuGet packages

Were going to need the reference to the following assemblies: (check this link)

Microsoft.Practices.EnterpriseLibrary.Common.dll
Microsoft.Practices.ServiceLocation.dll
Microsoft.Practices.Unity.dll (current version 3.0.1304.0 at the time of this writing)
Unity.WebAPI.dll

The corresponding NuGet packages are:
 Enterprise Library common
 Enterprise library policy injection
 Unity Interception extension
 Unity WebAPI

Before and After 
             A typical Web API controller class derives from the ApiController base class provided by the ASP.NET Web API framework like so:

public class StaticDataController : ApiController

Now suppose your controller needs the following services (or dependencies)
A Logger - say ILogger
A repository to talk with the data source - say IRepository

If you were not using a DI container, you would have to something like the below to get there dependencies:

        private readonly ILogger _logger;

        private readonly IRepository _websiteTemplateRepository;

        public MyDataController()
        {
            _logger = SomeServiceLocator.GetService(typeof(ILogger));
            _theRepository = SomeServiceLocator.GetService(typeof(IRepository));
        }
If that looks strange, fear not, it is the Service Locator anti-pattern

What you would rather do is have your constructor demand these as dependencies and let a DI container inject those from its registrations. So the same controller would look like this:
private readonly ILogger _logger;

        private readonly IRepository _websiteTemplateRepository;

        public MyDataController(ILogger logger, IRepository repository)
        {
            _logger = logger;
            _theRepository = repository;
        }
When using the Unity container, you just have to structure your controllers (or other classes that need the services) like above and once you have registered the dependencies into the container like so:
var container = new UnityContainer();

container.RegisterType<IService, ConcreteService>(new ContainerControlledLifetimeManager());

the container would see (through the Unity.WebAPI piece) that these dependencies need to be injected and it would oblige!
The Unity.WebAPI package adds a bootstrapper.cs class that shows you what is expected. You'll need to call the bootstrapping code from the Global.asax.cs Application_start() method and then register your container with the IDependencyResolver like this:
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

That is pretty much it!
Further reading:
Unity - getting started
Unity - Lifetime Managers
aExpense Reference Implementation (RI)

Summary: This package contains the aExpense Reference Implementation to showcase the use of Enterprise Library application blocks. There are two versions of the reference implementation: one using Enterprise Library 5.0 and another one using Enterprise Library 6.0. The objective was to assist you not only with getting acquianted with Enterprise Library, but also with migrating from the previous version.

The most up-to-date version of the documentation and release notes is available online:
http://go.microsoft.com/fwlink/p/?LinkID=290917


Microsoft patterns & practices
http://msdn.microsoft.com/practices


Happy Coding!

No comments:

Post a Comment