2016-11-03 5 views
1

Da ich einen Web/SOAP-Service habe, wie richte ich einen richtigen Transaktionskontext für Rebus (den Messaging-Bus) ein und löse ihn aus? Wenn Rebus einen Message-Handler aufruft, ist dies kein Problem, da Rebus den Transaktionskontext vor dem Aufruf des Handlers einrichten wird - aber was ist mit dem Gegenteil, wenn ein Web-Service-Handler eine Nachricht über Rebus senden/veröffentlichen muss?Wie setze ich den Rebus-Transaktionskontext für einen Web-Service?

Ich bin nicht daran interessiert, wie man ein HTTP-Modul oder ähnliches implementiert - nur die Grundlagen rund um Rebus: Was ist nötig, um Rebus für das Senden einer Nachricht vorzubereiten?

Der Web-Service-Code hat eine eigene Transaktion, wenn er mit der Anwendungsdatenbank kommuniziert. Ich muss in der Lage sein, Rebus einzurichten, wenn ich die Datenbanktransaktion einrichte und Rebus commit/rollback, wenn ich dasselbe mit der Datenbank mache.

Ich habe ein ähnliches Problem mit Standalone-Befehlszeilenprogrammen, die sowohl Interaktion mit einer Datenbank und Senden von Rebus-Nachrichten benötigt.

Antwort

1

Rebus wird Sende- und Veröffentlichungsvorgänge automatisch in seinem eigenen "Umgebungstransaktionskontext" eintragen, auf den über die statische Eigenschaft (*) AmbientTransactionContext.Current zugegriffen wird.

Sie könnten ITransactionContext selbst implementieren, wenn Sie wollten, aber Rebus kommt mit DefaultTransactionContext in der Box.

Sie verwenden es wie folgt aus:

using(var context = new DefaultTransactionContext()) 
{ 
    AmbientTransactionContext.Current = context; 

    // send and publish things in here 

    // complete the transaction 
    await context.Complete(); 
} 

, die leicht zum Beispiel genommen werden konnte in einer OWIN-Middleware oder ähnlichem.


(*) Das Objekt ist statisch, aber der zugrunde liegende Wert wird auf den aktuellen Ausführungskontext gebunden (durch CallContext.LogicalGet/SetData verwendet wird), was bedeutet, dass Sie daran denken können als fades gebunden, mit der schönen Eigenschaft, dass es fließt wie erwartet in Fortsetzungen.

In Rebus 2.0.2 ist es möglich, die Zugriffsmethoden anpassen verwendet, um den Kontext zu bekommen/Set von AmbientTransactionContext.SetAccessors(...) mit einem Action<ITransactionContext> Aufruf und einem Func<ITransactionContext>, z.B. wie folgt aus:

AmbientTransactionContext.SetAccessors(
    context => { 
     if (HttpContext.Current == null) { 
      throw new InvalidOperationException("Can't set the transaction context when there is no HTTP context"); 
     } 
     HttpContext.Current.Items["current-rbs-context"] = context 
    }, 
    () => HttpContext.Current?.Items["current-rbs-context"] as ITransactionContext 
); 

in diesem Fall, die sie in einer Art und Weise macht Arbeit, die richtig selbst fließt, wenn alte Schule HTTP-Modulen;)

+0

Dank. Es half bis zu einem gewissen Grad ... für normale synchrone ASP MVC 5 Controller-Methoden funktioniert es gut: AmbientTransactionContext.Current ist vor und nach dem Controller-Aufruf gleich. Aber wenn die Controller-Methode 'asyncTask ' ist und "bus.Publish (msg) abwartet", dann ist AmbientTransactionContext.Current nach dem Controller-Aufruf NULL. AmbientTransactionContext.Current wird in einem HTTP-Modul begin/end-request verwaltet. –

+0

"AmbientTransactionContext.Current wird in einem HTTP-Modul begin/end-request" ... Das ist wahrscheinlich nicht gut dann - ASP.NET ist bekannt, um Threads zu lustigen Zeiten zu wechseln, und anscheinend ist nicht garantiert, dass die Web-Anfrage Der Handler wird mit demselben Ausführungskontext wie das HTTP-Modul ausgeführt. Sie sollten wahrscheinlich einen anderen Ort auswählen, um den Kontext zu erstellen – mookid8000

+0

Okay, ich habe die Idee. Refactoring jetzt um den contex in HttpContext.Current.Items zu speichern. Fragst du dich aber, ob etwas in Rebus AmbientTransactionContext.Current anzeigt und fehlschlägt? Ist der Code innerhalb von Publish() zwei verschiedene Transaktionen, wenn ich zwei Bus.Publish() in einer Anfrage mache? –

Verwandte Themen