1
votes

In our MVC application we predominantly use Ninject to inject dependencies into controllers. As such, our default lifetime scope is InRequestScope(). We have now added an IHttpModule that uses common dependencies as the controllers (i.e., UserService). The problem is that HttpModules can be pooled by ASP.NET and IIS and reused over multiple requests. Because the injected dependencies are set to InRequestScope, subsequent requests will often get an ObjectDisposedException when referencing the injected dependencies inside the HttpModule. How can I specify InRequestScope() for the UserService when injecting into a controller and InScope() when injecting into an HttpModule.

Here is a simplified version of our registration:

public static class NinjectWebCommon
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    public static void Start(){
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    public static void Stop(){
        bootstrapper.ShutDown();
    }

    private static IKernel CreateKernel(){
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
        kernel.Bind<IHttpModule>().To<CustomModule>(); // needs a UserService
        kernel.Bind<IUserService>().To<UserService>().InRequestScope(); // injected into controllers and the CustomModule
        DependencyResolver.SetResolver(new Services.NinjectDependencyResolver(kernel));
        return kernel;
    }
}
1
this may be partially interesting to you: stackoverflow.com/questions/25167439/…BatteryBackupUnit

1 Answers

2
votes

Check out .When() on the binding syntax. You can use it to specify a specific scope for a service under specific circumstances. here's an example:

class Program
{
    static void Main(string[] args)
    {
        var kernel = new StandardKernel();

        var scope1 = new object();
        var scope2 = new object();

        kernel.Bind<IWidget>().To<WidgetA>().InScope(c => scope1);
        kernel.Bind<IWidget>().To<WidgetA>().WhenInjectedInto<WidgetController>().InScope(c => scope2);

        var service = kernel.Get<GeneralWidgetService>();
        service.Print();

        service = kernel.Get<GeneralWidgetService>();
        service.Print();

        var controller = kernel.Get<WidgetController>();
        controller.Print();

        controller = kernel.Get<WidgetController>();
        controller.Print();

        // when scope2 changes, WidgetController gets a new widget, while WidgetService continues getting the existing widget
        scope2 = new object();

        service = kernel.Get<GeneralWidgetService>();
        service.Print();

        controller = kernel.Get<WidgetController>();
        controller.Print();
    }
}

public class WidgetController
{
    private readonly IWidget _widget;

    public WidgetController(IWidget widget)
    {
        _widget = widget;
    }

    public void Print()
    {
        Console.WriteLine("WidgetController ID: " + _widget.ID);
    }

}

public class GeneralWidgetService
{
    private readonly IWidget _widget;

    public GeneralWidgetService(IWidget widget)
    {
        _widget = widget;
    }

    public void Print()
    {
        Console.WriteLine("GeneralWidgetService ID: " + _widget.ID);
    }

}


public interface IWidget
{
    string ID { get; }
    string Name { get; }
}

public class WidgetA : IWidget
{
    private readonly string _id = Guid.NewGuid().ToString();

    public string ID { get { return _id; } }
    public string Name { get { return "AAAAAAAAAAAAAAAAA"; } }
}

Output:

GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 519a2930-5b71-4cbb-b84e-a1d712ec5398