MVC5, Web API 2 и Ninject

Я создал новый проект MVC5 с Web API 2, затем я добавил пакет Ninject.MVC3 из NuGet.

Встраивание конструктора отлично работает для контроллеров MVC5, но я получаю сообщение об ошибке при попытке использовать его с помощью контроллеров веб-API.

Произошла ошибка при попытке создать контроллер типа UserProfileController. Удостоверьтесь, что у контроллера нет конструктора без параметров.

Конструктор для работы контроллера MVC5:

public class HomeController : Controller
{
    private IMailService _mail;
    private IRepository _repo;

    public HomeController(IMailService mail, IRepository repo)
    {
        _mail = mail;
        _repo = repo;
    }
}

Конструктор для нерабочего веб-контроллера API:

public class UserProfileController : ApiController
{
    private IRepository _repo;

    public UserProfileController(IRepository repo)
    {
        _repo = repo;
    }
}

Ниже представлен полный файл NinjectWebCommon.cs:

[assembly: WebActivator.PreApplicationStartMethod(typeof(DatingSite.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(DatingSite.App_Start.NinjectWebCommon), "Stop")]

namespace DatingSite.App_Start
{
using System;
using System.Web;

using Microsoft.Web.Infrastructure.DynamicModuleHelper;

using Ninject;
using Ninject.Web.Common;
using DatingSite.Services;
using DatingSite.Data;

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);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
#if DEBUG
        kernel.Bind<IMailService>().To<MockMailService>().InRequestScope();

#else
        kernel.Bind<IMailService>().To<MailService>().InRequestScope();
#endif
        kernel.Bind<SiteContext>().To<SiteContext>().InRequestScope();
        kernel.Bind<IRepository>().To<Repository>().InRequestScope();
    }
}
}

Ответ 1

Только что выпущен Ninject.Web.WebApi NuGet package. Отныне предпочтительным решением является использование этого пакета. Я не мог найти никакой связанной документации, но после установки пакета все сработало для меня.

Install-Package Ninject.Web.WebApi 

После установки как обычные MVC, так и экземпляры контроллера API предоставляются Ninject.

Если у вас уже установлен Ninject.Web.Common, обязательно сохраните привязки из NinjectWebCommon.cs и позвольте Nuget переписать NinjectWebCommon.cs во время установки и вернуть свои привязки по завершении.

Как указано в комментариях в зависимости от вашего контекста выполнения, вам понадобится one следующих пакетов:

  • Ninject.Web.WebApi.WebHost
  • Ninject.Web.WebApi.OwinHost
  • Ninject.Web.WebApi.Selfhost

Наиболее распространенным сценарием является IIS, который выбирает пакет WebHost.

В случае, если вы запускаете веб-приложение IIS MVC5 с нуля и хотите использовать Ninject, установите следующие пакеты:

  • Ninject - Ninject core dll
  • Ninject.Web.Common - Общие функции Web для Ninject, например. InRequestScope()
  • Ninject.MVC5 - Инъекторы зависимости MVC, например. для обеспечения контроллеров для MVC
  • Ninject.Web.Common.WebHost - регистрирует инжекторы зависимостей из Ninject.MVC5, когда IIS запускает веб-приложение. Если вы не используете IIS, вам понадобится другой пакет, проверьте выше
  • Ninject.Web.WebApi Инъекторы зависимостей WebApi, например. для обеспечения контроллеров для WebApi
  • Ninject.web.WebApi.WebHost - регистрирует инжекторы зависимостей из Ninject.Web.WebApi, когда IIS запускает веб-приложение.

Ответ 2

У вас есть эта проблема, потому что Controller и ApiController используют разные средства разрешения зависимостей. Решение очень просто.

Сначала создайте новые классы Dependency Resolver и Dependency Scope. Вы можете использовать это:

 public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private readonly 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;
    }
}

После этого добавьте следующую строку в метод CreateKernel() в NinjectWebCommon

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

Ответ 3

У меня была та же проблема. После установки следующих пакетов NuGet:

  • Ninject
  • Ninject.web.WebApi
  • Ninject.web.WebApi.WebHost
  • Ninject.MVC3
  • Ninject.web.Common
  • Ninject.web.Common.WebHost

все работает отлично

Ответ 4

Я обнаружил, что сборка Ninject.Web.WebApi.dll определяет собственный DependencyResolver и автоматически регистрирует его с ядром в классе Ninject.Web.WebApi.WebApiModule.

Поэтому я просто добавляю к NinjectWebCommon.CreateKernel одну строку...

                GlobalConfiguration.Configuration.DependencyResolver = kernel.Get<System.Web.Http.Dependencies.IDependencyResolver>();

Наконец, мой проект имеет следующие зависимости:

  • Ninject 3.2.0
  • Ninject.Web.Common 3.2.0
  • Ninject.Web.WebApi 3.2.4

Ответ 5

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

У меня было несколько приложений с использованием одного проекта WebApi. Я бы получил вышеуказанную ошибку, если бы не включил привязку в методе RegisterServices. Поэтому, прежде чем вытаскивать волосы, просто проверьте, есть ли у вас привязка. Ошибка не говорит вам, что у вас отсутствуют привязки. Что бы это было, если приложение находится в том же проекте, что и WebApi.

Ответ 6

Недавно мне пришлось работать с Web Api 2, поэтому я могу ответить на эту часть вопроса.

Это пакеты nuget, необходимые для Web Api 2-

Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi 
WebActivatorEx 

Затем отредактируйте NinjectWebCommon.CreateKernel(..), включая

RegisterServices(kernel);
// the next line is the important one
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;

Я написал более подробное сообщение об этом - http://NoDogmaBlog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-to-make-them-work-together/, включая полное решение для загрузки.