Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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??

like image 471
Umair Ishaq Avatar asked Nov 14 '12 16:11

Umair Ishaq


2 Answers

For now use this NinjectDependencyResolver and this NinjectDependencyScope implementations

like image 118
Ian Davis Avatar answered Sep 22 '22 17:09

Ian Davis


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/

like image 28
Filip W Avatar answered Sep 23 '22 17:09

Filip W