Convention Based Dependency Injection with Ninject 3.0.0
Asked Answered
T

1

9

I have two projects in my solution... a domain project and MVC3 web project (e.g. MyApp.Domain and MyApp.Web). Previously, when using Ninject.Extensions.Conventions ver. 2, I was able to use the following statement in the NinjectMVC3.cs file, and required dependencies throughout my solution (both web and domain) were injected properly (e.g. IFoo automatically bound to Foo).

kernel.Scan(x =>
{
  x.FromAssembliesMatching("*");
  x.BindWith<DefaultBindingGenerator>();
});

I have just upgraded to Ninject 3.0.0 (pre-release) and Ninject.Extensions.Conventions 3.0.0 (another pre-release) but the syntax for convention based binding has changed. I have figured out that I can use the following statement with the new version, but it only automatically binds the convention based interfaces in MyApp.Web and not in MyApp.Domain. The previous version bound interfaces throughout the application.

kernel.Bind(x => x
    .FromThisAssembly()
    .SelectAllClasses()
    .BindToAllInterfaces());

Any clue how I can configure convention based binding with the new Ninject version? I assume it has to do with specifying the assembly, but I have tried using FromAssembliesMatching("*") and it fails for everything then.

-- Edit to show my exisiting code in RegisterServices method: --

private static void RegisterServices(IKernel kernel)
{
  // This code used to work with v.2 of Ninject.Extensions.Conventions
  // kernel.Scan(x =>
  // {
  //   x.FromAssembliesMatching("*");
  //   x.BindWith<DefaultBindingGenerator>();
  // });

  // This is the new v3 code that automatically injects dependencies but only for interfaces in MyApp.Web, not MyApp.Domain
  kernel.Bind(x => x.FromThisAssembly().SelectAllClasses().BindToAllInterfaces()); 

  // I tried this code, but it throws "Error activating IDependencyResolver" at "bootstrapper.Initialize(CreateKernel)"
  // kernel.Bind(x => x.FromAssembliesInPath(AppDomain.CurrentDomain.RelativeSearchPath).SelectAllClasses().BindToAllInterfaces());

  // These are dependencies in MyApp.Web that ARE being bound properly by the current configuration
  // kernel.Bind<IMemberQueries>().To<MemberQueries>();
  // kernel.Bind<IGrantApplicationQueries>().To<GrantApplicationQueries>();
  // kernel.Bind<IMailController>().To<MailController>();

  // These are dependencies in MyApp.Domain that ARE NOT being bound properly by the current configuration, so I have to declare them manually 
  // They used to be injected automatically with version 2 of the conventions extention
  kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
  kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
  kernel.Bind<IMemberServices>().To<MemberServices>();
  kernel.Bind<IGrantApplicationServices>().To<GrantApplicationServices>();

  // These are dependencies that SHOULD NOT be bound by convention as they require a different scope or have unique naming
  kernel.Bind(typeof(EfDbContext)).ToSelf().InRequestScope();
  kernel.Bind<IConfigurationProvider>().To<WebConfigConfigurationProvider>().InSingletonScope();
  kernel.Bind<IAuthorizationProvider>().To<MyAppAuthorizationProvider>();
  kernel.Bind<IPrincipal>().ToMethod(ctx => HttpContext.Current.User).InRequestScope();
  kernel.Bind<IGrantApplicationDocumentServices>().To<MySpecialNameGrantAplicationDocumentServices>().InRequestScope();
}
Toastmaster answered 22/3, 2012 at 14:59 Comment(7)
You looked at the wiki. If not, can you give some idea of which bit is not making sense to you?Dentition
Ruben, I have looked at the wiki. What's not making sense is that with the old code x.FromAssembliesMatching("*") worked and bound all my interfaces in MyApp.Web and MyApp.Domain. However, with the new 3.0.0, that syntax doesn't work. The closest I've found is x.FromThisAssembly() but that only binds the interfaces within MyApp.Web (since that's where the injection takes place). It doesn't automatically bind the interfaces in MyApp.Domain.Toastmaster
Looking at the code, you could always get the assemblies yourself (either via AppDomain's assemblies list or some opther mechanism) and supply the list explicitly. Other than that I recommend jhust reading the source - its just not big. github.com/ninject/ninject.extensions.conventions/blob/master/…Dentition
Looking at the algorithm, it uses a combination of AppDomain relativesearchpoath and basepath. As a quick way of ruling out any issues there, you could do .FromAssembliesInPath( AppDomain.CurrentDomain.RelativeSearchPath) which will yield <absolutepath to your wwwroot\app\bin>Dentition
Thanks for all you help Ruben. Unfortunately, I tried that, but now I get an exception stating "Error activating IDependencyResolver More than one matching bindings are available. Activation path: 1) Request for IDependencyResolver. Suggestions: 1) Ensure that you have defined a binding for IDependencyResolver only once.". I wish the new version just worked like version 2.Toastmaster
I also edited my original post to show my current codeToastmaster
That exception is more likely tpo have something to do with you duplicating your Ninject/MVC 3integration - do you have both derivation from / initialiazation of Ninject in your Global.cs/HttpApplication class and the Ninject.MVC3 NuGet package-generated Application_Start stuff? If so, remove one of them. Unfortunately I have to stop guessing now though as messing with this is not something I've done a lot of - I do know that every permutation of this particular thing (general bootstrapping in MVC environments) hass been covered here on the ninject tag...Dentition
L
17

The equivalent is:

kernel.Bind(x => x
    .FromAssembliesMatching("*")
    .SelectAllClasses()
    .BindDefaultInterface());
Lochia answered 26/3, 2012 at 7:26 Comment(1)
Thanks Remo. I guess I'm a moron. That was one of the very first things I tried, but I used the BindToDefaultInterfaces (plural) method which failed. When I changed it to the singular method, it worked. Sorry for all the posts, but I do greatly appreciate your help. Great work on all your projects!Toastmaster

© 2022 - 2024 — McMap. All rights reserved.