2014-12-11 4 views
6

Автор предоставляет example о том, как использовать MediatR в консольное приложение с помощью Autofac:Как использовать MediatR с Autofac в ASP MVC 5?

var builder = new ContainerBuilder(); 
builder.RegisterSource(new ContravariantRegistrationSource()); 
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces(); 
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces(); 
builder.RegisterInstance(Console.Out).As<TextWriter>(); 

var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(builder.Build())); 
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value); 
builder.RegisterInstance(serviceLocatorProvider); 

Я взял этот пример и попытался, чтобы заставить его работать с ASP MVC 5 и Autofac.Mvc5 пакет:

var builder = new ContainerBuilder(); 
builder.RegisterSource(new ContravariantRegistrationSource()); 
builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces(); 
builder.RegisterAssemblyTypes(typeof(AddPostCommand).Assembly).AsImplementedInterfaces(); 
builder.RegisterControllers(typeof(HomeController).Assembly); 
var container = builder.Build(); 
var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(container)); 
var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value); 
builder.RegisterInstance(serviceLocatorProvider); 
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 

Когда я запускаю веб-приложение, я получаю страницу с сообщением об ошибке, указывающую, что зависимость ServiceLocationProvider не зарегистрирована. Что я делаю не так?

Я подозреваемого, что проблема связана с тем, что я регистрирующим ServiceLocatorProvider экземпляра после вызова Build - в примере автора, метод Build вызывается после благодаря Lazy<>. Однако я не знаю, как обойти это.

ответ

0

Вы не можете позвонить в Builder.Build, прежде чем завершить регистрацию типов.

в вашем примере вы вызываете Builder.Build перед вызовом builder.RegisterInstance, который объясняет, почему он не может вывести тип во время выполнения.

Я пришел с этим после удара один и тот же вопрос сегодня, но работа продолжается, как оно не решить мои реализации еще ...

builder.RegisterSource(new ContravariantRegistrationSource()); 
     builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces(); 
     builder.RegisterAssemblyTypes(typeof(HomePageThumbnail).Assembly).AsImplementedInterfaces(); 

     var lifetimeScope = new Lazy<ILifetimeScope>(() => builder.Build()); 
     var lazy = new Lazy<IServiceLocator>(() => new AutofacServiceLocator(lifetimeScope.Value)); 

     var serviceLocatorProvider = new ServiceLocatorProvider(() => lazy.Value); 
     builder.RegisterInstance(serviceLocatorProvider); 


     DependencyResolver.SetResolver(new AutofacDependencyResolver(lifetimeScope.Value)); 

     app.UseAutofacMiddleware(lifetimeScope.Value); 
     app.UseAutofacMvc(); 

Я создаю контейнер в отдельном Lazy<T> и мимоходом это вокруг.

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

var response = _mediator.Send(new RecentActivityThumbnailsQuery()); 

, который вызывает исключение ...

An exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in Microsoft.Practices.ServiceLocation.dll but was not handled in user code 

Additional information: Activation error occurred while trying to get instance of type IRequestHandler`2, key "" 

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

builder.RegisterType<RecentActivityThumbnailsHandler>().As<IRequestHandler<RecentActivityThumbnailsQuery, RecentActivityThumbnailsResults>>(); 

Я буду обновлять, когда я получу его работу. Пожалуйста, сделайте то же самое, если вы это выясните, прежде чем я это сделаю.

3

У меня были проблемы, чтобы правильно зарегистрировать классы Mediator и ServiceLocatorProvider.
Я потянул волосы на некоторое время, но, наконец, удалось обойти его.

Моя ошибка была зарегистрировать ServiceLocatorProvider против корневой Autofac контейнера, например:

var lazyContainer = new Lazy<IContainer>(() => builder.Build()); 
builder.Register(x => new ServiceLocatorProvider(() => new AutofacServiceLoator(lazyContainer.Value))); 

DependencyResolver.SetCurrent(new AutofacDependencyResolver(lazyContainer.Value); 

Во время выполнения Autofac бросает исключение, потому что один из моих Request имел зависимость от моей EF DbContext что я настроен на быть охвачены HTTP-запросом.

Хитрость заключается в регистрации ServiceLocatorProvider против текущего HTTP-запроса ILifetimeScope.
К счастью, сообщение об ошибке от Autofac является Спроецировать

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance 
was requested. This generally indicates that a component registered as per-HTTP request is being 
requested by a SingleInstance() component (or a similar scenario.) Under the web integration 
always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, 
never from the container itself. 

Это происходит потому, что AutofacServiceLocator подавались с корневым контейнером.
Контейнер при запросе разрешения DbContext не знает о внутреннем - связанном с текущим HTTP-запросом - областью.

Использование JustDecompile, я саксофон, что единственный класс, который реализует интерфейс ILifetimeScopeProvider был AutofacDependencyResolver, и вы можете получить доступ к текущему экземпляру со статическим свойством AutofacDependencyResolver.Current.

Вы можете получить доступ к текущему ILifetimeScope с помощью AutofacDependencyResolver.Current.RequestLifetimeScope, как поясняется в сообщении об ошибке, так что в конце регистрации выглядит следующим образом:

builder 
    .Register(x => new ServiceLocatorProvider(() => new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope))) 
    .InstancePerHttpRequest(); 

InstancePerHttpRequest() часть не является обязательным, но с ILifetimeScope будет то же самое во время весь HTTP-запрос, это предотвращает создание Autofac из n экземпляров AutofacServiceLocator.

Надеюсь, что это было ясно, не стесняйтесь делать некоторые изменения, если вы чувствуете, что это необходимо, потому что мне трудно объяснить это ясно.

+0

Nice один, mickaeld. Мне было ясно, спасибо. –

2

Я использую Webapi 2 + Autofac + OWIN и получаю его работу. Вот мой код:

Вот мой autofac Конструктор

 //Constructor 
     var builder = new ContainerBuilder(); 

     builder.RegisterSource(new ContravariantRegistrationSource()); 
     builder.RegisterAssemblyTypes(typeof(IMediator).Assembly).AsImplementedInterfaces(); 
     builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces(); 

     // Register Web API controller in executing assembly. 
     builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest(); 


     var lazyContainer = new Lazy<IContainer>(() => builder.Build()); 
     var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value)); 
     builder.RegisterInstance(serviceLocatorProvider); 
     config.DependencyResolver = new AutofacWebApiDependencyResolver(lazyContainer.Value); 


     // This should be the first middleware added to the IAppBuilder. 
     app.UseAutofacMiddleware(lazyContainer.Value); 

     // Make sure the Autofac lifetime scope is passed to Web API. 
     app.UseAutofacWebApi(config); 

Вот мои пространств имен:

using System; 
using System.Reflection; 
using System.Web.Http; 
using Autofac; 
using CommonServiceLocator.AutofacAdapter.Unofficial; 
using Autofac.Features.Variance; 
using Autofac.Integration.WebApi; 
using MediatR; 
using Microsoft.Practices.ServiceLocation; 
using Owin; 

Все работало хорошо, и не пришлось explict зарегистрировать каждый RequestHandler или CommandHandler. Поскольку я также потерял много времени, чтобы поместить его в список, я надеюсь, что это поможет другим, имеющим ту же проблему. Предыдущие ответы были полезны, чтобы добраться до этого.

UPDATE:

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

Вместо:

 var lazyContainer = new Lazy<IContainer>(() => builder.Build()); 
     var serviceLocatorProvider = new ServiceLocatorProvider(() => new AutofacServiceLocator(lazyContainer.Value)); 
     builder.RegisterInstance(serviceLocatorProvider); 

Просто используйте:

 builder.RegisterType<AutofacServiceLocator>().AsImplementedInterfaces(); 
     var container = builder.Build(); 

     //ServiceLocator.SetLocatorProvider(serviceLocatorProvider);    
     config.DependencyResolver = new AutofacWebApiDependencyResolver(container);