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;
}
}
UsersController: Работает просто отлично.
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) { ... }
8 ответов
Эта ошибка является известной ошибкой, когда вы не устанавливаете преобразователь зависимостей в своем приложении. Фабрике контроллеров не удалось найти конструктор без параметров, чтобы создать контроллер и выполнить метод действия (или метод глагола?). Итак, вы должны создать класс средства разрешения зависимостей и установить его при инициализации вашего веб-приложения. Это разрешит зависимости ваших контроллеров.
С помощью 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
метод.
Вы должны указать Ninject, как правильно разрешать зависимости Web API.
Вы можете использовать ответ Фелипе Ориани, но если вам нравится, есть пакет NuGet с именем WebApiContrib.IoC.Ninject, который сделает это за вас.
В Visual Studio выберите: Инструменты> Диспетчер пакетов NuGet> Управление пакетами NuGet для решения.
Установите пакет WebApiContrib.IoC.Ninject
Отредактируйте: NinjectWebCommon.cs и обновите метод CreateKernel(), включив в него: GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
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; } }
Для меня это был только вопрос добавления пакета 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
Я также столкнулся с этой идентичной ошибкой, но по другой причине, используя Ninject
, У меня на самом деле были правильные преобразователь зависимостей и конфигурация. На самом деле приложение работало хорошо, пока я не попытался разрешить еще одну новую зависимость. У меня была установлена регистрация для этого, поэтому я не мог понять, чего не хватало.
Проблема заключалась в том, что я случайно решил Интерфейс к тому же Интерфейсу, а не разрешил соответствующий конкретный тип. Таким образом, используя пример из OP, я сделал следующее, что приводит к идентичной ошибке:
container.Bind<IUserManager>().To<IUserManager>();
Уведомление о разрешении на IUserManager
это был недосмотр, но он приводит к идентичной ошибке от OP. Очевидно, что решение заключается в том, чтобы решить, какой тип бетона нужен.
Принятый ответ - с 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
,
У меня тоже была эта проблема, но оказалось, что один из моих интерфейсов на самом деле не был реализован никакими классами (я забыл добавить его в объявление класса).
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();
Убедитесь, что часть To<> является конкретным классом, а не интерфейсом, поскольку это также вызовет такую же ошибку!
В случае любого SimpleInjector
пользователи попадают сюда...
Для меня это было просто потому, что я забыл добавить SimpleInjectorInitializer.Initialize();
к моему Application_Start()
метод.
Я обычно создаю SimpleInjectorInitializer
класс в App_Start
папка в наши дни, в которой я делаю container.Verify()
а также GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
звонки; после того, как я позвонил своемуGetInitializeContainer()
метод, который выполняет все регистрации типов и т. д.
Это происходило со мной, когда я не упомянул интерфейс и класс для внедрения зависимостей в файле web.config.
Эта распространенная проблема возникает в основном при работе с Ninject Dependency инъекционным контейнером. Пожалуйста, следуйте инструкциям, чтобы решить эту проблему.
Снова пойти на это и установить это-
Теперь проверьте папку 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();
}
Я уверен, что это заставит ваше решение работать.