2014-12-11 4 views
6

저자는 Autofac 사용하여 콘솔 응용 프로그램에서 MediatR을 사용하는 방법에 대한 example 제공ASP MVC 5에서 Autofac과 함께 MediatR을 어떻게 사용합니까?

:이 예를 데려 그것이 ASP MVC (5)와 Autofac.Mvc5 패키지와 함께 작동하도록을 시도
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); 

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 종속성이 등록되지 않았다는 오류 페이지가 표시됩니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

그 문제는 내가이 Build를 호출 한 후 ServiceLocatorProvider 예를 를 등록하고 때문이다 의심 - 저자의 예에서 Build 방법은 Lazy<>에 나중에 감사를 호출됩니다. 하지만이 문제를 해결하는 방법을 모르겠습니다.

답변

0

유형 등록을 완료하기 전에 Builder.Build를 호출 할 수 없습니다.

예에서 builder.RegisterInstance를 호출하기 전에 Builder.Build를 호출하여 런타임에 유형을 유추 할 수없는 이유를 설명합니다.

는 오늘 같은 문제를 타격 한 후이 함께했다,하지만 내 구현을 해결 아직 나던로는 ...

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 "" 

이것은 MediatR에 포함 된 Autofac 예제 프로젝트에서 제공하는 것과 동일한 규칙에 기반한 등록을 사용하고 있으며, 나는 또한 명시 적으로 등록하려고 시도했습니다 ....

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

제대로 작동하면 업데이트 할 예정입니다. 내가하기 전에 알아 내면 똑같이하십시오.

3

MediatorServiceLocatorProvider 클래스를 제대로 등록하는 데 문제가있었습니다.
나는 잠시 동안 내 머리카락을 뽑았지만 마침내 그럭저럭 나갈 수 있었다.

내 실수는 다음과 같이 루트 Autofac 컨테이너에 대해 ServiceLocatorProvider을 등록했다 : 내 Request 중 하나가 I가 구성 내 EF DbContext에 대한 종속성이 있었기 때문에

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

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

, Autofac는 예외를 던지고 HTTP 요청에 의해 범위가 지정됩니다.

트릭은 을 현재 HTTP 요청 ILifetimeScope에 등록하는 것입니다. AutofacServiceLocator이 루트 컨테이너가 공급 되었기 때문에이 문제가 발생

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. 

:
다행히, Autofac에서 오류 메시지가 자체 설명이다.
컨테이너는 DbContext을 해결할 때 현재 HTTP 요청 범위와 관련된 내부 정보를 가지고 있지 않습니다.

JustDecompile을 사용하여 ILifetimeScopeProvider 인터페이스를 구현하는 유일한 클래스는 AutofacDependencyResolver이고 정적 속성 AutofacDependencyResolver.Current을 사용하여 현재 인스턴스에 액세스 할 수 있습니다.

오류 메시지에 설명 된대로처럼 결국 등록이 보이는, 그래서 당신은 AutofacDependencyResolver.Current.RequestLifetimeScope을 사용하여 현재 ILifetimeScope에 액세스 할 수 있습니다

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

InstancePerHttpRequest() 부분은 선택 사항이지만 ILifetimeScope 이후 동안 동일합니다 전체 HTTP 요청으로 인해 Autofac이 AutofacServiceLocator의 n 개의 인스턴스를 생성하지 못하게합니다.

희망 사항이 분명하기를 바랍니다. 필요하다고 생각하면 주저하지 말고 자세히 설명해주십시오.

+0

니스 하나, mickaeld 우는 소리가 변경됩니다. 나에게 분명했다. 그래서 고마워. –

2

저는 Webapi 2 + Autofac + OWIN을 사용하고 있습니다.

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; 

모든 것이 잘 작동하고 RequestHandler를 또는 CommandHandler 모든 등록 EXPLICT했다하지 않았다 : 여기

 //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); 

내 네임 스페이스입니다

다음

이 생성자

내 autofac입니다 : 여기 내 코드입니다. 나는 또한 그것을 구걸하는 데 많은 시간을 잃어 버렸기 때문에 같은 문제가있는 다른 사람들을 도울 수 있기를 희망한다. 과거의 답변이 도움이되었습니다.

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);