Ich verwende WebAPI + Autofac + Automapper mit einem Repository für den Datenzugriff. Ich muss meinen Domain-Entitäten ein Modell zuordnen, insbesondere muss ich einen Identitätswert in die tatsächliche Entität konvertieren. Keine große Sache, oder? Ich habe das in MVC ohne Probleme gemacht. Ich werde vereinfachen, was ich mache, um das Wesentliche zu enthüllen.
%Vor% Repositories sind bei Autofac registriert und werden wegen der Sitzungs- / Transaktionsverwaltung als InstancePerApiRequest
verwaltet. Also muss ich meinen Konverter im selben Umfang registrieren:
Die Automapper-Konfiguration sieht ungefähr so aus:
%Vor% Also hier ist der Teil, der saugt. Ich muss verstehen, dass Automapper den ConstructServicesUsing
Guy benötigt, bevor du deine Config erstellst. Wenn Sie es später einstellen, wird es nicht verwendet. Das obige Beispiel funktioniert nicht, da container
der Root-Bereich ist. Wenn ich versuche, EntityConverter<TestEntity>
aufzulösen, wird sich Autofac darüber beschweren, dass der angeforderte Typ für einen anderen Bereich registriert ist, und der, in dem Sie sich befinden, ist es nicht. Macht Sinn, ich möchte den von WebApi erstellten Bereich.
Lassen Sie mich eine Sekunde pausieren und eine Tatsache über die WebApi-Abhängigkeitsinjektion behandeln (ich glaube nicht, dass dies Autofac-spezifisch ist). WebApi erstellt eine IDependencyScope
für die Anfrage und speichert sie in HttpRequestMessage.Properties
. Ich kann es nicht wieder zurückbekommen, wenn ich nicht auf dieselbe HttpRequestMessage
-Instanz zugreifen kann. Mein AsInstancePerApiRequest
scoping auf IRepository
und mein Konverter verlassen sich daher auf IDependencyScope
.
Also, das ist wirklich das Fleisch und die Kartoffeln des Problems, und ich frustrierte wirklich mit diesem Unterschied von MVC. Du kannst es nicht tun
%Vor% Das entspricht der Verwendung von container.Resolve
. Ich kann nicht
weil A), das einen neuen Bereich neben dem einen erstellt, den ich eigentlich möchte, B) lässt mich nicht wirklich den neuen Bereich aufräumen, den ich erstellt habe. Die Verwendung von Service Locator ist eine neue Möglichkeit, das gleiche Problem zu haben. Ich komme nicht zu dem Umfang, den WebApi benutzt. Wenn mein Konverter und seine Abhängigkeiten eine einzelne Instanz oder eine Instanz pro Abhängigkeit wären, wäre das kein Problem, aber sie sind es nicht, so ist es, und das Ändern würde viele Probleme für mich erzeugen.
Jetzt kann ich AutoMapper config mit Autofac erstellen und es als eine einzelne Instanz registrieren. Ich kann sogar pro-Anfrage IMappingEngine
Instanzen erstellen. Aber das bringt mir nichts, wenn der Dienstkonstruktor immer den einzigen Delegaten verwendet, den Sie am Anfang registrieren, der keinen Zugriff auf den aktuellen Bereich hat. Wenn ich diesen Delegaten für jede Mapping-Engine-Instanz ändern könnte, könnte ich geschäftlich tätig sein. Aber ich kann nicht.
Also was kann ich tun?
Eine weitere Option, die dieses Mal eingebaut wird, ist die Verwendung der pro-map-Optionen:
%Vor%Berücksichtigen Sie nicht die globale IoC-Konfiguration in Ihrer Mapping-Konfiguration.
Eine andere Option ist die Verwendung Ihres IoC-Tools, um zu konfigurieren, wie die MappingEngine instanziiert wird:
%Vor%Der erste ist nur Mapper.Configuration, der zweite sollte wahrscheinlich ein Singleton sein und der dritte, den Sie mit der aktuellen geschachtelten Container-Auflösung ausfüllen können. Dies würde es vereinfachen, die Map-Überladung jedes Mal aufzurufen.
Update: Der Automapper wurde aktualisiert, um diese Funktion zu unterstützen. Siehe @Jimmy Bogards Antwort
Diese Lösung könnte nicht sehr nett sein, aber es funktioniert. Die Lösung bezieht sich auf WebAPI 2, über frühere Versionen bin ich mir nicht sicher.
In WebAPI 2 können Sie die aktuelle IDependencyScope
von der aktuellen HttpRequestMessage
via GetDependencyScope()
Erweiterungsmethode abrufen. Der aktuelle HttpRequestMessage
wird in der Eigenschaft Items
des aktuellen HttpContext
gespeichert. Zu wissen, dass Ihre Fabrik aussehen könnte:
Dies kann oder kann nicht für Sie geeignet sein .. aber hier geht:
Wir haben das kürzlich gemacht .. für Modellbinder in MVC. Unsere Modellbinder (auf GET-Anfragen) verwenden jetzt Ninject-Managed Services, um Modelle zu erstellen.
Im Grunde injizieren wir eine Fabrik (mit Ninjects Factories-Erweiterung ... vielleicht gibt es eine ähnliche für Autofac) in eine "AutomapperBootstrapper" -Klasse, die wiederum Automapper-Mapping Profile
erstellt und sie zu Automapper hinzufügt. Etwas so:
Die Zuordnungen Profile
selbst verwenden MapFrom()
, was jedes Mal ausgewertet wird, wenn eine Zuordnung stattfindet. Etwas wie das:
Jedes Mal, wenn der Modellbinder gestartet wird, werden alle Abhängigkeiten für die Anfrage von Ninject noch verdrahtet und alles wird gefiltert.
(Für diejenigen, die daran interessiert sind, lässt uns dieses Setup im Wesentlichen Folgendes tun: /Area/Controller/Action/12
, und unsere Methode für die Controller-Aktion ist dies:
).
Tags und Links asp.net-web-api c# dependency-injection autofac automapper