Ninject и ASP.NET Web API

Прежде чем задать вопрос, вы должны знать, что я получил свой текущий код с этой страницы: http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/

Я пытаюсь использовать ASP.NET Web API и Ninject в своем приложении, используя адаптер IDependencyResolver, найденный на сайте выше.

Я создал весь код так, как он показывает на сайте, и он работает, но когда я загружаю свою аппликацию, мои обычные контроллеры терпят неудачу и показывают эту ошибку:

[MissingMethodException: No parameterless constructor defined for this object.]
[InvalidOperationException: An error occurred when trying to create a controller of type 'AccountManager.Controllers.HomeController'...

Итак, похоже, что я могу использовать Ninject с помощью обычных контроллеров или контроллеров Web API, но не для обоих.: (

Вот мой код:

NinjectResolver.cs

public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private IKernel _kernel;

    public NinjectResolver(IKernel kernel)
        : base(kernel)
    {
        _kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

NinjectScope.cs

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;

    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }

    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }

    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    private void SetupDependencyInjection()
    {
        //create Ninject DI Kernel
        IKernel kernel = new StandardKernel();

        //register services with Ninject DI container
        RegisterServices(kernel);

        //tell asp.net mvc to use our Ninject DI Container
        GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
    }
}

AccountingController.cs

public class AccountingController : ApiController
{
    private ICustomerService _customerService;

    public AccountingController(ICustomerService service)
    {
        _customerService = service;
    }

    // GET /api/<controller>/5
    public string Get(int id)
    {
        return "value";
    }
}

Ответ 1

Вставьте следующую строку кода в метод CreateKernel() до вызова RegisterServices(kernel);.

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

Вам также понадобится использовать приведенный ниже код, я предпочитаю его определять в том же классе.

public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private IKernel _kernel;
    public NinjectResolver(IKernel kernel)  : base(kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;
    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }
    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }
    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }
    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Запустите его, и он должен работать. Это сработало для меня, я надеюсь, это и для вас тоже.

Дальнейшее чтение:

Использование инъекции Ninject - Dependency Injection с помощью контроллеров веб-API ASP.NET

Ответ 2

У меня есть проект веб-API, который работает с использованием того же решения, что и у вас из strathweb, поэтому я просто добавил нормальный контроллер в проект, и он работает. Для вас это не очень помогает, поэтому я подробно расскажу о настройке, которую у меня есть:

У меня установлены следующие пакеты (на стороне IOC):

  • Ninject 3.0.1.10
  • Ninject MVC 3.0.0.6
  • Ninject.Web.Common 3.0.0.7
  • WebActivator 1.5.1

У меня нет абсолютно ничего в файле Global.asax.cs относительно Ninject, вместо этого используется файл NinjectWebCommon.cs, который автоматически создается в App_Start при установке Ninject. Я не знаю, имеет ли код в вашем глобальном файле, что означает, что Ninject не настроил себя правильно в вашем проекте?

Вот код в NinjectWebCommon.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 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<IUserRepository>().To<UserRepository>().InSingletonScope();
        kernel.Bind<IUserManager>().To<UserManager>();
    }        
}

Здесь другая разница, которую я вижу между нашим кодом, где я создаю Ядро, мой код объявляет два привязки к ядру.

Вот код моего тестового контроллера, я могу установить точку останова в конструкторе и получить его:

public class TestController : Controller
{
    IUserManager _userManager;

    public TestController(IUserManager userManager)
    {
        _userManager = userManager;
    }

    //
    // GET: /Test/
    public ActionResult Index()
    {
        return View();
    }
}

Это работает как с моим контроллером, так и с моими APIControllers.