BizTalk Orchestration Shape bei behandelten Exceptions ermitteln

09.10.2018

Wenn in einer Orchestration eine Exception geworfen wird, möchte man oft wissen, woher sie kommt. So geht's:

Unbehandelte Exception

Schauen wir zunächst, wie es sich verhält, wenn die Exception ungeschützt ist. Hierzu folgende einfache Orchestration:

 

Im Shape „Unguarded Ex“ wird von uns absichtlich eine ApplicationException durch einen C# Helper geworfen.

public static void ThrowApplicationException(String message)

{

    throw new ApplicationException(message);

}

Die entsprechende Orchestration Instanz wird durch die Exception suspendiert.


In der BizTalk Administration Console kann zu der suspendierten Instanz die
Fehlerbeschreibung angeschaut werden. Sehr schön ist der Shape Name „Unguarded Ex“ zu erkennen, aus dem die Exception stammt.


Behandelte Exception

Wie verhält es sich, wenn wir die Exception behandeln wollen?

Hierzu fügen wir der Orchestration einen Scope „Scope RiskyWork“ hinzu, in dem wir die „gefährliche Arbeit“ erledigen. Der Scope erhält einen Exception Handler „Catch Any Exception“ mit folgenden Eigenschaften.


Als Ganzes sieht die Orchestration dann so aus.

Im Exception Handler versuchen wir an den Shape Namen zu kommen, indem wir 2 BizTalk Funktionen miteinander kombinieren.

Microsoft.XLANGs.Core.Context.RootService.ExceptionLocation.ShapeID

Microsoft.XLANGs.Core.Context.RootService.FriendlyNameFromShapeId(shapeId)

Erstere sollte uns eine ShapeId geben, die zweite aus der ShapeId dann den lesbaren Shape Namen. Damit wir diese aufrufen können, benötigen wir im BizTalk Projekt eine Referenz auf Microsoft.XLANGs.RuntimeTypes:

Im Asn_Result Shape sieht das ganze dann so aus:

Das Ergebnis senden wir über einen SendPort ins Dateisystem.

Leider ist das Ergebnis überhaupt nicht zufriedenstellend. Wir erhalten nicht wie erhofft den Shape Namen der Exception (wie man anhand der Bezeichnung „ExceptionLocation.ShapeId“ denken könnte). Wir erhalten stattdessen „Cns_Result“, den Shape Name des Shapes, in dem wir die Exception behandeln.

<ns0:ResultProperties xmlns:ns0="ShapeInfoAtException.ResultProperties">

  <ResultText>Cns_Result</ResultText>

</ns0:ResultProperties>


Die Ursache hierfür ist, dass der „ExceptionLocation.ShapeID“ von der BizTalk Engine gleich als erstes im Shape gesetzt wird, für den Fall, dass es eine unbehandelte Exception gibt. Das hilft uns leider so nicht weiter.


Behandelte Exception mit Shape Name

Um an den Shape Namen dennoch zu kommen, können wir einen FirstChance Exception Handler in der Application Domain des Hosts registrieren. Hierzu setzen wir im Helper Projekt zunächst zwei Referenzen.



Und erweitern den Code wie folgt:

public class Helper

{

    private const String ExtendedDataShapeNameKey = "ExceptionShapeNameForInstance";

   

    static Helper()

    {

        AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;

    }

   

    private static void FirstChanceHandler(object sender, FirstChanceExceptionEventArgs e)

    {

        Microsoft.XLANGs.Core.Service rootService = Microsoft.XLANGs.Core.Service.RootService;

        String shapeId = rootService.ExceptionLocation.ShapeID;

        String shapeName = rootService.FriendlyNameFromShapeId(shapeId);

       

        rootService.SetExtendedData(ExtendedDataShapeNameKey, shapeName);

    }

   

    public static String GetExceptionShapeName()

    {

        Microsoft.XLANGs.Core.Service rootService = Microsoft.XLANGs.Core.Service.RootService;

        String shapeName = rootService.GetExtendedData(ExtendedDataShapeNameKey) as String;

        return shapeName;

    }

   

    public static void ThrowApplicationException(String message)

    {

        throw new ApplicationException(message);

    }

}

Im statischen Constructor static Helper() registrieren wir den FirstChanceHandler. Der FirstChanceHandler wird bei jeder aufgetretenen Exception aufgerufen, bevor nach ExceptionHandlern gesucht wird.

Im FirstChanceHandler wird nach der bereits beschriebenen Methode der Shape Name ermittelt und in den ExtendedData der Orchestration Instanz zwischengespeichert.

Im Asn_Result Shape wird der Shape Name dann mit Hilfe der GetExceptionShapeName Methode wieder hervorgeholt und im SendResult eingetragen:



Das finale Ergebnis sieht genau so aus, wie wir erhofft haben.

<ns0:ResultProperties xmlns:ns0="ShapeInfoAtException.ResultProperties">

  <ResultText>Unguarded Ex</ResultText>

</ns0:ResultProperties>


Zusammengefasst ist es uns gelungen, eine Exception zu behandeln und dennoch den Shape Name zu ermitteln, in dem die Exception entstanden ist. Dieser kann geloggt werden und kann bei der Ursachenanalyse sehr hilfreich sein, vorausgesetzt, die Shapes haben schöne Namen ;-)

Viel Spaß beim Coding!

Plamen Petrow
QUIBIQ Schweiz











 

 

 

 

zurück