MVC 4 Web Api Controller не имеет конструктора по умолчанию? - программирование
Подтвердить что ты не робот

MVC 4 Web Api Controller не имеет конструктора по умолчанию?

Вот трассировка:

<Error>
   <Message>An error has occurred.</Message>

   <ExceptionMessage>
      Type 'ProjectName.Web.Api.Controllers.ContinentsController' does not have a default constructor
   </ExceptionMessage>

   <ExceptionType>System.ArgumentException</ExceptionType>

   <StackTrace>
      at System.Linq.Expressions.Expression.New(Type type)

      at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
   </StackTrace>
</Error>

Я нахожу это странным, поскольку public class UsersController : ApiController { ... } работает отлично. Я сравнил 2 контроллера, все настройки и структуры схожи.

Я использую Ninject, и у меня установлена ​​моя система, аналогичная Jamie Kurtz Asp.Net Mvc 4 и веб-Api: создание службы REST из Начните готово.

Из трассировки стека кто-нибудь может определить проблему и как ее решить? Спасибо!

Как запрошено.

ContinentsController

[LoggingNHibernateSession]
public class ContinentsController : ApiController
{
    private readonly ISession _session;
    private readonly IContinentMapper _continentMapper;
    private readonly IHttpContinentFetcher _httpContinentFetcher;
    private readonly IDateTime _dateTime;

    public ContinentsController(ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime)
    {
        _session = session;
        _continentMapper = continentMapper;
        _httpContinentFetcher = continentFetcher;
        _dateTime = dateTime;
    }

    public IEnumerable<Continent> Get()
    {
        var continents = _session
            .Query<Data.Model.Continent>()
            .Select(_continentMapper.CreateContinent)
            .ToList();

        return continents;
    }

    public Continent Get(long id)
    {
        var modelContinent = _httpContinentFetcher.GetContinent(id);
        var continent = _continentMapper.CreateContinent(modelContinent);

            return continent;
        }
  }

UserController: работает нормально.

    public class UsersController : ApiController
    {
        private readonly ISession _session;
        private readonly IUserManager _userManager;
        private readonly IUserMapper _userMapper;
        private readonly IHttpUserFetcher _userFetcher;

        public UsersController(
            IUserManager userManager,
            IUserMapper userMapper,
            IHttpUserFetcher userFetcher,
            ISession session)
        {
            _userManager = userManager;
            _userMapper = userMapper;
            _userFetcher = userFetcher;
            _session = session;
        }

        [Queryable]
        public IQueryable<Data.Model.User> Get()
        {
            return _session.Query<Data.Model.User>();
        }

        [LoggingNHibernateSession]
        public User Get(Guid id)
        {
            var user = _userFetcher.GetUser(id);
            return _userMapper.CreateUser(user);
        }
    }

Я использую NinjectWebCommon.cs, и в нем у меня есть это и несколько других методов по умолчанию.:

        private static void RegisterServices(IKernel kernel)
        {
            var containerConfigurator = new NinjectConfigurator();
            containerConfigurator.Configure(kernel);

            GlobalConfiguration.Configuration.MessageHandlers.Add(kernel.Get<BasicAuthenticationMessageHandler>());
        }

Тогда у меня есть NinjectConfigurator.cs:

public class NinjectConfigurator
{
    ......
    private void AddBindings(IKernel container)
        {
            .....
            container.Bind<IDateTime>().To<DateTimeAdapter>();
            container.Bind<IDatabaseValueParser>().To<DatabaseValueParser>();

            //HttpFetchers
            container.Bind<IHttpUserFetcher>().To<HttpUserFetcher>();
            container.Bind<IHttpContinentFetcher>().To<HttpContinentFetcher>();                                

            //TypeMappers
            container.Bind<IUserManager>().To<UserManager>();
            container.Bind<IMembershipInfoProvider>().To<MembershipAdapter>();
            container.Bind<IUserMapper>().To<UserMapper>();
            container.Bind<IContinentMapper>().To<ContinentMapper>();    
            .........
        }
     .......
}

Оба NinjectWebCommon.cs и NinjectConfigurator.cs находятся в папке App_Start.

container.Bind<ISession>().ToMethod(CreateSession); есть NHibernate. Он находится внутри NinjectConfigurator.cs внутри private void ConfigureNHibernate(IKernel container) { ... }

4b9b3361

Ответ 1

Эта ошибка является известной ошибкой, когда вы не устанавливаете преобразователь зависимостей в своем приложении. Контроллер Factory не смог найти конструктор без параметров для создания контроллера и выполнить метод действия (или метод глагола?). Таким образом, вы должны создать класс распознавателя зависимостей и установить его при инициализации своего веб-приложения. Он будет определять зависимости ваших контроллеров.

Используя ninject, вы можете попробовать что-то вроде этого:

using Ninject; 
using Ninject.Syntax; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics.Contracts; 
using System.Web.Http.Dependencies; 

namespace MyApplication.App_Start 
{     
    public class NinjectDependencyScope : IDependencyScope     
    {         
        private IResolutionRoot resolver;         

        internal NinjectDependencyScope(IResolutionRoot resolver)         
        {             
            Contract.Assert(resolver != null);             
            this.resolver = resolver;         
        }         

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

        public object GetService(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.TryGet(serviceType);         
        }   

        public IEnumerable GetServices(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.GetAll(serviceType);         
        }     
    }     

    public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver     
    {         
        private IKernel kernel;         
        public NinjectDependencyResolver(IKernel kernel)             
            : base(kernel)         
        {             
            this.kernel = kernel;         
        }         

        public IDependencyScope BeginScope()         
        {             
            return new NinjectDependencyScope(kernel.BeginBlock());         
        }     
    } 
}

Класс NinjectDependencyResolver принимает объект Ninject StandardKernel в качестве аргумента конструктора, и эта ссылка используется всякий раз, когда область зависимостей конвейерна. Чтобы все это работало, класс NinjectDependencyResolver присваивается глобальной конфигурации приложения:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
    kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

    // register all your dependencies on the kernel container
    RegisterServices(kernel);

    // register the dependency resolver passing the kernel container
    GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

    return kernel;
}

В своем Global.asax.cs файле в конце события Application_Start вызовите этот метод CreateKernel.

Ответ 2

Вам нужно сообщить Ninject, как правильно разрешать зависимости API.

Вы можете использовать Felipe Oriani ответ, но если вам нравится, пакет NuGet называется WebApiContrib.IoC.Ninject, который сделает это за вас.

  • В Visual Studio Перейдите по ссылке: Инструменты > Диспетчер пакетов NuGet > Управление Пакеты NuGet для решения

  • Установите пакет WebApiContrib.IoC.Ninject

  • Изменить: NinjectWebCommon.cs и обновить метод CreateKernel(), чтобы включить: GlobalConfiguration.Configuration.DependencyResolver = новый NinjectResolver (ядро);

    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
    
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
    
            RegisterServices(kernel);
    
            //Note: Add the line below:
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
    
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }
    

Ответ 3

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

Проблема заключалась в том, что я случайно разрешил интерфейс для того же интерфейса, а не для решения конкретного конкретного типа. Поэтому, используя пример из OP, я сделал следующее, что приводит к идентичной ошибке:

container.Bind<IUserManager>().To<IUserManager>();

Обратите внимание на разрешение IUserManager, которое было надзором, но оно приводит к идентичной ошибке с OP. Очевидно, что исправление заключается в разрешении на конкретный конкретный тип.

Ответ 4

Для меня это был только вопрос добавления пакета NuGet Ninject.Web.WebApi.Webhost.

Для моих приложений, использующих как MVC, так и WebApi2, у меня есть следующие пакеты для Ninject:

  • Ninject
  • Ninject.MVC5
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost
  • Ninject.Web.WebApi
  • Ninject.Web.WebApi.WebHost

Ответ 5

Принятый ответ - с 2014 года. Так как у тонн людей была эта проблема, с 2016 года там рецепт. Это просто добавляет к принятому ответу.

Как я это делаю, устанавливая пакеты Ninject.MVC3 и WebApiContrib.IoC.Ninject. Файл с именем NinjectWebCommon добавляется в вашу папку App_Start. Затем вы можете использовать встроенный NinjectResolver.

Просто добавьте этот метод:

private static void AddWebApiSupport(StandardKernel kernel)
{
  // Support WebAPI
  GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
  GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new NinjectWebApiFilterProvider(kernel));
}

и вызовите его перед вызовом RegisterServices.

Ответ 6

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

Ответ 7

Это обычная проблема возникает, главным образом, при работе с контейнером для инъекций Ninject Dependency. Чтобы решить эту проблему, выполните следующие действия. Убедитесь, что вы установили следующие пакеты.

Снова пойдите для этого и установите this- введите описание изображения здесь

Теперь проверьте папку App_start. Вы найдете следующее (NinjectWebcommon.cs). введите описание изображения здесь

Теперь дважды щелкните и проверьте следующую строку в методе CreateKernel(), подобном этому

 private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

А затем зарегистрируйте свое зависимое имя как

 private static void RegisterServices(IKernel kernel)
    {

        kernel.Bind<IProductDetails>().To<ProductDetails>().InRequestScope();
    }      

Я уверен, что это заставит ваше решение работать.

Ответ 8

private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();

Убедитесь, что часть To & lt;> является конкретным классом, а не интерфейсом, поскольку это также вызовет такую же ошибку!

Ответ 9

На случай, если кто-нибудь из пользователей SimpleInjector окажется здесь...

Для меня это было просто, что я забыл добавить SimpleInjectorInitializer.Initialize(); в мой метод Application_Start().

Обычно я создаю класс SimpleInjectorInitializer в папке App_Start в эти дни, в течение которого я выполняю вызовы container.Verify() и GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);; после того, как я вызвал мой метод GetInitializeContainer(), который выполняет все регистрации типов и т.д.

Ответ 10

Это происходило со мной, когда я не упомянул интерфейс и класс для внедрения зависимостей в файле web.config.