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) { ... }
Ответы
Ответ 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.