Search code examples
c#dependency-injectionninject

Defining Ninject's binding without scope to keep the code DRY


I have a Web project and a Windows Service project in my solution. I have created 2 different binding modules for these 2 projects, but as you can see it has a lot of duplicate code... the only difference is that I am using InRequestScope() for the Web project and InTransientScope() for Windows Service project.

Is it possible combine the bindings, and add the scope depending on the project/entry point?

public class WebModule : NinjectModule
{
    public override void Load()
    {
        Bind<ApplicationDbContext>().ToSelf().InRequestScope();
        Bind<IMyRepository>().To<MyRepository>().InRequestScope();
        // more types ... InRequetScope();
    }
}

public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<ApplicationDbContext>().ToSelf().InTransientScope();
        Bind<IMyRepository>().To<MyRepository>().InTransientScope();
        // more types ... InTransientScope();
    }
}

Solution

  • Update:

    As explained by ninject team, we can use InRequestScope() in both scenarios... since there is no concept of Request in a Windows Service project, ninject would use the default scope, which is InTransientScope() in the service project.


    Original Answer

    The best solution that I have come up with is to create an extension method:

    public static class NinjectExtensions
    {
        public static IBindingNamedWithOrOnSyntax<T> GetScopeByName<T>(this IBindingInSyntax<T> syntax, string scope)
        {
            if (scope.Equals("request", StringComparison.InvariantCultureIgnoreCase))
            {
                return syntax.InRequestScope();
            }
            else if (scope.Equals("thread", StringComparison.InvariantCultureIgnoreCase))
            {
                return syntax.InThreadScope();
            }
            else if (scope.Equals("singleton", StringComparison.InvariantCultureIgnoreCase))
            {
                return syntax.InSingletonScope();
            }
            
            return syntax.InTransientScope();
        }
    }
    

    And set the scope dynamically.

    public class MyModule : NinjectModule
    {
        private string _scope = "transient";
    
        public MyModule()
        {
            if (Convert.ToBoolean(ConfigurationManager.AppSettings["IsWebProject"]))
            {
                _scope = "request";
            }
        }
    
        public override void Load()
        {
            Bind<ApplicationDbContext>().ToSelf().GetScopeByName(_scope);
            Bind<IMyRepository>().To<MyRepository>().GetScopeByName(_scope);
            // more types ... InRequetScope();
        }
    }
    

    Note: I am not sure if there is a better solution... this is just the cleanest approach that has come to my mind.