Friday, May 6, 2011

IoC - Unity as a DI and Service Locator container

Inversion of control (IoC) is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to procedural programming. Rather than a caller deciding how to use an object, in this technique the object called decides when and how to answer the caller, so the caller is not in charge of controlling the main flow of the application. This approach makes your code flexible enough to be decoupled.

Some of the main advantages of using IoC in your code are
  • Your code gets decoupled so you can easily exchange implementations of an interface with alternative implementations
  • It is a strong motivator for coding against interfaces instead of implementations
  • It's very easy to write unit tests for your code because it depends on nothing else than the objects it accepts in its constructor/setters and you can easily initialize them with the right objects in isolation.

The pattern is implemented through injecting dependencies into a component when it is constructed. These dependences are usually provided as interfaces for further decoupling and to support testability.

IoC can be implemented using many techniques as given below
  • Setter Injection
  • Constructor Injection
  • Interface Injection
  • Factory Pattern
  • Service Locator Pattern etc.

This post we'll see how to use the Unity Application block as a DI container and Service Locator implementation for implementation of the IoC pattern.

Sample object model used in the example.


Unit as a DI container
The example code we use has ViewModel which has a dependency on a CustomerRepository. The CustomerRepository is declared in the container and it is responsible to create and instance and resolve the dependency when the ViewModel is created. To specify the dependency we have decorated the constructor of the ViewModel with an [InjectionConstructor] attribute to specify that Unity will be in charge of creating this object at runtime.
public class CustomerViewModel
{
    [InjectionConstructor]
    public CustomerViewModel(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public void LoadCustomers()
    {
        Customers = new ObservableCollection<Customer>(_customerRepository.GetAll());
    }

    public ObservableCollection<Customer> Customers { get; set; }
    private readonly ICustomerRepository _customerRepository;
}

[TestClass]
public class CustomerViewModelFixture
{
    [TestInitialize]
    public void Initialize()
    {
        _container = new UnityContainer()
            .RegisterType<ICustomerRepository, CustomerRepository>()
            .RegisterType<CustomerViewModel>();
    }


    [TestMethod]
    public void LoadDataShouldLoadTheCustomersFromContextUsingDiTest()
    {
        var viewModel = _container.Resolve<CustomerViewModel>();
        viewModel.LoadCustomers();
        Assert.IsTrue(viewModel.Customers.Count > 0);
    }

    private IUnityContainer _container;
}

Unity as Service Locator
To use the Service Locator with Unity you need an adapter, which you can find on the CodePlex website at http://commonservicelocator.codeplex.com . You can create an adapter as given below.
_container = new UnityContainer()
    .RegisterType<ICustomerRepository, CustomerRepository>()
    .RegisterType<CustomerViewModel>();

var provider = new UnityServiceLocator(_container);
ServiceLocator.SetLocatorProvider(() => provider);

_serviceLocatorProvider = ServiceLocator.Current;

And then use this Service locator to resolve the dependencies in your code like.
var customerRepository = _serviceLocatorProvider.GetInstance<ICustomerRepository>();
var viewModel = new CustomerViewModel(customerRepository);
viewModel.LoadCustomers();
Assert.IsTrue(viewModel.Customers.Count > 0);

No comments: