Search code examples
c#dependency-injectionninjectninject.web.mvcninject-extensions

How to bind using Ninject Conventions Extension?


I like to bind bellow code with Ninject auto binding. Is it possible to use both mannual & auto binding within a single project? Let;s take bellow manual binding, I want to achieve with auto binding. Please tell me how to achieve this.

  1. kernel.Bind<TestContext>().ToSelf().InRequestScope();

  2. kernel.Bind<IUnitOfWork<TestContext>>().To<UnitOfWork<TestContext>>();

Bellow all interface inherited from base Interface : IRepository< Model >

3 . kernel.Bind<IUserRepository>().To<UserRepository>();

4 . kernel.Bind<IAccountRepository>().To<AccountRepository>();

5 . kernel.Bind<IMessageRepository>().To<MessageRepository>().WithConstructorArgument("apikey", AppSettingsManager.GetSmsApiKey)

Additional

Do I need to write .Exclude<MessageRepository>() for multiple classes If I required to do it such as

.Exclude<ARepository>() .Exclude<BRepository>() .Exclude<CRepository>() ?

and for 1 & 2 is required separate manual binding ? or 1 can be done using BindToSelf()' and.Configure(b => b.InRequestScope())` ?


Solution

  • Yes, it is possible to use convention binding and single binding in the same project, even in the same module.

    IBindingRoot.Bind(x => x
        .FromThisAssembly()
        .IncludingNonePublicTypes()
        .SelectAllClasses()
        .InheritedFrom(typeof(IRepository<>))
        .BindDefaultInterface()
        .Configure(y => y.InRequestScope()));
    

    However you won't be able to pass a constructor argument to a specific class. So i suggest replacing the constructor argument with an interface which wraps the access to the configuration (that's a nice design anyway).

    Alternatively you can also do this:

    IBindingRoot.Bind(x => x
        .FromThisAssembly()
        .IncludingNonePublicTypes()
        .SelectAllClasses()
        .InheritedFrom(typeof(IRepository<>))
        .Exclude<MessageRepository>()
        .BindDefaultInterface()
        .Configure(y => y.InRequestScope()));
    
    IBindingRoot.Bind<IMessageRepository>().To<MessageRepository>)
        .WithConstructorArgument("apikey", AppSettingsManager.GetSmsApiKey)
        .InRequestScope();
    

    --> You can do one .Exclude<TRepository>() for every repository, where the convention binding is not sufficient. For every exlucded binding you will have to specifiy one yourself. As above: conditional binding for all classes implementing IRepository<> except class MessageRepository, which gets its own binding.

    Also have a look at this: https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind

    Addendum: Note that you can specify multiple conventional bindings, for example:

    IBindingRoot.Bind(x => x
        .FromThisAssembly()
        .SelectAllClasses()
        .InheritedFrom(typeof(IFoo))
        .BindDefaultInterface()
        .Configure(y => y.InRequestScope()));
    
    
    IBindingRoot.Bind(x => x
        .FromThisAssembly()
        .SelectAllClasses()
        .InheritedFrom(typeof(IBar))
        .BindToSelf()
        .Configure(y => y.InRequestScope()));
    

    Is totally ok.