2014-12-11 5 views
6

Der Autor bietet eine example wie Autofac mit MediatR in einer Konsolenanwendung verwenden:Wie verwende ich MediatR mit Autofac in 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); 

ich dieses Beispiel nahm und versucht, um es mit ASP MVC 5 und dem Autofac.Mvc5 Paket funktioniert:

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

Wenn ich die Webanwendung ausführen, erhalte ich eine Fehlerseite, die mir sagt, dass die ServiceLocationProvider Abhängigkeit nicht registriert wurde. Was mache ich falsch?

ich Verdächtiger, dass das Problem auf die Tatsache zurückzuführen ist, dass ich die ServiceLocatorProvider Instanz bin Registrierung nachBuild Aufruf - in dem Beispiel des Autors, die Build Methode wird aufgerufen, danach dank Lazy<>. Ich weiß jedoch nicht, wie ich das umgehen soll.

Antwort

0

Sie können Builder.Build nicht aufrufen, bevor Sie die Registrierung von Typen abgeschlossen haben.

In Ihrem Beispiel rufen Sie Builder.Build auf, bevor Sie builder.RegisterInstance aufrufen, was erklärt, warum es den Typ zur Laufzeit nicht ableiten kann.

kam ich mit diesem, nachdem das gleiche Problem heute schlagen, aber es wird daran gearbeitet, wie es meine Implementierungen lösen tut noch ...

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

Ich bin der Behälter in einem separaten Lazy<T> Erstellung und Weitergabe das herum.

Während diese Builds und die Seite lädt, kann sie nicht schließen, die Handler für die Anforderung in meinem Controller-Aktion zu verwenden ...

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

, die die Ausnahme auslöst ...

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

Dies geschieht mit der gleichen Konventionsbasierten Registrierung, die im Autofac-Beispielprojekt in MediatR enthalten ist, und ich habe auch versucht, es explizit zu registrieren.

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

Ich werde aktualisieren, wenn ich es funktioniere. Bitte machen Sie das gleiche, wenn Sie es herausfinden, bevor ich es tue.

3

Ich hatte Probleme, die Mediator und ServiceLocatorProvider Klassen ordnungsgemäß zu registrieren.
Ich zog meine Haare für eine Weile, aber schaffte es schließlich, um es herumkommen.

war mein Fehler ServiceLocatorProvider gegen die Wurzel Autofac Behälter zu registrieren, wie folgt aus:

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

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

Zur Laufzeit Autofac warf eine Ausnahme, weil einer meiner Request eine Abhängigkeit von meinem EF hatte DbContext, die ich konfiguriert durch HTTP-Anfrage definiert werden.

Der Trick besteht darin, die ServiceLocatorProvider gegen die aktuelle HTTP-Anfrage ILifetimeScope zu registrieren.
Glücklicherweise wird die Fehlermeldung vom Autofac ist selbsterklärend:

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. 

Dies geschieht, weil die AutofacServiceLocator mit dem Stammbehälter zugeführt wurde.
Der Container, der die DbContext auflösen will, hat keine Kenntnis von einem mit der aktuellen HTTP-Anforderung verknüpften Bereich.

Mit JustDecompile, ich sax, dass die einzige Klasse, die die ILifetimeScopeProvider Schnittstelle implementiert AutofacDependencyResolver, und Sie können auf die aktuelle Instanz mit der statischen Eigenschaft AutofacDependencyResolver.Current zugreifen.

Sie können die aktuellen ILifetimeScope von AutofacDependencyResolver.Current.RequestLifetimeScope mit Zugriff wie in der Fehlermeldung erklärt, so dass am Ende der Registrierung wie folgt aussieht:

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

Der InstancePerHttpRequest() Teil optional ist aber seit den ILifetimeScope wird das gleiche sein während Die gesamte HTTP-Anforderung verhindert, dass Autofac n Instanzen von AutofacServiceLocator erstellt.

Hoffe, das war klar, zögern Sie nicht, einige Änderungen zu machen, wenn Sie das Gefühl haben, dass es notwendig ist, weil es mir schwer fällt, dies klar zu erklären.

+0

Nice one, mickaeld. Mir war klar, danke. –

2

Ich benutze Webapi 2 + Autofac + OWIN und verwalten, damit es funktioniert. Hier ist mein Code:

Hier ist mein Autofac Constructor

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

hier meine Namensräume sind:

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; 

Alles hat gut funktioniert und nicht jedes Request oder Command registrieren musste EXPLICT. Da ich auch eine Menge Zeit verloren habe, um es an den Gast zu stellen, hoffe ich, dass es anderen helfen wird, das gleiche Problem zu haben. Frühere Antworten waren hilfreich, um zu diesem zu gelangen.

UPDATE:

Nun, ich de Code nur Refactoring entfernen alle faul Bindung es viel einfacher macht. Bellow sind die Änderungen:

Statt:

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

Verwenden Sie einfach:

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

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