Search code examples
asp.net-mvcninjectninject-2

Ninject 2 + ASP.NET MVC 2 Binding Types from External Assemblies


I'M just trying to get started with Ninject 2 and ASP.NET MVC 2. I have followed this tutorial http://www.craftyfella.com/2010/02/creating-aspnet-mvc-2-controller.html to create a Controller Factory with Ninject and to bind a first abstract to a concrete implementation. Now I want to load a repository type from another assembly (where my concrete SQL Repositories are located) and I just cant get it to work. Here's my code:

Global.asax.cs

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

        RegisterRoutes(RouteTable.Routes);


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

Controller Factory:

public class Kernelhelper
{
    public static IKernel GetTheKernel()
    {
        IKernel kernel = new StandardKernel();
        kernel.Load(System.Reflection.Assembly.Load("MyAssembly"));
        return kernel;
    }
}

public class MyControllerFactory : DefaultControllerFactory
{
    private IKernel kernel = Kernelhelper.GetTheKernel();


    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {

        return controllerType == null ? null : (IController)kernel.Get(controllerType);
    }
}

In "MyAssembly" there is a Module:

    public class ExampleConfigModule : NinjectModule
{
    public override void Load()
    {
        Bind<Domain.CommunityUserRepository>().To<SQLCommunityUserRepository>();
    }

}

Now when I just slap in a MockRepository object in my entry point it works just fine, the controller, which needs the repository, works fine. The kernel.Load(System.Reflection.Assembly.Load("MyAssembly")); also does its job and registers the module but as soon as I call on the controller which needs the repository I get an ActivationException from Ninject:

No matching bindings are available, and the type is not self-bindable. Activation path: 2) Injection of dependency CommunityUserRepository into parameter _rep of constructor of type AccountController 1) Request for AccountController

Can anyone give me a best practice example for binding types from external assemblies (which really is an important aspect of Dependency Injection)? Thank you!


Solution

  • Ok, I did some refactoring and now I got it running. I'll post the code of my Global.asax since that's where everything happens. I'm using the latest Ninject 2 Build with the latest Ninject.Web.Mvc Build for MVC 2.

     public class MvcApplication : NinjectHttpApplication
    {
        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 = "" }  // Parameter defaults
            );
    
        }
    
        protected override void OnApplicationStarted()
        {
            AreaRegistration.RegisterAllAreas();
    
            RegisterRoutes(RouteTable.Routes);
    
            RegisterAllControllersIn(System.Reflection.Assembly.GetExecutingAssembly());
        }
    
    
        protected override Ninject.IKernel CreateKernel()
        {
    
            var kernel = new StandardKernel();
            kernel.Load(new ExampleConfigModule());
            return kernel;
        }
    }
    
    public class ExampleConfigModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            string connectionString =
                ConfigurationManager.ConnectionStrings
                ["ConnectionString1"].ConnectionString;
            string communityUserRepTypeName =
               ConfigurationManager.AppSettings
               ["CommunityUserRepositoryType"];
            var communityUserRepositoryType =
                Type.GetType(communityUserRepTypeName, true);
            Bind<Domain.CommunityUserRepository>().To(communityUserRepositoryType).WithConstructorArgument("conString",connectionString);
        }
    
    }
    

    As you can see I got rid of my ControllerFactory, inherited from NinjectHttpApplication and load & bind the external assemblies' type in the Module. Now there might be a better way without specifiyng the type as a string in the config file, maybe you could declare the Module in the external assembly and let Ninject auto-load it from there but I still would need to pass the connection string down to the constructor of the concrete implementation. Maybe someone got an idea for this but for now this works fine.