Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject throws Activation Exception in a WebApi project with multiple assemblies

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.FromAssembliesInPath(AppDomain.CurrentDomain.RelativeSearchPath)
            .SelectAllIncludingAbstractClasses()
            .BindDefaultInterface()
            .Configure(config => config.InSingletonScope()));

        //kernel.Bind(x => 
        //    {
        //        x.FromAssembliesMatching("*")
        //        .SelectAllClasses()
        //        .BindDefaultInterface()
        //        .Configure(b => b.InTransientScope());
        //    });
        //kernel.Load()
        //kernel.Bind<ISecurityService>().To<SecurityServiceImplementation>();

        //kernel.Bind(x => x
        //    .FromAssembliesMatching("*")
        //    .SelectAllClasses()
        //    .BindDefaultInterface());
        //.Configure(b => b.InTransientScope()));
        //kernel.Load("*.dll");
    }        
}

exception is

[ActivationException: Error activating IHostBufferPolicySelector
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for IHostBufferPolicySelector

I have used various registrations (commented out) but none work. The break point in NinjectWebCommon.cs -> CreateKernel() method is hit and so does the break point in GetService(System.Type serviceType) method. AppDomain.CurrentDomain.RelativeSearchPath resolves to the bin directory of the app and it contains all the dlls including System.Web.Http.dll which contains the IHostBufferPolicySelector type.

How can I properly use the Ninject.Extensions.Conventions to setup the kernel for type resolution?

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

Umair Ishaq


People also ask

What are the common errors in ninject framework?

NinjectControllerFactory FileLoadException Error 2 LightInject Attempt to create a scoped instance without a current scope 0 Typecast error while binding in ninject framework 4 Simple injector: Registering a dynamically created delegate

Is ninject completely automatic?

7 NInject isn't quite completely automagical; you still need to tell it sometimes which implementations of your interfaces to create and inject (your "bindings" in NInject terms). Here is where they belong: /// <summary> /// Load your modules or register your services here!

How to add reference to required assemblies in WebAPI?

To add reference to required assemblies, you can simply install Microsoft.AspNet.WebApi.SelfHost via Nuget package installer. Once you have successfully installed WebApi.SelfHost Nuget, add the following namespaces which are required for the sample application.

How to host a WebAPI service using console application?

For hosting WebApi service, I will be using Console Application in Admin mode. Admin mode will be required since hosting mechanism will need to gain access to port which you have configured. For demo, we will be using JSON output.


1 Answers

From the hints in the answer by Remo and comment by Filip along with a significant amount of debugging time, I found out the use of this.resolver.Get(serviceType) instead of this.resolver.TryGet(serviceType) in GetService() implementation was the culprit in my situation.

I plan a detailed blog post about this but the short of it is that once we have the NinjectDependencyResolver plugged into MVC using the line: GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); and we don't define Framework level dependency bindings (e.g. IHostBufferPolicySelector etc.), an exception is raised by the Get() method for some framework level dependencies when they are not resolved through Ninject. Using TryGet() does not raise an exception and the framework falls back to default dependencies for unresolved (a.ka. null) dependencies like IHostBufferPolicySelector. So, the options are

  1. Use the TryGet() method to resolve dependencies.
  2. Wrap Get in Try/Catch and discard the exception.
like image 110
Umair Ishaq Avatar answered Oct 12 '22 17:10

Umair Ishaq