2016-12-13 3 views
0

Я относительно новый пользователь как для Autofac, так и для ASP.NET Core. Недавно я перенес небольшой проект из «классического» проекта ASP.NET WebAPI в ASP.NET Core. У меня возникают проблемы с Autofac, особенно при регистрации родовых типов.Ошибка регистрации типичных типов с Autofac в ASP.NET Core

Этот проект использует шаблон Command, каждый обработчик команд является закрытым родовое как

public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand> 

Эти обработчики команд инъецируют в контроллеры, такие как:

readonly private ICommandHandler<UpdateCustomerCommand> _updateCustomerCommand; 
public ValuesController(ICommandHandler<UpdateCustomerCommand> updateCustomerCommand) 
{ 
    _updateCustomerCommand = updateCustomerCommand; 
} 

Autofac сконфигурирован (частично) в качестве :

var builder = new ContainerBuilder(); 
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 
//This doesn't seem to be working as expected. 
builder.RegisterAssemblyTypes(assemblies) 
    .As(t => t.GetInterfaces() 
     .Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>))) 
     .Select(a => new KeyedService("commandHandler", a))); 

Выше, похоже, не регистрируется t он общий, как ожидалось. Если я использую метод ниже для регистрации, он работает хорошо.

builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>(); 

Когда я говорю «Это не работает», что я имею в виду, что при попытке создать экземпляр контроллера, я получаю «InvalidOperationException: Не удается разрешить услугу типа«BusinessLogic.ICommandHandler`1 [BusinessLogic. UpdateCustomerCommand] 'при попытке активировать' AutoFac_Test.Controllers.ValuesController '. "

Это хорошо работало в полной версии WebAPI этого проекта, но не после его воссоздания в ASP.NET Core. Чтобы быть ясным, это отлично работало перед переносом на ASP.NET Core.

Вот ссылка на код, который я использовал, чтобы воссоздать этот вопрос: https://dl.dropboxusercontent.com/u/185950/AutoFac_Test.zip

**** ИЗМЕНИТЬ ПОСЛЕ РЕШЕНИЯ НАЙДЕННЫХ ****

Там не было ничего на самом деле не так с моя конфигурация Autofac и, конечно, не сам Autofac. Случилось так, что я переименовал вывод моих зависимых сборок, чтобы сделать сборку для сканирования (замена AppDomain.CurrentDomain.GetAssemblies() более элегантной, однако я никогда не изменял зависимости проекта API для ссылки на новые сборки. Таким образом, Autofac сканировал правильно загруженные узлы, которые случились быть более старыми версиями, которые не содержат интерфейсы и реализации я ожидал ...

+0

Возможного дубликатом [Могу ли я сделайте ключевую услугу для AutoFac на основе типа Open Generic] (http://stackoverflow.com/questions/13636492/can-i-make-a-keyed-service-for-autofac-based-on-the- type-of-the-the-open-generic) – Tseng

+0

Спасибо за предложение, но этот вопрос не является дубликатом этого. В этом случае реквестер хотел зарегистрировать общий вывод из конкретной базы и реализовать определенный закрытый общий интерфейс. В моем случае я просто хочу зарегистрировать реализации конкретного закрытого общего интерфейса. Более того, вышеприведенный синтаксис доказал свою эффективность в классическом ASP.NET, но не в ASP.NET Core. Мне интересно, изменилось ли что-то в размышлении, которое могло бы вызвать это? – QuietSeditionist

ответ

0

Autofac имеет встроенную поддержку для регистрации закрытого типа открытого родовым.

builder 
    .RegisterAssemblyTypes(ThisAssembly) 
    .AsClosedTypesOf(typeof(ICommandHandler<>)); 

Это сканирует вашу сборку, находит типы, закрывающие открытый общий интерфейс ICommandHandler<>, и регистрирует каждую из них закрытый комплексный интерфейс, который они реализуют - в вашем случае, ICommandHandler<UpdateCustomerCommand>.

В вашем примере не работает то, что вы связываете ключ с вашими услугами. Autofac не ищет ключевую версию вашего ICommandHandler<UpdateCustomerCommand> при попытке создать экземпляр ValuesController, поэтому вы получаете исключение.

Редактировать после комментария QuietSeditionist в:

Я попытаюсь разработать немного на ключом VS. по умолчанию услуги.Способ регистрации ваших обработчиков заключается в сопоставлении с ними ключа commandHandler.

Это означает, что после того, как контейнер будет построен, вот единственный способ разрешить такой обработчик:

// container will look for a registration for ICommandHandler<UpdateCustomerCommand> associated with the "commandHandler" key 
container.ResolveKeyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler"); 

Когда инстанцировании ValuesController, Autofac не смотрит на шпонкой регистрации ICommandHandler<UpdateCustomerCommand>, т.к. его не просили.

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

// BOOM! 
container.Resolve<ICommandHandler<UpdateCustomerCommand>>(); 

Причина ваша вторая регистрация работает, потому что вы не ключ службы:

// No key 
builder 
    .RegisterType<UpdateCustomerCommandHandler>() 
    .As<ICommandHandler<UpdateCustomerCommand>>(); 

// commandHandler key 
builder 
    .RegisterType<UpdateCustomerCommandHandler>() 
    .Keyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler"); 

Но так как вы не хотите зарегистрировать все обработчики один за другим, вот как зарегистрировать их без манипуляция их:

builder 
    .RegisterAssemblyTypes(ThisAssembly) 
    .AsClosedTypesOf(typeof(ICommandHandler<>)); 

/Edit

Я вижу два сценария манипуляция услуг может быть полезно:

  • У вас есть несколько типов, реализующих один и тот же интерфейс, и вы хотите, чтобы ввести различные реализации в разных службах. Скажем, вы регистрируете SqlConnection и DB2Connection как IDbConnection. Затем у вас есть 2 службы, одна из которых предназначена для работы с SQL Server, а другая - с DB2. Если они оба зависят от IDbConnection, вы хотите убедиться, что вы ввели правильное значение в каждую службу.

  • Если вы используете decorators, работа регистрации способа является определение службы, к которым декораторы будут применяться с помощью ключа - первого примера является самостоятельным пояснительной

+0

На самом деле, я использую шаблон Decorator здесь, поэтому мне нужно, чтобы этот ключ был указан. Почему Autofac не ищет ключевую версию этого? Извиняюсь, но похоже, что у вашего ответа нет ответа. – QuietSeditionist

+0

Вы действительно используете шаблон Decorator? В исходном вопросе не упоминается, что вы его используете, а связанный с ним .zip не содержит регистрацию декоратора или реализацию декоратора 'ICommandHandler'. Autofac по умолчанию пытается разрешить * по умолчанию * службы, то есть те, которые явно не указаны * или * keyed *. Если вы хотите, чтобы он разрешал такие службы, вы должны быть откровенно об этом. –

+0

Когда я создал образец проекта, это была упрощенная версия моего проекта. Вы правы, что, когда я удалил строку, чтобы зарегистрировать ее как услугу с ключом, она была успешно решена. Я просто пошел вперед и добавил регистрацию дизайнеров, и он работает, как ожидалось. Должно быть что-то другое между моим проектом и предоставленным образцом. Спасибо, и я буду работать, чтобы воссоздать и вернуться к вам. – QuietSeditionist

Смежные вопросы