.NET Dependency Injection

3 Feb 2011

Introduction

Recently I’ve been started a new MVC 3 app which is to have lot’s of components so I decided to go down the Dependency Injection route. This, for those who are hazy, is a OO design pattern for decoupling components.

I did some research (read, Google) and thought I’d go with StructureMap, but due to my limitations at work I must use VB.NET and I couldn’t find many examples, even converting from C# using my brain and auto tools, so I had some issues getting it working exactly how I wanted it to. Therefore I decided to try Ninject. The differences aren’t much and both do the DI I wanted to do but Ninject I got working in less than 10 minutes.

The app I’m working on is a MVC3 e-Commerce app with several distinct areas, such as categories, products, content pages, etc. Using the repository pattern I have repositories for returning the models but the actual concrete implementation of this can be done however I want and Ninject takes care of returning the correct concrete implementation. This means the application can be built with simple “fake/dummy” implementations and the whole site can be designed without ever needing to do the actual behind the scene complexities.

I will also use Ninject for returning concrete implementations of logging functionality, accounts, baskets, etc.

Simple "How I Did It"

The thing that frustrated me was trying to find a good example that was simple and easy to reimplement for myself so hopefully this will help for those with similar software architecture:

  1. Download Ninject - http://ninject.org/

  2. Add a reference to the MVC Web Project for Ninject.dll

  3. Create a class inheriting from the default MVC controller factory.

    Imports System.Configuration
    Imports System.Web.Mvc
    Imports System.Web.Routing
    Imports Ninject
    Imports Ninject.Modules
    Imports makit.Core.Repositories
    
    Namespace Infrastructure
    
    	Public Class DIControllerFactory
    		Inherits DefaultControllerFactory
    
    		Private kernel As IKernel = New StandardKernel(New DIServices())
    
    		' MVC calls this to get the controller for each request
    		Protected Overrides Function GetControllerInstance(ByVal context As RequestContext, 
                                                                         ByVal controllerType As Type) As IController
    			If controllerType Is Nothing Then
    				Return Nothing
    			End If
    			Return DirectCast(kernel.[Get](controllerType), IController)
    		End Function
    
    		' Configures how abstract service types are mapped to concrete implementations
    		Private Class DIServices
    			Inherits NinjectModule
    
    			Public Overrides Sub Load()
    
    				Bind(Of Abstract.IProductRepository)().[To](Of Concrete.XMLProductRepository)()
    				Bind(Of Abstract.ICategoryRepository)().[To](Of Concrete.XMLCategoryRepository)()
    
    			End Sub
    
    		End Class
    
    	End Class
    
    End Namespace
    
  4. As can be seen in the example above I am specifying to use the concrete XML repository class where ever the repository interfaces are referenced. An example of this use is:
    Namespace Controllers
        Public Class ProductController
            Inherits System.Web.Mvc.Controller
    
            Private m_ProductsRespository As IProductRepository
    
            Public Sub New(ByVal prodRepos As IProductRepository)
                m_ProductsRespository = prodRepos
            End Sub
    
            Function Index() As ActionResult
                Return View()
            End Function
    
        End Class
    End Namespace
    
  5. Now we need to add in the code that will get the dependency to fire, this is done with a line in the Application_Start function (in Global.asax):
    Sub Application_Start()
    
            AreaRegistration.RegisterAllAreas()
            RegisterGlobalFilters(GlobalFilters.Filters)
            RegisterRoutes(RouteTable.Routes)
    
            ' The Important line below
            ControllerBuilder.Current.SetControllerFactory(New DIControllerFactory())
    
    End Sub
    
  6. This now means when the application starts in IIS Ninject will sort out the dependencies based on the code in DIServices, such as in the case of the ProductController example above. The main example used here is so that the products & categories for an eCommerce site can come from any type of repository - XML, SQL Server, MYSQL, Magic, etc.
Hopefully this will help you setup dependency injection in your MVC app. If you wish to see how I’ve got the repositories setup then here are my base class/intertface setups:
Namespace Repositories.Abstract

    Public Interface IProductRepository

        Function getProduct(ByVal id As String) As Models.Product

    End Interface

End Namespace
Imports System.IO

Namespace Repositories.Concrete.XML

    Public Class XMLProductRepository
        Implements Abstract.IProductRepository

        Public Function getProduct(ByVal id As String) As Models.Product Implements Abstract.IProductRepository.getProduct

            Dim prodMdl As Models.Product = Nothing

            Dim x As New System.Xml.Serialization.XmlSerializer(GetType(Models.Product))
            Dim fileName As String = Path.Combine(System.Web.HttpContext.Current.Server.MapPath("~/App_Data/Products/"), id & ".xml")

            If File.Exists(fileName) Then
                Using oStmR As New StreamReader(fileName)
                    prodMdl = CType(x.Deserialize(oStmR), Models.Product)
                    oStmR.Close()
                End Using
            End If

            Return prodMdl

        End Function

    End Class

End Namespace
asp.net   mvc  
Posted by makit
Last revised 18 May 2012 11:04 AM

makit / Martyn Kilbryde

Professional software developer, ponderer and eccentric.

flickr

Github

LinkedIn

Stack Overflow

Twitter