Ich habe ein paar Muster verwendet, die auf dem Konzept der Kindcontainer/Scopes beruhen (abhängig von der Terminologie Ihres IoC-Containers Ihrer Wahl). Ich bin mir nicht sicher, welche es unterstützt, aber ich kann Ihnen sagen, dass StructureMap 2.6.x und AutoFac tun.
Die Idee besteht darin, einen untergeordneten Bereich für jede eingehende Nachricht hochzufahren, einen beliebigen Kontext für diese Anforderung einzufügen, das Objekt der obersten Ebene aus dem untergeordneten Bereich aufzulösen und dann den Prozess auszuführen.
Hier ist ein verallgemeinerter Code, der es mit AutoFac zeigt. Es führt eine direkte Auflösung aus dem Container aus, ähnlich wie das Anti-Pattern, das Sie vermeiden möchten, aber es wurde an einer Stelle isoliert.
In diesem Fall verwendet es einen ServiceBusTrigger, um den Job auszulösen, könnte aber alles Mögliche sein - ein Job-Host könnte möglicherweise eine Liste von diesen für die verschiedenen Warteschlangen/Prozesse haben.
public static void ServiceBusRequestHandler([ServiceBusTrigger("queuename")] ServiceBusRequest request)
{
ProcessMessage(request);
}
Diese Methode wird von allen Instanzen der oben genannten Methoden aufgerufen. Es wird die Erstellung des untergeordneten Bereichs in einem Verwendungsblock umbrochen, um sicherzustellen, dass die Objekte bereinigt werden. Dann würden alle Objekte, die je Anforderung variieren und den Kontext enthalten, der von anderen Abhängigkeiten verwendet wird (Benutzer-/Client-Informationen usw.), erstellt und in den untergeordneten Container (in diesem Beispiel IRequestContext) eingefügt. Schließlich wird die Komponente, die die Arbeit ausführt, vom untergeordneten Container aufgelöst.
private static void ProcessMessage<T>(T request) where T : IServiceBusRequest
{
try
{
using (var childScope = _container.BeginLifetimeScope())
{
// create and inject things that hold the "context" of the message - user ids, etc
var builder = new ContainerBuilder();
builder.Register(c => new ServiceRequestContext(request.UserId)).As<IRequestContext>().InstancePerLifetimeScope();
builder.Update(childScope.ComponentRegistry);
// resolve the component doing the work from the child container explicitly, so all of its dependencies follow
var thing = childScope.Resolve<ThingThatDoesStuff>();
thing.Do(request);
}
}
catch (Exception ex)
{
}
}
Können Sie ein wenig näher erläutern? Versuchen Sie, einen "pro-Job" -Bereich für Objekte zu erhalten, die aus Ihrem Container kommen, ähnlich einer pro-Anfrage in einer Standard-Web-App? – Veatch
Ja. Ich habe die Frage bearbeitet. Bitte beachten Sie den Blog-Post, den ich für weitere Details verlinkt habe. –
Wenn Sie davon ausgehen, dass Sie eine Konsolenanwendung ausführen, sollten Sie DI wie in jeder Konsolenanwendung verwenden. Davon abgesehen ist die einzige Methode, die ich gefunden habe, etwas Ähnliches wie das Anti-Pattern im Blog-Post zu verwenden. Ich kann ein Beispiel mit Ninject auf Anfrage geben. – lopezbertoni