Связывание веб-API ASP.NET с ninject

Я только что установил обновление mvc4 rc, и я пытаюсь создать приложение api с небольшой удачей.

Я использую ninject, но не могу загрузить мои контроллеры. Я продолжаю получать сообщение об ошибке

Тип 'Api.Controllers.ConsumerController' не имеет конструктора по умолчанию

Я очень новичок в mvc и использую инъекцию, поэтому, пожалуйста, несите меня.

Я не сделал ничего особенного для связывания по умолчанию, созданного с помощью nuget

 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)
    {
        kernel.Bind<IConsumerRepository>().To<ConsumerRepository>();
    }        
}

Мой контроллер выглядит как

   private readonly IConsumerRepository _repository;

    public ConsumerController(IConsumerRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public IQueryable<Consumer> Get(Guid id)
    {
        return _repository.Get(id).AsQueryable();
    }

Что мне нужно сделать, чтобы заставить api-контроллеры работать с ninject?

Извините, если это простой материал

Я попробовал ваше предложение Майкла, но после изменения webcommon.cs на этот

  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<IConsumerRepository>().To<ConsumerRepository>();
    }

Я получаю сообщение об ошибке, когда

var kernel = new StandardKernel();

называется

Метод GetFilters в типе "Ninject.Web.WebApi.Filter.DefaultFilterProvider" из сборки "Ninject.Web.WebApi, Version = 3.0.0.0, Culture = neutral, PublicKeyToken = c7192dc5380945e7" не имеет реализации.

Что мне не хватает?

Ответ 1

Я спросил Брэд Уилсон об этом, и он изменился в MVC4 RC.

GlobalConfiguration.Configuration.ServiceResolver перенесен в GlobalConfiguration.Configuration.DependencyResolver

Используйте эту реализацию для создания Ninject DependencyResolver для вашего Web Api: https://gist.github.com/2417226

В NinjectWebCommon.cs:

// Register Dependencies
RegisterServices(kernel);

// Set Web API Resolver
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

Ответ 2

Это общее сообщение об ошибке

Тип 'Api.Controllers.ConsumerController' не имеет конструктора по умолчанию

также может возникать, если вы не делаете свой конструктор общедоступным, или зависимость не может быть разрешена контейнером IoC, возможно, из-за отсутствующего аргумента.

Сообщение об ошибке вводит в заблуждение, если не сказать больше.

Ответ 3

Вы можете установить пакет NuGet WebApiContrib.IoC.Ninject и добавить следующую строку кода в NinjectWebCommon.cs

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

Ответ 4

Для кого-то, приземляющегося здесь при поиске "... не имеет конструктора по умолчанию", который ищет простой способ отладки безмолвных конфигураций:

  • Удалить объекты, вложенные в конструктор, до тех пор, пока не будет вызван конструктор
  • Для каждого из ранее введенных, теперь неинициализированных объектов, вызовите с помощью:

ServiceLocator.Current.GetInstance<[OBJ-TYPE]>()

Нарушительный объект вызовет исключение ActivationException с описательным сообщением. У вас есть что поделать.

Не забудьте удалить вызов для исправления ServiceLocator. То есть. это не рекомендация использовать анти-шаблон локатора службы вне отладки.

Ответ 5

Вы зарегистрировали контейнер с помощью frawework? Я предпочитаю использовать autofac, вот пример использования autofac с API. http://alexmg.com/post/2012/03/08/Autofac-ASPNET-Web-API-%28Beta%29-Integration.aspx

Кроме того, у Марка Симана хорошая публикация на DI в целом с WebAPI

http://blog.ploeh.dk/2012/03/20/RobustDIWithTheASPNETWebAPI.aspx

От Ploeh:

GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
    t => this.container.Kernel.HasComponent(t) ?
        this.container.Resolve(t) :
        null,
    t => this.container.ResolveAll(t).Cast<object>());

Вышеуказанное должно выполняться в global.asax

Ответ 6

Надеюсь, это поможет кому-то еще...

У меня была одна и та же проблема, и это было связано со мной, перемещающим класс, ответственным за регистрацию сборки, отвечающей за инициализацию контроллеров. Перемещено из сети в проект рамки.

Использование Autofac, но то же самое применимо и к другим контейнерам.

Вызывал:

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

Что отлично работает, когда оно находится в веб-приложении, но выбрасывается выше исключения при перемещении в проект фреймворка, поскольку исполняющая сборка больше не содержит контроллеров.

Вместо этого нужно было обновить:

builder.RegisterApiControllers(Assembly.GetCallingAssembly());

Ответ 7

Кажется, что Ninject не генерирует исключение, как обычно, когда ваши зависимости IOC не совсем настроены правильно. Вместо этого он выглядел так, будто я не зарегистрировал преобразователь зависимостей WebAPI, который я, безусловно, сделал. Вот мое решение этой проблемы, но из-за того, что я нашел, это могло быть МНОГО РАЗЛИЧНЫХ типов проблем установки. Просто перепроверьте все в цепочке зависимостей. Надеюсь, это поможет кому-то!

Контроллер:

public class ContestsController : ApiController
{
    //Ninject wouldn't inject this CTOR argument resulting in the error
    public ContestsController(IContestEntryService contestEntryService)
    {

Зависимость:

public class ContestEntryService : IContestEntryService
{

    public ContestEntryService(IContestsContext contestsContext)
    {

Неверная конфигурация:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IContestsContext>()
              .To<ContestsContext>()
              .InRequestScope();

        kernel.Bind(x =>
            x.FromAssembliesMatching("MyNameSpace.*")
             .SelectAllClasses()
             .BindAllInterfaces()
         );

Правильная конфигурация:

    private static void RegisterServices(IKernel kernel)
    {
         kernel.Bind(x =>
            x.FromAssembliesMatching("MyNameSpace.*")
             .SelectAllClasses()
             .BindAllInterfaces()
         );

         kernel.ReBind<IContestsContext>()
              .To<ContestsContext>()
              .InRequestScope();

Как правило, Ninject довольно хорошо сообщает об этих типах ошибок, поэтому я действительно получил бросок для цикла на этом!

Ответ 9

если у кого-то все еще есть проблемы, пожалуйста, послушайте почему-то, что ninject не работает, как мы ожидаем с mvc 4. В вашем веб-api вам нужно написать этот код

public DefaultController() : base() { }  

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

public IEnumerable<YourModelGoesHere> Get() 
{
    return context.YourData;  
} 

Имейте в виду, что вам также потребуется получить доступ к вашему классу db, например:

DefaultConnection context = new DefaultConnection(); 

Ответ 10

просто установите пакет Ninject.MvcXXX, где XXX - версия MVC...

Ответ 11

У меня тоже было это сообщение об ошибке, но оказалось, что один из моих интерфейсов фактически не реализован ни одним классом (я забыл добавить его в объявление класса).