Search code examples
asp.net-mvcninjectninject.web.mvc

Ninject can't resolve a dependency for a controller, but have no problems with services


1) I'm creating an ASP.NET MVC app and want to make use of DbContext right in the app itself, along with some simple services that are slightly resembling a layered architecture.

So, I'm registering the dependency in the standard NinjectWebCommon bootstrapper:

kernel
    .Bind<IDbContextFactory<WebDbContext>>()
    .To<WebDbContextFactory>()
    .InRequestScope()
    .WithPropertyValue(nameof(WebDbContextFactory.ConnectionString), ConfigurationManager.ConnectionStrings["WebDb"].ConnectionString);

It works as expected, if it initializes some MyService class with the IDbContextFactory<WebDbContext> dependency in its constructor. In debug I see an initialized instance.

However, if MyController has a constructor with the same dependency, Ninject throws an exception that the dependency is not registered.

Hm, why?

2) And the Kernel initialization is following:

var kernel = new StandardKernel();
    try
    {
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        ControllerBuilder.Current.SetControllerFactory(new ControllerFactory(kernel));
        DependencyResolver.SetResolver(new AppDependencyResolver(kernel));

        return kernel;
    }
...

RegisterServices() method contains that dependency registration, so I assume the kernel already has it when passed to the controller factory, for example.

3) And one more thing. The DB context factory isn't the only dependency that MyController is pulling when initializing. There are a couple like:

kernel.Bind<MyService>().ToSelf().InRequestScope();

So if I workaround the IDbContextFactory dependency in MyController, it has no problems with the other dependencies.

4) And another thing. The possible workaround is to change the DB context factory registration to this:

kernel
    .Bind<IDbContextFactory<WebDbContext>, WebDbContextFactory>()
    .To<WebDbContextFactory>()
    .InRequestScope()
    .WithPropertyValue(nameof(WebDbContextFactory.ConnectionString), ConfigurationManager.ConnectionStrings["WebDb"].ConnectionString);

Notice the second type in Bind() method. With corresponding changes in the MyController constructor, of course. But WebDbContextFactory is in fact WebDbContextFactory : IDbContextFactory<WebDbContext>. The only way it's different is, I think, that it is in my local assembly (another referenced project, though) and IDbContextFactory<> is an external one. Huh?


Solution

  • MVC has 2 extension points for registering MVC to resolve services through dependency injection:

    • ControllerBuilder.Current.SetControllerFactory
    • DependencyResolver.SetResolver

    You should be using one or the other not both to resolve services for your controllers.

    Whatever your exact issue is, it is sure to be inside one or both of those classes, but you haven't posted the code so nobody can tell you exactly what is going wrong.