Ninject.MVC3 and Ninject.Web.MVC3 merged to one package

With Ninject.MVC3 2.2.0.3 available from NuGet Ninject.MVC3 and Ninject.Web.MVC3 got merged into one project providing the advantage or both.

A long time ago Microsoft released with Ninject.MVC3 a DependencyResolver for Ninject in the NuGet gallery. A lot of people started using Ninject.MVC3 because it was easily installable by NuGet. Unfortunately, this package does not provide the full power of the official implementation Ninject.Web.MVC3. Therefore, we decided to replace this package with an implementation using Ninject.Web.MVC3 while still using the WebActivator to integrate the bootstapper into the application.

What changed for Ninject.MVC3 users?

In order to make that the package correctly disposes the Ninject kernel on application shutdown the bootstrapper code has been moved into NinjectHttpApplicationModule.cs. This means that you have to specify your modules and bindings in this file now and not in AppStart_NinjectMVC3.cs anymore. Let’s have a look at this bootstrapper:

namespace MvcApplication2
{
    using System;
    using System.Web;

    using Ninject;
    using Ninject.Web.Mvc;

    public sealed class NinjectHttpApplicationModule : IHttpModule, IDisposable
    {
        #region Ninject Mvc3 extension bootstrapper (Do not touch this code)
        [...]
        #endregion

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            RegisterServices(kernel);
            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
        }
    }
}

As you see there are two methods now that can be changed to your needs. In CreateKernel the Ninject Kernel is created. The default implementation (create a standard kernel) fits for almost every application. In RegisterServices you can load your modules or define bindings. I have removed the bootstrapping section from the code above intentionaly. I’ll explain this code later in this blog post.

Which new features were added compared to Ninject.MVC3?

The new package adds two very important features:

  • The Ninject core and all scoped objects are properly disposed at shut down of the application.
  • Objects that are InRequestScope are released immediately after the request ends. This makes sure that applications that use a unit of work pattern and have a unit of work pattern do not run into out of memory exceptions.

Additionally, the package brings all the features that were added to Ninject.Web.Mvc. I blogged about these features several week ago.

What changed for Ninject.Web.MVC3 users?

If you get the binaries from github or the build server or if you build the sources yourself then absolutely nothing changed. But if you decide to thake advantage of Nuget and install Ninject.MVC3 from there you have to change one or two things in your application:

  1. The bootstrapper does not derive from HttpApplication anymore. Therefore you have to move your kernel configuration to NinjectHttpApplicationModule.cs as explained in chapter one.
  2. If you had some code in OnApplicationStarted or OnApplicationStopped you have to move this code to global.asax.cs. Just add two new methods void Application_Start() and Application_End()

What is the bootstrapper doing in detail?

The bootstrapping has been extracted to a module. As you see in the code below it ensures that initialization and disposing happens exactly once.  Both actions are forwarded to the bootstrapper that comes with Ninject.Web.Mvc. This newly introduced bootstrapper is exactly the same as NinjectHttpApplication except that it is not derived from HttpApplication anymore so that it can be used in other ways such as here in the bootstrapper module. In fact, the new NinjectHttpApplication implementation uses the bootstrapper internally itself now to get everything running.

/// <summary>
/// Initializes a module and prepares it to handle requests.
/// Do not change this method!
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
public void Init(HttpApplication context)
{
    lock (bootstrapper)
    {
        if (initialized)
        {
            return;
        }

        initialized = true;
        bootstrapper.Initialize(CreateKernel);
    }
}

/// <summary>
/// Disposes the <see cref="T:System.Web.HttpApplication"/> instance.
/// Do not change this method!
/// </summary>
public void Dispose()
{
    lock (bootstrapper)
    {
        if (kernelDisposed)
        {
            return;
        }

        kernelDisposed = true;
        bootstrapper.ShutDown();
    }
}

About the author

Remo Gloor

My name is Remo Gloor and I’m working as a software architect at bbv Software Services AG in Zug, Switzerland. My first expiriences with computers were a a little boy with basic programming on a C64, later Pascal an C on an Intel 8080. After finishing my study in software engineering I started working with C#.

Currently, I'm one of two Main Developers of the well known Ninject IoC containers. My other interests beside Ninject are TDD, Scrum and software architecture in general.

21 comments

  • I installed the new ninjectMVC3 using Nuget. I get this error:

    Server Error in ‘/’ Application.

    This method can only be called during the application’s pre-start initialization stage.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.InvalidOperationException: This method can only be called during the application’s pre-start initialization stage.

    Source Error:

    Line 11: public static void Start()
    Line 12: {
    Line 13: DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
    Line 14: DynamicModuleUtility.RegisterModule(typeof(NinjectHttpApplicationModule));
    Line 15: }

    Source File: K:\Alvaro\MedicalFiles\Locofiles\LocoFiles.WebUI\AppStart_NinjectMVC3.cs Line: 13

    Global.asax.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using FluentNHibernate.Automapping;
    using FluentNHibernate.Cfg;
    using FluentNHibernate.Cfg.Db;
    using NHibernate;
    using NHibernate.Cfg;
    using NHibernate.Context;
    using NHibernate.Tool.hbm2ddl;

    namespace LocoFiles.WebUI
    {
    // Note: For instructions on enabling IIS6 or IIS7 classic mode,
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {

    // NHibernate Fluent Configuration
    private static ISessionFactory BuildSessionFactory()
    {
    AutoPersistenceModel model = CreateMappings();
    string connString = “MedicalFilesConnectionString”;

    return Fluently.Configure()
    .Database(MsSqlConfiguration.MsSql2005
    .ConnectionString(c => c.FromConnectionStringWithKey(connString))).Mappings(m => m.AutoMappings.Add(CreateMappings))
    .ExposeConfiguration(BuildSchema)
    .BuildSessionFactory();
    }

    private static AutoPersistenceModel CreateMappings()
    {
    return AutoMap
    .Assembly(System.Reflection.Assembly.GetCallingAssembly())
    .Where(t => t.Namespace == “LocoFiles.Data”);

    }
    private static void BuildSchema(Configuration config)
    {
    new SchemaExport(config).Create(false, true);
    }

    //Begins Session Request
    private static ISessionFactory _sessionFactory;

    static void NHibenateSessionPerRequest()
    {
    _sessionFactory = BuildSessionFactory();
    }
    public void Init(HttpApplication context)
    {
    context.BeginRequest += BeginRequest;
    context.EndRequest += EndRequest;
    }

    public static ISession GetCurrentSession()
    {
    return _sessionFactory.GetCurrentSession();
    }

    public void Dispose() { }

    private static void BeginRequest(object sender, EventArgs e)
    {
    ISession session = _sessionFactory.OpenSession();
    session.BeginTransaction();
    CurrentSessionContext.Bind(session);
    }

    //Ends Session Reques

    private static void EndRequest(object sender, EventArgs e)
    {
    ISession session = CurrentSessionContext.Unbind(_sessionFactory);
    if (session == null) return;
    try
    {
    session.Transaction.Commit();
    }
    catch (Exception)
    {
    session.Transaction.Rollback();
    }
    finally
    {
    session.Close();
    session.Dispose();
    }
    }

    // Finish Fluent Configuration

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
    filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
    routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

    routes.MapRoute(
    “Default”, // Route name
    “{controller}/{action}/{id}”, // URL with parameters
    new { controller = “Home”, action = “Index”, id = UrlParameter.Optional } // Parameter defaults
    );

    }

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

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

    NinjectHttpApplicationModule.cs

    namespace LocoFiles.WebUI
    {
    using System;
    using System.Web;
    using Core.Models.Abstract;
    using Core.Models.Concrete;

    using Ninject;
    using Ninject.Web.Mvc;

    public sealed class NinjectHttpApplicationModule : IHttpModule, IDisposable
    {
    #region Ninject Mvc3 extension bootstrapper (Do not touch this code)
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();
    private static bool initialized;
    private static bool kernelDisposed;

    ///
    /// Initializes a module and prepares it to handle requests.
    /// Do not change this method!
    ///
    /// An that provides access to the methods, properties, and events common to all application objects within an ASP.NET application
    public void Init(HttpApplication context)
    {
    lock (bootstrapper)
    {
    if (initialized)
    {
    return;
    }

    initialized = true;
    bootstrapper.Initialize(CreateKernel);
    }
    }

    ///
    /// Disposes the instance.
    /// Do not change this method!
    ///
    public void Dispose()
    {
    lock (bootstrapper)
    {
    if (kernelDisposed)
    {
    return;
    }

    kernelDisposed = true;
    bootstrapper.ShutDown();
    }
    }
    #endregion

    ///
    /// Creates the kernel that will manage your application.
    ///
    /// The created kernel.
    private static IKernel CreateKernel()
    {
    var kernel = new StandardKernel();
    RegisterServices(kernel);
    return kernel;
    }

    ///
    /// Load your modules or register your services here!
    ///
    /// The kernel.
    private static void RegisterServices(IKernel kernel)
    {
    kernel.Bind().To();
    }
    }
    }

  • Hy
    Could you please ask these questions either on StackOverflow, Github or the ninject google group? This makes it a lot easier for other people to search for answers. You could then add a link to the question in the comment section here.

    Daniel

  • So what is this newly merged package called on nuget? Also, will it remove the old references when installed? Thanks.

  • The package name is still Ninject.MVC3. It will remove the old references but it will keep any source code file that has been manually changed.

  • Hi Remo,

    I don’t understand, there’s a new file now called NinjectMVC3.cs. I thought there wasn’t any more startup files and that the application simply needed to extend NinjectHttpApplication.

    What is the name of the repo on github. I’m having some problems after the upgrade 🙂

  • I’m glad to see Ninject has been updated to incorporate the newer features of MVC3 (I wasn’t even aware there was a Ninject.web.Mvc3 package).

    In this new setup, howevr, I’m still unclear how explicitly to get an instance of something. For example, in my application startup (global.asax), I want an instance of an ILog, but as far as I can tell, the kernel isn’t exposed. How would I do this??

  • Hi, would you please update the package and rename/fix the AppStart folder in the current Ninject package to App_Start. The convention all the other packages and David Ebbo uses is App_Start. Thanks!

  • Hi Remo,
    I’m new to MVC and am learning on 3.0. I normally work in VB.net

    I’v never worked with add ons in my websites in the past but MVC opens so many new possibilities so I’m beginning to explore new areas.

    Will this work with the application being written in VB?

    Thanks in advance

  • Of course. But be aware, the NuGet package generates a C# file. You have to translate this one to VB.

  • What if I have an exception in RegisterServices (which is called by a PreApplicationStartMethod) and I want to log it? I need to Server.MapPath the file path but HttpContext.Current is null..

    Any ideas?

    Thanks.

  • God what a mess. I’m a Ninject newbie but can’t find a simple canonical example of how to get it working with MVC3, and the ninject.mvc3 nuget package seems to make things worse.

    Fuck this I’m going home.

  • Which is correct, this blog post or “Setting up an MVC3 application” on GitHub (https://github.com/ninject/ninject.web.mvc/wiki/Setting-up-an-MVC3-application)? When you say, “This means that you have to specify your modules and bindings in this file [NinjectHttpApplicationModule.cs] now and not in AppStart_NinjectMVC3.cs anymore.” Is that still true? And if it is true, why doesn’t the nuget package install a NinjectHttpApplicationModule.cs file? This is very confusing.

  • Hi 🙂

    I’m using the Ninject MVC3 extension and I would like to inject an accounRepository into à Membership provider class. How can I do that with the new NinjectMVC3 class? I made the binding of IAccountRepository to AccountRepository in the method RegisterServices(kernel) but when I use my membershipProvider class, the accountRepository instance is null.

  • Gotta say, “Awesome work on the MVC3 Extension”. I am new to Ninject but have been building smaller MVC apps for a while now, and ignorantly thinking, “I don’t need all that other complication to my apps”. Well i finally broke down tonight and gave Ninject a shot with your Plugin. After compiling, I ran the test app in the browser, just waiting for an error screen…… Needless to say I got the home page of the test app and everything I requested was working just fine to my amazement. I quickly realized that my apps were actually more complicated without it.

    Thank You for making my life a lot easier.

By Remo Gloor

Recent Posts