Dependency Injection With Ninject And Extending It a Bit Further

In this post I am going to discuss a very interesting concept called “dependency injection (DI)” and also about extending the class that injects the dependencies further to achieve some more functionalities that I needed for a project of mine. I am going to use a mvc 3 application to explain about DI. DI is a type of interface programming that allows you to create loosely coupled systems. This increases testability and also reduces the amount of changes required to a project for adding / removing features. At this point it may be confusing, but once I discuss more about this with some examples, it will be much more clearer.

A system implementing DI could be pictured of as having 3 components:

  • Dependent Consumer
  • Dependency
  • Dependency Injector

Dependency consumer‘s are parts of the system that expects a concrete instance to implement something. Consider the following code listing (listing 1):

public class Consumer
{
    private DbAccessor _accessor;

    public Consumer(DbAccessor accessor)
    {
        _accessor = accessor;
    }

    public void DoSomething()
    {
       // -- snip --
    }
}

public class Tester
{
   public static void Main(string[] args)
   {
        DbAccessor accessor = new DbAccessor();
        Consumer consumer = new Consumer(accessor);
        consumer.DoSomething();
   }
}

If you notice the Main method, in order to create an instance of a Consumer, the method has to first create a DbAccessor instance. This is a Dependency. Thus, the method has to know about both the DbAccessor and Consumer. This is known as tight coupling. Because, if you change the name of this class to say DbType1Accessor and assuming this class is used a number of files, you have to change it in all of these files. A way better example is, say you want to replace DbAccessor with XmlAccessor you have to replace the same in all those numerous files. So with all of these facts, I am sure you understand why strong coupling is bad! Later in the post I will show how this strong coupling can be removed.

Now, let’s get to the most important component, the dependency injector. A Dependency Injector is a component that would help you to free the system from this coupling. And this post concentrates on adding a DI component for your project. I have always used “NInject” for implementing DI in my projects.

It’s extremely easy to setup and get started with NInject. To get started download, the NInject dll from here. For this post I was using NInject v2.0.0 (yeto to update to v2.2 :( ). Once you download the dll, add it to the project using “Add Reference”. Then create a class called NinjectControllerFactory and add the following code snippet to this file. This class is going to act as the principal class for implementing DI. If you notice this class inherits the DefaultControllerFactory, which is the default for the mvc framework.

A controller factory is a component of the mvc framework that helps in creating an instance of a controller as required by the mvc framework. In this case we are attempting to provide loose coupling to all the controllers. The controller factory, which is responsible for creating the controllers is overridden in this case so that when a controller is created now, the new controller factory would take the responsibility of creating an instance of the controoler and enabling the Ninject module to “inject” the dependency required by the controller.

public class NinjectControllerFactory : DefaultControllerFactory
{
	private IKernel kernel = new StandardKernel(new AplicationIocServices());

	protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
	{
	    if (controllerType == null)
        {
		    return null;
        }
	    return (IController)kernel.Get(controllerType);
	}

	private class AplicationIocServices : NinjectModule
	{
	    public override void Load()
	    {
		    Bind<IProductsRepository>().To<FakeProductsRepository>();
		    Bind<ICategoryRepository>().To<FakeCategoryRepository>();
	    }
	}
}

In the above code listing, line 3 creates an instance of StandardKernel which is required for the ninject module to work. The StandardKernel implements the IKernel interface which is used in the overriden GetControllerInstance method to return an instance of the required controller by passing the dependency needed by the controller. Note that, as this class is set to replace the DefaultControllerFactory, it’s very important to override the GetControllerInstance method to return an appropriate controller. If you notice line 3, an instance of the ApplicationIocServices instance is passed to the StandardKernel. This is a private class within the NinjectControllerFactory which is used to specify the bindings between an interface and a concrete instance. This class inherits from the NinjectModule class and overrides the Load method of the NinjectModule class.

Every line within the Load binds an interface to a concrete instance so that ninject can create a concrete type corresponding to the interface type passed when creating a controller instance. So when a controller requests a concrete type for IProductsRepository, ninject module returns an instance of FakeProductsRepository which could be used within the controller.

It’s not over if you just create this class. You have to inform the framework to use this instead of the DefaultControllerFactory using the Application_Start event in the Global.asax.cs file. This is done in line 8. ControllerBuilder class of mvc has the
Current property which is nothing but an instance of a ControllerBuilder for the current
application. The application’s controller factory is set to an instance of the NinjectControllerFactory we created earlier using the SetControllerFactory method of the ControllerBuilder instance. After this point, when a request is received for the HomeController (say), an instance of Home Controller will be created by our custom factory, by injecting in the required dependencies.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}

Following is an example of how this is put to use. Let us assume that the HomeController has an action called Products that displays a list of products that this web site offers for purchase. Without DI, I will have to create an instance of FakeProductsRepository and use it in the controller as shown below:

public class HomeController : Controller
{
	public ActionResult Products()
	{
        FakeProductsRepository repository = new FakeProductsRepository();
	    return View(repository.Products);
	}
}

The above snippet has a strong coupling of the FakeProductsRepository with the HomeController. This is not good because it reduces testability and also makes you modify this code whenever something changes with the FakeProductsRepository class. For example, in case you want the controllers to receive a concrete instance of ProductsRepository instead of an instance of FakeProductsRepository, the only change required is the change in line 9. Thus even if a number of controllers uses the IProductsRepository dependency, nothing would change, as the only change required was in the NinjectControllerFactory class.

public class NinjectControllerFactory : DefaultControllerFactory
{
	// -- snip --

	private class AplicationIocServices : NinjectModule
	{
	    public override void Load()
	    {
		    Bind<IProductsRepository>().To<ProductsRepository>();
		    Bind<ICategoryRepository>().To<FakeCategoryRepository>();
	    }
	}
}

Now that we have set up DI, we can modify the code as shown below. Note that now, the fact that the controller expects a concrete type bound to IProductsRepository could be identified by the parameter to the constructor of the HomeController, which is IProductsRepository. From this point onwards, ninject takes care of creating an instance of the Home controller including passing to it an instance of the FakeProductsRepository because IProductsRepository is bound to FakeProductsRepository.

public class HomeController : Controller
{
	private IProductsRepository productsRepository;

    public HomeController(IProductsRepository productsRepo)
    {
          productsRepository = productsRepo;
    }

	public ActionResult Products()
	{
	    return View(productsRepository.Products);
	}
}

Extending the Ninject Module:

Now, let me get to the most important part of this post. What if I need to create a concrete instance somewhere in a class where Ninject does not come in to the picture? Thats what the remainder of the post is going to deal with. For this part, I again take up one of my favorite area of C# – type constraints :) Let’s add a method called GetConcreteInstance to the NinjectControllerFactory class. This method will be used to get a concrete instance based on the interface type passed. This is a generic method which takes in an interface as a type parameter, finds a concrete instance, casts it to the type T and returns it to the caller.

So, with this method, you don’t have pass every required instance to a controller. This method uses the TryGet method of the StandardKernel to see if a concrete instance exists for the type passed. If not available this method throws an exception.

public class NinjectControllerFactory : DefaultControllerFactory
{
	// -- snip

	public T GetConcreteInstance<T>()
	{
	    object instance = kernel.TryGet<T>();
	    if (instance != null)
        {
		    return (T)instance;
        }
	    throw new InvalidOperationException(string.Format("Unable to create an instance of {0}", typeof(T).FullName));
	}

	// -- snip --
}

Let us look in to an example on how this is put in to use in a controller. Before that let us add a helper class to call this method, so that we abstract the part of getting a reference to the controller factory. Its given below:

public static class InstanceFactory
{
	public static T CreateConcreteInstance<T>()
	{
	    NinjectControllerFactory factory =(NinjectControllerFactory)ControllerBuilder.Current.GetControllerFactory();
	    return (T)factory.GetConcreteInstance<T>();
	}
}

Now, I have added the Categories method to the HomeController. Let’s assume apart from this method, no other method requires the ICategoryRepository. So instead of injecting the dependency to the constructor, within the action method, I use the new helper created earlier to get a concrete instance of ICategoryRepository by passing in ICategoryRepository as the type parameter.

public class HomeController : Controller
{
	private IProductsRepository productsRepository;

	// -- snip --

	public ActionResult Categories()
	{
	    ICategoryRepository categoryRepo = InstanceFactory.CreateConcreteInstance<ICategoryRepository>();
	    return View(categoryRepo.GetCategories());
	}

	// -- snip --
}

In the case of the CategoryController, DI is used as its more likely to be used throughout the controller. So I am just letting ninject take the responsibility for the CategoryController.

public class CategoryController : Controller
{
	private ICategoryRepository categoryRepository;

	public CategoryController(ICategoryRepository categoryRepo)
	{
	    categoryRepository = categoryRepo;
	}

	public ActionResult Index()
	{
	    return View(categoryRepository.GetCategories());
	}
}

Now that I have given you the full picture about DI, let me show how the code in listing 1 can be refactored to free it of the strong coupling.

public class Consumer
{
    private DbAccessor _accessor;

    public Consumer(DbAccessor accessor)
    {
        _accessor = InstanceFactory.CreateConcreteInstance<IDbAccessor>();
    }

    public void DoSomething()
    {
       // -- snip --
    }
}

public class Tester
{
   public static void Main(string[] args)
   {
        Consumer consumer = new Consumer();
        consumer.DoSomething();
   }
}

Given below is another high level implementation of how this new helper class/method could be used.

public class BaseClass
{
	private SomeBusinessFunction func;

	public BaseClass()
	{
	    func = new SomeBusinessFunction();
	}

	public void SomeMethod()
	{
	    func.DealWithSomething();
	}
	}

	public class DerivedClass : BaseClass
	{
	public DerivedClass()
	{

	}
}

public class SomeBusinessFunction
{
	private ICategoryRepository categoryRepo;

	public SomeBusinessFunction()
	{
	    categoryRepo = InstanceFactory.CreateConcreteInstance<ICategoryRepository>();
	}

	public List<Category> DealWithSomething()
	{
	    List<Category> categories = categoryRepo.GetCategories().ToList();

	    // -- do something --

	    return categories;
	}
}

Okay, I know that you have seen a lot code. You can download a sample project here. Hope you enjoyed this post. Happy coding!

Share

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>