Ninject 3 - Does BeginBlock() override InRequestScope in asp.net WebAPI?
Asked Answered
A

2

5

My asp.net WebApi project comprises of multiple assemblies for Services, Core and Data Access. In an attempt to use Ninject as my DI container in the project, I added Ninject.Web.Common package from NuGet. Then, I Implemented IDependencyResolver as:

public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
    readonly IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel) : base(kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(this.kernel.BeginBlock());
    }
}

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

    public object GetService(System.Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        var resolved = this.resolver.Get(serviceType);
        return resolved;
    }

    public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return this.resolver.GetAll(serviceType);
    }

    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();

        resolver = null;
    }
}

Here is my Ninject.Web.Common.cs.

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

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
        RegisterServices(kernel);

        GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind(x =>
            x.FromAssembliesMatching("WebApiTest.DataAccess.dll")
            .SelectAllClasses()
            .BindAllInterfaces()
            .Configure(config => config.InRequestScope()));

        kernel.Bind(x =>
            x.FromAssembliesMatching("WebApiTest.*.dll")
            .SelectAllClasses()
            .BindAllInterfaces()
            .Configure(config => config.InTransientScope()));
    }        
}

My question is about the code in NinjectDependencyResolver -> BeginScope() method: return new NinjectDependencyScope(this.kernel.BeginBlock());

I would like to have my repositories (implemented in WebApiTest.DataAccess.dll) be request scoped. I came across this post from Nate Kohari. I realize the post is old but the description about Activation Blocks makes me wonder if that is still the current implementation.

There’s one final way of handling scope in Ninject2, through activation blocks. Blocks are >a way to override the scope that was declared on a binding, and instead associate the >activated instances with the block itself. ...

So,what is the actual scope of my repositories?

Also, sounds to me that the use of BeginBlock() is optional but when i remove it, the first call to the Controller succeeds but any subsequent calls throw exception:

Ninject component ICache No such component has been registered in the kernel's component container

WHY??

Albano answered 14/11, 2012 at 16:43 Comment(0)
H
13

For now use this NinjectDependencyResolver and this NinjectDependencyScope implementations

Highclass answered 15/11, 2012 at 15:48 Comment(6)
I am using those. What do you mean exactly?Albano
You are not. Look at the implementations. We created them out of this thread: github.com/ninject/Ninject.Web.WebApi/pull/1Highclass
Ian, thanks. Didn't immediately discover the links in your answer. Is my understanding correct that with my implementation, the BeginBlock() overwrites the scope to Singleton?Albano
Creating a block scopes all items resolved from that block to the block object. If you dispose of the block, the attached instances are no longer bound. You can consider them to be singletons when resolved from a block.Highclass
Thanks, confirms my understanding.Albano
the answer's link is broken.Scissure
R
1

In order to use dependencies in request scope do not set them up using Ninject's InRequestScope() but pull them off the Request using GetDependencyScope()

I put together a blog post about that http://www.strathweb.com/2012/11/asp-net-web-api-and-dependencies-in-request-scope/

Radom answered 15/11, 2012 at 16:7 Comment(1)
Filip, thanks for the blog post. Really nice. However, the UoW is abstracted away from the controller and I don't want to carry the context all the way down. Any thoughts?Albano

© 2022 - 2024 — McMap. All rights reserved.