I am using Ninject in a C# 4.5 project as the IoC container. I am trying to use Ninject to inject into an abstract factory pattern which works fine in MVC but not in Web Api.

I have the following installed:

Ninject 3.0.1.10
Ninject.Extensions.WCF 3.0.0.5
Ninject.MVC3 3.0.0.6
Ninject.Web.Common 3.0.0.7
SignalR.Ninject

My factory classes look like this:

public interface IBusinessEngineFactory
{
    T GetBusinessEngine<T>() where T : IBusinessEngine;
}

public interface IBusinessEngine
{
}

public class BusinessEngineFactory : IBusinessEngineFactory
{

    private IKernel Kernel { get; set; }

    public BusinessEngineFactory(IKernel kernel)
    {
        Kernel = kernel;
    }

    T IBusinessEngineFactory.GetBusinessEngine<T>()
    {
        return Kernel.Get<T>();
    }
}

I have the standard NinjectWebCommon:

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);
        // Install our Ninject-based IDependencyResolver into the Web API config
        GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(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<IUserIdentity>().To<UserIdentity>();
        kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
        kernel.Bind<IAlarmEngine>().To<AlarmEngine>();
        kernel.Bind<IBusinessEngineFactory>().To<BusinessEngineFactory>();
    }        
}

This is set up in a controller thus

public class UserController : BaseController
{

    public UserController(IBusinessEngineFactory businessEngineFactory, IUnitOfWork unitOfWork, UserIdentity userIdentity)
        : base(businessEngineFactory, unitOfWork, userIdentity)
    {

    }

...

    public ActionResult Edit(int id = 0)
    {
...
        var x = BusinessEngineFactory.GetBusinessEngine<IAlarmEngine>();
        x.ProcessAlarmEventUpdate("test");

        return View(x);
    }
}

Which works fine. Where I have the problems is identical code in the WebAPIController:

public class AlarmWebApiController : ApiController
{

    public IBusinessEngineFactory BusinessEngineFactory { get; set; }

    public IUnitOfWork UnitOfWork {get; set;}

    public IUserIdentity UserIdentity { get; set; }

    public AlarmWebApiController(IBusinessEngineFactory businessEngineFactory, IUnitOfWork unitOfWork, IUserIdentity userIdentity)
    {
        if (businessEngineFactory == null) throw new NullReferenceException("businessEngineFactory");
        BusinessEngineFactory = businessEngineFactory;
        if (unitOfWork == null) throw new NullReferenceException("unitOfWork");
        UnitOfWork = unitOfWork;
        if (userIdentity == null) throw new NullReferenceException("userIdentity");
        UserIdentity = userIdentity;
    }

}

When I run this the MVC controller processes fine but the Web API function does not and I get the obscure error message which occurs before any code in the constructor of the webapi is called.

"Error loading Ninject component ICache

No component has been registered in the kernel's component container"

I think the problem is the that MVC has knowledge of Kernel but because WebAPI uses this:

GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

so it does not know the kernel. The code for creating the business engine exists in a different project to the main MVC, Web API and ninject creation and I would prefer not to stick a dependency to System.Web.Http (for the GlobalConfiguration.Configuration.DependencyResolver object) if I can help it. Is there any way to make it work across both MVC and WebAPI?

Thanks in advance

有帮助吗?

解决方案

I fixed this problem so the IoC would inject the abstract factory and return the correct concrete implementation in both MVC and WebAPI. In the end my solution had the following packages:

<package id="Ninject" version="3.0.1.10" targetFramework="net40" />
<package id="Ninject.Extensions.Wcf" version="3.0.0.5" targetFramework="net40" />
<package id="Ninject.MVC3" version="3.0.0.6" targetFramework="net40" />
<package id="Ninject.Web.Common" version="3.0.0.7" targetFramework="net40" />
<package id="Ninject.Web.WebApi-RC" version="3.0.0.22" targetFramework="net45" />

The business engine factory was modified to use the following:

public class BusinessEngineFactory : IBusinessEngineFactory
{

    private IResolutionRoot resolutionRoot { get; set; }

    public BusinessEngineFactory(IResolutionRoot resolutionRoot)
    {
        this.resolutionRoot = resolutionRoot;
    }

    T IBusinessEngineFactory.GetBusinessEngine<T>()
    {
        return this.resolutionRoot.Get<T>();
    }
}

I tried to use the package Ninject.Web.WebApi which didn't work and Ninject.Web.WeApi.Updated which stopped my solution from running with a "exception has been thrown by the target of an invocation" error message on application start. Going back to the older version was the solution so now everything is working fine. I even checked it worked in WCF as well!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top