Wednesday, September 8, 2010

Using Ninject as IOC container in ASP.NET MVC

Yesterday I tried to use Fluent NHibernate and Ninject in ASP.NET MVC project the first time to prepare for my personal project. After doing some reading and surfing around the Internet, I end up with a solution and it just works. And here is how I did.

First, I start with a Ninject module which is used to register dependencies
public class CustomNinjectModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToMethod(c => GetSessionFactory()).InSingletonScope();
Bind<ISession>().ToMethod(c => c.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
}

public static ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("connectionString")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<ProductMap>())
.BuildSessionFactory();
}
}
In this custom module, I used FluentNHibernate to create instance of ISessionFactory. We only need one instance of ISessonFactory for the whole project so I keep in singleton scope. In opposite way, we need to create a ISession instance per web request so I set it in request scope.

Then I create a bootstrapper which is used to create the kernel with above module
public static class NinjectBootstrapper
{
public static IKernel Kernel { get; private set; }

public static void Initialize()
{
Kernel = new StandardKernel(new CustomNinjectModule());
}
}
Because I uses Ninject as IOC, in a consistent way it's better if I also use it to create instances of controllers. So I create a custom controller factory

public class NinjectControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;

public NinjectControllerFactory(IKernel kernel)
{
_kernel = kernel;
}

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
return _kernel.Get(controllerType) as IController;
}
catch (Exception)
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
}
The last thing I need to do is updating Application_Start in my MvcApplication to initialize dependecies and use the custom factory

protected void Application_Start()
{
NinjectBootstrapper.Initialize();
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(NinjectBootstrapper.Kernel));

AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);
}
Lesson learn:
  • How to use Ninject to inject dependencies in ASP.NET MVC
  • Understand about some Ninject scopes and how to create instance in the scopes (transient, singleton and request)
  • How to retrieve dependencies from current context (IContext.Kernel.Get<ISessionFactory>())
  • And object lifecycle management in Ninject (as you can see, I don't need to release instances of ISession after each request because Nijnect does it for me. For more details, you can find here)

1 comment: