Nun kann man ja eine BizTalk Orchestration schon vorzeitig verlassen, mit Hilfe des Suspend-Shapes (https://msdn.microsoft.com/en-us/library/aa560868.aspx), oder der Terminate-Shapes (https://msdn.microsoft.com/en-us/library/ee294389.aspx). Allerdings sind beide Shapes nur für Fehlersituationen vorgesehen. Was also tun, wenn in einer größeren Orchestration z.B. bei unterschiedlichen Bedingungen der Ablauf an verschiedenen Stellen vorzeitig (und erfolgreich) beendet werden sollte?
Zur Not kann man natürlich die Terminate-Shapes missbrauchen. Dann sind jedoch „erfolgreich“ terminierte von wirklich fehlerhaften Orchestration-Instanzen beim Orchestration-Tracking schwer zu unterscheiden. Oder man kann mit Dutzenden Decide-Shapes den schwer zu überblickenden Programmablauf bis zum bitteren erfolgreichen Ende führen. Nicht wirklich schön. Als Lösung (oder wenn man will, Workaround, bis es ein Return-Shape gibt ;-) haben wir folgenden Ansatz erfolgreich verwendet.
Exception Typ
In einem kleinen C# Helper-Projekt basteln wir eine minimale Exception. Diese repräsentiert kein Problem, sondern ein erfolgreiches Ende.
[Serializable]
public class ExitWithSuccessException : Exception
{
public ExitWithSuccessException() {}
public ExitWithSuccessException(SerializationInfo info, StreamingContext context)
: base(info, context) {}
}
Zu bemerken sind die beiden Konstruktoren: Mit dem parameterlosen Konstruktor kann eine Exception-Instanz von der Orchestration direkt instanziiert werden. Der Konstruktor mit den Serialisierungs-Parametern wird im Falle von Dehydration/Rehydration benötigt, damit BizTalk beim Aufwachen der Orchestration-Instanz die Exception deserialisieren kann.
Exception Variable
Wir erzeugen in der Orchestration eine Variable vom Typ dieser Exception, z.B. SuccessException genannt.
Global Scope mit Exception Handler
Wir legen die komplette Orchestration in einen Scope mit einem Exception Handler, in dem nur Exceptions vom Typ der ExitWithSuccessException gefangen werden.
Throw to Exit
An jeder Stelle, an der ein Early Exit benötigt wird, werfen wir mit Hilfe eines Throw Shapes die SuccessException. Dieses Throw Shape repräsentiert dann das erfolgreiche Return.
Demo
Voila,das war’s schon! Eine komplette einfache Demo eines beispielhaften Ablaufs passt auf eine Seite.
Details können nun selbstverständlich ausgeschmückt werden. Z.B. können verschiedene Exception Typen sinnvoll sein (für Erfolg, für Warning oder doch für Fehler – dann mit anderer Behandlung…) oder es kann zum Erzeugen der Exceptions ein kleiner C# Helper verwendet werden, um z.B. interessante Infos in die Exception zu stecken oder diese Infos auszugeben. Statt des Throw-Shapes wird dieser Helper dann in einem Expression-Shape aufgerufen.
Viel Spaß beim Umsetzen. Wir freuen uns darauf, von Euren Erfahrungen und Ideen zu hören!