Привязка веб-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, версия =3.0.0.0, культура = нейтральная, PublicKeyToken=c7192dc5380945e7" не имеет реализации.
Что мне не хватает?
11 ответов
Я спросил Брэда Уилсона об этом, и это изменилось в MVC4 RC.
GlobalConfiguration.Configuration.ServiceResolver был перемещен в GlobalConfiguration.Configuration.DependencyResolver
Используйте эту реализацию для создания Ninject DependencyResolver для вашего веб-API: https://gist.github.com/2417226
В NinjectWebCommon.cs:
// Register Dependencies
RegisterServices(kernel);
// Set Web API Resolver
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
Это общее сообщение об ошибке
Тип "Api.Controllers.ConsumerController" не имеет конструктора по умолчанию
может также произойти, если вы не сделаете ваш конструктор общедоступным, или зависимость не может быть разрешена контейнером IoC, возможно, из-за отсутствующего аргумента.
Сообщение об ошибке вводит в заблуждение, если не сказать больше.
Вы можете установить пакет NuGet WebApiContrib.IoC.Ninject и добавить следующую строку кода в NinjectWebCommon.cs
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
Для того, кто приземлится здесь во время поиска "... не имеет конструктора по умолчанию", ищет простой способ отладки бездействующих неудачных конфигураций:
- Удалите объекты, внедренные в конструктор, пока конструктор не будет вызван
- Для каждого из ранее внедренных, теперь неинициализированных объектов, вызовите с помощью:
ServiceLocator.Current.GetInstance<[OBJ-TYPE]>()
Объект-нарушитель вызовет исключение ActivationException с описательным сообщением. Вам будет на что пойти.
Не забудьте удалить вызов в ServiceLocator после исправления. То есть. это не рекомендация использовать шаблон поиска служб вне отладки.
Надеюсь, это поможет кому-то еще...
У меня была та же проблема, и она была связана с тем, что я переехал в класс, отвечающий за регистрацию сборки, отвечающей за инициализацию контроллеров. Перемещено из сети в рамочный проект.
Использование Autofac, но то же самое относится и к другим контейнерам.
Звонил:
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
Это прекрасно работает, когда оно находится внутри веб-приложения, но выдает вышеупомянутое исключение при перемещении в проект фреймворка, поскольку исполняемая сборка больше не содержит контроллеров.
Вместо этого пришлось обновить до:
builder.RegisterApiControllers(Assembly.GetCallingAssembly());
Кажется, что 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 довольно хорошо сообщает о подобных ошибках, поэтому я действительно был зациклен на этом!
Вы зарегистрировали контейнер с помощью работ? Я предпочитаю использовать 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
Из Плое
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
t => this.container.Kernel.HasComponent(t) ?
this.container.Resolve(t) :
null,
t => this.container.ResolveAll(t).Cast<object>());
Выше должно быть выполнено в global.asax
Просто установите пакет Ninject.MvcXXX, где XXX - версия MVC...
Если у кого-то все еще есть проблемы, пожалуйста, послушайте, по какой-то причине ninject не работает так, как мы ожидаем от mvc 4. В вашем веб-интерфейсе API вам нужно написать этот код
public DefaultController() : base() { }
Это устраняет сообщение об отсутствии конструктора по умолчанию, а затем, когда вам нужно получить данные из метода get, напишите этот код:
public IEnumerable<YourModelGoesHere> Get()
{
return context.YourData;
}
Имейте в виду, вам также понадобится получить доступ к вашему классу БД, например:
DefaultConnection context = new DefaultConnection();
Я знаю, это старый пост, но я нашел решение по какой-то ссылке, поэтому делюсь здесь. Надеюсь, поможет.
У меня тоже было это сообщение об ошибке, но оказалось, что один из моих интерфейсов не был реализован ни одним классом (я забыл добавить его в объявление класса).