Workflowdienste

Visueller Entwurf von Workflows mit WCF und WF 4

Leon Welicki

Herunterladen des Codebeispiels.

Die Entwickler verwenden zunehmend die dienstorientierte Architektur (SOA, Service-Oriented Architecture) als Möglichkeit zum Erstellen von verteilten Anwendungen. Für die Uneingeweihten kann das Entwerfen und Implementieren von dienstorientierten, verteilten Anwendungen eine schwierige Aufgabe darstellen. Jedoch ist es mit Microsoft .NET Framework 4 einfacher als jemals zuvor, WCF-Dienste (Windows Communication Foundation) mithilfe von Windows Workflow Foundation (WF) zu implementieren.

WCF-Workflowdienste bieten eine produktive Umgebung für das Erstellen von langfristig ausführbaren, dauerhaften Vorgängen und Diensten, bei denen es wichtig ist, ein Anwendungsprotokoll über das Erstellen einer Reihenfolge der Vorgänge zu erzwingen. Workflowdienste werden mithilfe von WF-Aktivitäten implementiert, mit denen WCF zum Senden und Empfangen von Daten verwendet werden kann.

In diesem Artikel möchte ich erläutern, wie mehrere WCF- und WF-Features kombiniert werden, die in .NET Framework 4 zur Modellierung eines langfristig ausführbaren, dauerhaften und instrumentierten Hypothekengenehmigungsprozesses für ein Immobilienunternehmen eingeführt wurden, ohne Code schreiben zu müssen. Dieser Artikel soll weder als allgemeine Einführung in WCF oder WF noch als schrittweise Anleitung für den gesamten Prozess des Erstellens einer Arbeitslösung dienen. Stattdessen konzentriere ich mich anhand eines praktischen Geschäftsszenarios auf die Bedeutung neuer .NET Framework 4-Features. Sie finden eine vollständige Arbeitslösung im Codedownload für diesen Artikel.

Das Szenario

Wir beginnen mit der Beschreibung des Szenarios, auf Grundlage dessen die Workflowanwendung erstellt wurde. Contoso Housing ist ein Immobilienunternehmen, das Häuser und Eigentumswohnungen verkauft. Um einen besseren Kundendienst und eine durchgängige Betreuung der Käufer zu gewährleisten, bildet Contoso Partnerschaften mit drei Hypothekenunternehmen, die potenzielle Kunden bei ihren Hypothekenanfragen unterstützen. Jedes Hypothekenunternehmen bietet verschiedene Zinssätze. Contoso priorisiert die Hypothekenanbieter nach Zinssätzen, um sicherzustellen, dass die Kunden die besten Konditionen erhalten (unter der Annahme, dass das Haus mit einem besseren Zinssatz besser zu verkaufen ist).

Die Kunden senden ihre Hypothekenanfragedaten über eine Webanwendung. Jeder Kunde gibt eine Kunden-ID, den Preis des Hauses, den Betrag der Abzahlungsraten, die Leihfrist in Jahren, die Lohn- und Gehaltsdaten sowie einige Hintergrundinformationen zur Überprüfung an.

Im ersten Schritt des Anwendungsworkflows (siehe Abbildung 1) werden die vom Kunden eingegebenen Daten verwendet, um den Kunden zu prüfen und die Eignung vor dem Senden der Anfrage an die Hypothekenanbieter zu ermitteln.

Figure 1 The Mortgage Approval Process
Abbildung 1 Der Hypothekengenehmigungsprozess

Die Anwendung folgt diesen Regeln:

  • Falls gegen den Antragsteller Zwangsvollstreckungsmaßnahmen bestehen, wenn er insolvent ist oder sich in einem Gerichtsverfahren befindet, wird der Antrag abgelehnt.
  • Falls der Antragsteller keine Bonitätsgeschichte vorweisen kann und eine Teilzahlung von weniger als 20 Prozent leistet, wird der Antrag zur Prüfung zurückgesendet (fehlerhafter Antrag), jedoch nicht abgewiesen. Der Kunde muss eine Teilzahlung von mindestens 20 Prozent zur Verfügung stellen, um fortfahren zu können.
  • Falls keiner der obigen Punkte zutrifft, wird der Antrag genehmigt.

Die Hypothekenanbieter werden entsprechend der bevorzugten Reihenfolge von Contoso für die Beantragung der Hypothekenanfrage kontaktiert. Falls ein Hypothekenanbieter den Antragsteller ablehnt, wird der nächste gefragt. Es gibt einen Standarddienstvertrag für Hypothekengenehmigungsanfragen, der von allen Anbietern implementiert wird. Während dieser Phase im Prozess sollten die Kunden den Status ihrer Anfrage abfragen können.

Sobald der Hypothekenantrag gelöst wurde (ein Anbieter hat akzeptiert oder alle haben abgelehnt), wird die Kundeninteraktion über einen entsprechenden Dienst im CRM-System von Contoso aufgezeichnet. Das Ergebnis wird dem Kunden zurückgesendet.

Beachten Sie, dass der Hypothekengenehmigungsprozess, der in Abbildung 1 zu sehen ist, eine allgemeine Beschreibung des Geschäftsprozesses darstellt, jedoch nicht zeigt, wie er implementiert wird. Der Workflowdienst wird eine Implementierung dieses Prozesses sein.

Erstellen von deklarativen Diensten

Der Workflowdienst erhält Daten vom Kunden, führt die erste Prüfung durch, koordiniert das Gespräch mit den Hypothekenanbietern, registriert die Interaktion im CRM-Dienst und legt dem Kunden das Ergebnis offen.

Der Dienst wird langfristig ausführbar (er kann Tage oder Monate bis zum Abschluss dauern), dauerhaft (er kann den Status speichern und zu einem späteren Zeitpunkt daran anknüpfen) und instrumentiert sein (sowohl Entwickler als auch Benutzer wissen, was abläuft, ohne dass ein Debugging des Dienstes erforderlich ist). Durch die Verwendung von WCF und WF können Sie all dies deklarativ erreichen, ohne Code schreiben zu müssen. Sie müssen nur von .NET Framework bereitgestellte Komponenten zusammenstellen und konfigurieren. Abbildung 2 zeigt ein Diagramm der Lösung.

Figure 2 Architecture of the Solution
Abbildung 2 Architektur der Lösung

Ein WCF-Workflowdienst ist in einer XAMLX-Datei enthalten, die den Workflow definiert. Sie können Geschäftsprozesse visuell mithilfe von WF Designer definieren. Der Dienstvertrag wird auf der Grundlage der Workflowstruktur abgeleitet.

Um einen Workflowdienst in Visual Studio 2010 zu erstellen, erzeugen Sie ein neues Projekt und wählen dann die Vorlage „WCF Workflow Service Application“ aus. Die Projektvorlage erstellt einen sehr einfachen (aber ausgeführten) Workflow mit den Aktivitäten „Receive“ (Empfangen) und „SendReply“ (Senden/Antworten). Dies ähnelt einer Klasse mit einer Methode, die eine Ganzzahl empfängt und eine Zeichenfolge zurückgibt. Sie können den Workflow erweitern, indem Sie weitere Aktivitäten ergänzen. Diese Aktivitäten können Ausführungslogik und Dienstvorgänge hinzufügen.

Verwenden Sie zur Definition des Dienstvertrags die von WF bereitgestellten Messaging-Aktivitäten. Die Dienstkonfiguration ist wie bei normalen WCF-Diensten in der Datei „Web.config“ gespeichert. Wenn Sie die Datei „Web.config“ öffnen, sehen Sie eine sehr saubere Konfigurationsdatei, da die WCF-Workflowdienste die Vorteile der Dienstkonfigurationsverbesserungen nutzen, die in WCF 4 eingeführt wurden.

Die Messaging-Aktivitäten kombinieren WF und WCF nahtlos. Sie wurden entworfen, um die nachrichtenorientierten Workflows zu unterstützen und eine bessere Integration von Messaging in Workflows zu gewährleisten. Messaging-Aktivitäten ermöglichen Workflows das Senden von Daten an andere Systeme (Send, SendReply und SendAndReceiveReply) und das Empfangen von Daten aus anderen Systemen (Receive, ReceiveReply und ReceiveAndSendReply). Sie umfassen auch Aktivitäten für die Arbeit mit Korrelation (InitializeCorrelation, CorrelationScope) und Transaktionen (TransactedReceiveScope).

Receive- und Send-Aktivitäten ermöglichen die Modellierung der Messaging-Interaktionen innerhalb eines Workflows. Der Vertrag in einem Dienst kann anhand der Konfiguration der Receive- und Send-Aktivitäten definiert werden. Jeder Receive-Vorgang wird als Operation verfügbar gemacht. Jede Send-Aktivität sendet eine Nachricht an einen Dienst. Der Zieldienst muss nicht WCF oder sogar .NET Framework verwenden, da Sie über die Standardprotokolle damit interagieren.

Send und Receive können so konfiguriert werden, dass entweder ein nachrichten- oder ein parameterbasierter RPC-Ansatz zum Empfangen und Senden der tatsächlichen Daten verwendet wird. Dadurch wird das Wire-Format gesteuert, in dem die Daten gesendet oder empfangen werden.

Beschreibung von Prozessen in Flussdiagrammen

Sie können den Prozess modellieren, indem Sie eine Sequence-Aktivität (Sequenz) verwenden. Ein kurzer Blick auf Abbildung 1 zeigt jedoch, dass das Verfahren an einem bestimmten Punkt eine Rückwärtsschleife zu einem vorhergehenden Schritt erfordert und dass dieser nicht direkt in nachfolgenden Workflows unterstützt wird. (Dazu wäre eine manuelle Modellierung der Schleife mithilfe von Konstrukten erforderlich, wie z. B. eine While-Aktivität mit einer vorsichtig modellierten Bedingung.) Ein Flussdiagramm ist eine bessere Anpassung zur Modellierung dieses Szenarios.

Flowchart (Flussdiagramm) ist eine neue Steuerungsflussaktivität, die in WF 4 eingeführt wurde und mit der Sie Ihre Prozesse so beschreiben können wie auf einem Whiteboard. Flowchart beschreibt Prozesse, die naturgemäß hintereinander erfolgen, mit einem einzelnen Ausführungspfad, für den eine Rückwärtsschleife zu einem vorherigen Schritt unter bestimmten Bedingungen erforderlich ist. Zur Beschreibung des Prozesses verwendet das Flussdiagramm Pfeile und Felder, ein beliebter Ansatz in vielen Disziplinen.

Der von der WCF Workflow Service-Projektvorlage erstellte Standardworkflow ist eine Sequence-Aktivität. Dies bedeutet jedoch nicht, dass es sich dabei um die einzige Ablaufsteuerungsaktivität handelt, die Sie in Workflowdiensten verwenden können. Löschen Sie für die Verwendung eines Flussdiagramms (oder einer anderen kombinierten Aktivität) als Stammaktivität in einem Dienst einfach die Sequence-Aktivität und fügen Sie ein Flussdiagramm hinzu.

Abbildung 3 zeigt, wie einfach ein Flussdiagramm aus den Diagrammen erstellt werden kann, die von den Unternehmensbenutzern in der Regel zum Beschreiben eines Prozesses entworfen werden.

Figure 3 The Mortgage Approval Process as a Flowchart
Abbildung 3 Der Hypothekengenehmigungsprozess als Flussdiagramm

Flowchart ist ein hervorragendes Tool zum Beschreiben von Geschäftsprozessen, das die Abweichung zwischen den Prozessen und der Weise, wie sie angegeben werden, minimiert. In diesem Fall entspricht die Flowchart-Definition der Dokumentation des Prozesses.

Aber wollen wir in einem langsameren Tempo voranschreiten. Wir sind von einem leeren Flussdiagramm gleich zu einem vollständigen gesprungen. Gehen wir noch einmal zurück zum leeren Flussdiagramm, und beginnen wir damit, daran zu arbeiten.

Der potenzielle Hauskäufer sendet seine Daten über eine Webanwendung. Diese Daten werden über eine Receive-Aktivität an den Workflow übergeben. Das Ergebnis der Integration einer Receive-Aktivität im Flussdiagramm besteht darin, dass der WorkflowServiceHost einen Endpunkt verfügbar macht, anhand dessen die Benutzer durch das Senden von Nachrichten kommunizieren können.

Wie bereits zuvor erwähnt, können Sie die Send- und Receive-Aktivitäten für die Verwendung eines Nachrichten- oder RPC-basierten Ansatzes konfigurieren. In diesem Fall konfigurierte ich die Receive-Aktivität für die Verwendung eines RPC-basierten Ansatzes. Dies bedeutet, dass sie einen Satz Eingabeargumente empfängt, ähnlich einem Methodenaufruf. Um sie dem Workflow zur Verfügung zu stellen, muss ich Variablen erstellen und sie an die Parameter binden (siehe Abbildung 4). Ein weiterer möglicher Ansatz würde darin bestehen, mit einem DataContract-Element zu arbeiten, das alle diese Felder reduziert.

Figure 4 Configuring Input Parameters
Abbildung 4 Konfigurieren von Eingabeparametern

Falls Sie eine neue Instanz des Workflows nach dem Empfangen einer Nachricht erstellen und starten möchten, müssen Sie die CanCreateInstance-Eigenschaft in der Receive-Aktivität auf „True“ festlegen. Dies bedeutet, dass der WorkflowServiceHost eine neue Instanz erstellen wird, wenn er eine Nachricht von diesem Endpunkt empfängt.

Modellieren des Prüfschritts (Screening) mit WF Composition

Sobald Daten im Workflow vorhanden sind, können Sie damit arbeiten. Der erste Schritt ist das Prüfen (Screening). Dies bedeutet, dass ein Satz Bedingungen geprüft wird, um zu bestimmen, ob der Antragsteller für eine Hypothek in Frage kommt, bevor die Anbieter kontaktiert werden.

Ein Ansatz besteht darin, dass dem Hauptflussdiagramm mehrere Entscheidungs-Shapes (FlowDecision) hinzugefügt werden. Dies funktioniert, macht aber den Gesamtprozess schwer leserlich. Außerdem wäre für jede Änderung der Prüfregeln das Aktualisieren des Hauptflusses erforderlich. Das Flowchart-Tool scheint eine gute Wahl für die visuelle Darstellung von Bedingungen zu sein, der Hauptprozess soll jedoch schlank bleiben.

Eine Lösung besteht darin, im bereits vorhandenen Flussdiagramm ein neues Flussdiagramm hinzuzufügen. WF 4 enthält in seinem Kern eine starke Unterstützung der Komposition. Auf diese Weise können die Aktivitäten frei zusammengestellt werden. Sie können also an beliebiger Stelle ein neues Flussdiagramm hinzufügen, auch innerhalb eines bereits vorhandenen Flussdiagramms. Überdies ist die Komposition willkürlich und unterliegt keinerlei Beschränkungen. Sie können bereits vorhandene Aktivitäten beliebig kombinieren.

Das untergeordnete Flussdiagramm wird reduziert im übergeordneten angezeigt (der Flussdiagramm-Designer unterstützt keine unmittelbare Erweiterung). Sie müssen darauf doppelklicken, um die Prüflogik zu modellieren. Das Flussdiagramm zum Prüfen (Screening) (siehe Abbildung 5) ist ein untergeordnetes Element des Hauptflussdiagramms und greift auf seine Variablen und Argumente zu.

Figure 5 Adding the Screening Flowchart
Abbildung 5 Hinzufügen des Flussdiagramms zum Prüfen (Screening)

Was geschieht, wenn Sie Code schreiben möchten? Sie könnten sicherlich Code schreiben, um den Prüfvorgang zu beschreiben. In diesem Fall können Sie z. B. eine CodeActivity-Aktivität erstellen, die die Daten vom Kunden als Eingabe erhält, die Prüfung durchführt (ein Satz von verketteten If-Anweisungen in Ihrer ausgewählten Sprache) und das Ergebnis zurückgibt. Dies hat Vor- und Nachteile. Es bietet eine potenziell höhere Leistung (alle Prüfungen werden in einem einzigen Ausführungsimpuls ausgeführt) und eine kompaktere Darstellung als der deklarative Ansatz. Andererseits geht die visuelle Darstellung des Prozesses (Undurchsichtigkeit) verloren, und die Änderung des Prozesses erfordert die Änderung des Codes sowie eine Neukompilierung.

Senden von Ergebnissen an den Kunden

Sobald die Screening-Überprüfung abgeschlossen ist, muss ich das Ergebnis an den Antragsteller zurücksenden. Ich erhielt die Daten des Antragstellers über eine Receive-Aktivität zu Beginn des Workflows. Um die Antwort zurückzusenden, verwende ich eine SendReply-Aktivität (eine SendReply-Aktivität für eine bereits vorhandene Receive-Aktivität kann durch Rechtsklicken auf „Receive“ und Auswählen von „Create SendReply“ erstellt werden). Die Kombination von „Receive“ und „SendReply“ ermöglicht die Implementierung des Anforderungs-/Antwort-Nachrichtenaustauschmusters. Die SendReply-Aktivität wird konfiguriert, um das Ergebnis des Vorgangs und eine Beschreibung an den Kunden zurückzusenden.

Warum die SendReply- und nicht die Send-Aktivität? Sie können ein Paar Receive- und Send-Aktivitäten für die Modellierung von doppelten Nachrichtenaustauschmustern wie „anfordern und auf eine Antwort warten“ (ähnlich wie Rückruf) verwenden, die SendReply-Aktivität ist jedoch besser für die Modellierung von Anforderungs-/Antwort-Nachrichtenaustauschmustern geeignet (ähnlich wie der Methodenaufruf).

Festlegen der Richtung

Wenn das Screening abgeschlossen ist, kann der Workflow das Hypothekenantragsverfahren fortsetzen. An diesem Punkt gibt es zwei Möglichkeiten: „Reject“ und „Approved“. Wenn der Antragsteller jedoch mehr Daten bereitstellen muss, muss der Workflow zu einem früheren Schritt zurückkehren. Mithilfe des Flowchart-Tools kann diese Zeilenzeichnungs-Aktion bis zu dem Schritt modelliert werden, an dem der Workflow fortgesetzt wird.

Um den Pfad festzulegen, der basierend auf dem Ergebnis des Screenings genommen werden soll, verwende ich eine FlowSwitch-Aktivität (ähnlich einer Switch-Anweisung), wie in Abbildung 6 dargestellt.

Figure 6 Each Outbound Arrow in the FlowSwitch Represents a Case in the Switch
Abbildung 6 Jeder ausgehende Pfeil in FlowSwitch stellt einen Fall im Switch dar

Korrelation

Wenn die Hypothekenanfrage als fehlerhaft bewertet wird, fordert der Workflow den Kunden dazu auf, einer bereits vorhandenen Workflowinstanz zusätzliche Daten bereitzustellen. Wie kann die Receive-Aktivität wissen, dass die empfangenen Daten eine Korrektur der Daten sind, die der Kunde bereits zuvor bereitgestellt hatte? Mit anderen Worten: Wie können Sie eine weitere Nachricht an eine ausgeführte Instanz eines Workflows senden? Die Antwort lautet: mit Korrelation.

WF 4 setzt ein Framework für die Korrelation ein. Eine Korrelation beinhaltet eine der beiden folgenden Möglichkeiten:

  • Eine Möglichkeit, Nachrichten zusammen zu gruppieren. Ein klassisches Beispiel dafür sind Sitzungen in WCF oder einfacher noch die Beziehung zwischen einer Anforderungsnachricht und ihrer Antwort. 
  • Eine Möglichkeit der Zuweisung von Daten zu einer Workflowdienstinstanz.

Es gibt mehrere Arten der Korrelation, die in .NET Framework 4 zur Verfügung stehen. Ich verwende in diesem Beispielworkflow die inhaltsbasierte Korrelation. Eine inhaltsbasierte Korrelation nimmt Daten aus der eingehenden Nachricht und weist sie einer bereits vorhandenen Instanz zu. Die inhaltsbasierte Korrelation wird verwendet, wenn ein Workflowdienst mehrere Methoden aufweist, auf die von einem einzelnen Client zugegriffen wird, und Daten in den ausgetauschten Nachrichten vorhanden sind, mit denen die gewünschte Instanz identifiziert wird.

Für die Konfiguration der Korrelation deklariere ich eine Variable vom Typ CorrelationHandle. Dies ist der Handle, der zum Speichern der Korrelationsinformationen verwendet wird (customerCorrelationHandle in der begleitenden Lösung). Der nächste Schritt besteht in der Verwendung des Korrelationshandles. Das Eigenschaftenraster der Receive-Aktivität verfügt über einen Korrelationen-Abschnitt zur Konfiguration der Korrelation. Er verfügt über Eigenschaften zur Konfiguration des Korrelationshandles (CorrelatesWith), zur Angabe der Daten, die Sie über eine Korrelationsabfrage korrelieren (CorrelatesOn) und zur Initialisierung eines Korrelationshandlers (CorrelationInitializers). Ich konfigurierte die Argumente CorrelatesWith und CorrelatesOn in der Receive-Aktivität, um für das customerCode-Feld zu korrelieren.

CorrelatesOn und CorrelatesWith können leicht verwechselt werden. Im Folgenden erhalten Sie eine Regel, die Ihnen helfen kann: Eine Receive-Aktivität korreliert mit (CorrelatesWith) einem bereits vorhandenen Korrelationshandle und korreliert (CorrelatesOn) Daten, die von einer Korrelationsabfrage angegeben wurden.

All dies kann mithilfe des WF-Designers konfiguriert werden.

Ich möchte die Kundenidentifikation so korrelieren, dass ich eine Korrelationsabfrage erstelle, mit der der customerCode aus der Nachricht extrahiert wird. Beachten Sie, dass die Korrelationsabfragen mit XPath verfasst werden. Sie müssen jedoch mit XPath nicht vertraut sein, da die Abfrage vom WF-Designer erstellt wird, indem der Vertrag der empfangenen Nachricht geprüft wird.

Die erste Receive-Aktivität im Workflow wird konfiguriert, um nach Erhalt einer Nachricht eine neue Workflowinstanz zu erstellen. Es wird jedoch keine neue Instanz erstellt, wenn ich zu ihr zurückkehre, da sie auch so konfiguriert ist, dass sie für den customerCode korreliert wird. Vor dem Erstellen einer neuen Instanz wird mit diesem Korrelationsschlüssel nach einer bereits vorhandenen Instanz gesucht.

Anfragen von Zinssätzen bei Anbietern

Wenn der Antrag das Screening durchlaufen hat, wird er zur Evaluierung an die Anbieter gesendet. Contoso arbeitet mit drei Anbietern zusammen und hat eine bevorzugte Reihenfolge, mit ihnen Geschäfte zu machen. Deshalb fragt der Prozess die Anbieter nacheinander, bis einer zusagt.

Alle Anbieter implementieren einen Standarddienstvertrag für Hypothekengenehmigungsanfragen. Der einzige Unterschied zwischen den Zinssatzanfragen an die drei Hypothekenanbieter besteht in dem URI des Dienstes. Die Anbieterzinssatzanfrage ist jedoch durch die Tatsache komplizierter, dass eine Nachricht gesendet und asynchron auf eine Antwort gewartet werden soll, während gleichzeitig auf Kundenanfragen bezüglich des Status geantwortet wird.

Ich könnte diesen Prozess einmal modellieren und ihn dreimal im Workflow kopieren. Dies würde jedoch zu vielen unnötigen Duplizierungsvorgängen und deshalb zu einem schwerwiegenden Verwaltungsproblem führen. Ich möchte diesen Schritt abstrahieren, damit ich denselben Prozess mehrmals verwenden kann. Idealerweise würde ich dem Workflow einige Eingabedaten übergeben und ein Ergebnis erhalten, wenn er abgeschlossen ist. Genau dazu sind benutzerdefinierte Aktivitäten gedacht.

WF 4 bietet zwei Ansätze zum Erstellen von benutzerdefinierten Aktivitäten:

  • Deklarativ Erstellen einer neuen Aktivität durch Zusammenstellen anderer bereits vorhandener Aktivitäten.
  • Imperativ Erstellen einer neuen Aktivität durch das Schreiben von Code. Es gibt mehrere Basisklassen mit unterschiedlichen Möglichkeiten, die abgeleitet werden können, einschließlich CodeActivity (einfaches unerlässliches Verhalten), AsyncCodeActivity (asynchron Arbeit verrichten) und NativeActivity (mit der WF-Runtime interagieren).

Aktivitäten sind mit Argumenten versehen, die die öffentlichen Signaturen dahingehend definieren, welche Daten sie erhalten (InArgument) und welche Daten sie zurückgeben können (OutArgument), wenn sie abgeschlossen sind. Meine Aktivität erhält Kundenhypothekeninformationen und einen Dienst-URI als Eingabe und gibt einen Zinssatz sowie eine Ergebniszeichenfolgenachricht zurück.

Ich verwende die Elementvorlage für eine Aktivität in Visual Studio, um mit dem WF-Designer eine neue Aktivität deklarativ zu erstellen. Mit dem Designer können Sie benutzerdefinierte Aktivitäten visuell erstellen, indem Sie bereits vorhandene Aktivitäten ziehen und ablegen und ihre Argumente festlegen. Das Ergebnis der Erstellung einer benutzerdefinierten Aktivität mit dem Designer ist eine XAML-Datei, die eine x:Class definiert.

Ich nannte die Aktivität „AskVendor“. Die AskVendor-Aktivität erhält Hypothekeninformationen vom Kunden und den URI des Dienstes als Eingabe und liefert einen Zinssatz sowie eine Ergebniszeichenfolgenachricht als Ausgabe. Falls der Zinssatz 0 beträgt, wurde der Antrag abgelehnt.

AskVendor sendet eine Nachricht an einen Hypothekenanbieter, fragt nach einem Zinssatz und wartet auf eine Antwort vom Anbieter. Es kann Minuten, Stunden oder sogar Tage dauern, bis die Antwort ankommt. Während Sie auf die Antwort warten, möchte der Antragsteller u. U. den Status des Prozesses erfahren. Deshalb antwortet die Aktivität auch auf Statusanforderungsnachrichten vom Antragsteller.

Für eine gleichzeitige Verarbeitung beider Aktionen verwende ich eine Parallel-Aktivität als Basis der benutzerdefinierten Aktivität. In einer Verzweigung habe ich alle Aktivitäten für die Kommunikation mit einem Hypothekenanbieter und in der anderen die Aktivitäten, dem Kunden zuzuhören, während ich auf die Antwort vom Anbieter warte. Alle in AskVendor verwendeten Messaging-Aktivitäten sind für eine Korrelation im customerCode-Feld konfiguriert. Abbildung 7 stellt eine benutzerdefinierte AskVendor-Aktivität dar.

Figure 7 AskVendor Custom Activity
Abbildung 7 Benutzerdefinierte AskVendor-Aktivität

Wie bereits erwähnt, ist die Basis der benutzerdefinierten Aktivität eine Parallele. Die linke Verzweigung sendet eine Nachricht an einen Anbieter und wartet auf eine Antwort. Sobald die Antwort eingegangen ist, wird die resultierende Zeichenfolgenachricht formatiert und das abgeschlossene Flag auf „True“ festgelegt. Die rechte Verzweigung wartet auf Statusabfrage-Anforderungen vom Antragsteller. Receive und SendReply befinden sich innerhalb einer While-Aktivität, die so lange ausgeführt wird, bis das abgeschlossene Flag auf „True“ festgelegt ist. Die Komplettierungsbedingung der Parallel-Aktivität (ausgeführt, wenn eine Verzweigung abgeschlossen ist) legt das abgeschlossene Flag auf „True“ fest. Wenn also die linke Verzweigung abgeschlossen ist (die Nachricht vom Anbieter eingeht), wird die abgeschlossene Variable als „True“ signalisiert, und die While-Variable rechts wird ebenso abgeschlossen.

Benutzerdefinierte Aktivitäten sind wie jede andere Aktivität. Wenn Sie eine benutzerdefinierte Aktivität erstellen, wird sie automatisch in der Aktivitäten-Toolbox angezeigt. Und ihre Verwendung unterscheidet sich nicht im Geringsten von der Verwendung einer anderen bereits vorhandenen Aktivität: Ziehen aus der Toolbox, Ablegen im Designer und Konfigurieren der Argumente. Da ich für diese Aktivität keinen Designer erstellt habe, wird der Standarddesigner zugewiesen (ein Rechteck, für das Sie die DisplayName-Eigenschaft festlegen können). Das Eigenschaftenraster zeigt automatisch alle Argumente der Aktivität an.

Ich erwähnte zuvor bereits die starke Unterstützung der Komposition in WF 4. Dies gilt auch für die benutzerdefinierten Aktivitäten. Wenn Sie Ihre eigene zusammengesetzte Aktivität erstellen, können Sie sie frei mit einer beliebigen anderen Aktivität, wie Sequence, Flowchart, Parallel oder sogar benutzerdefinierten Aktivitäten erstellen.

Aufrufen des CRM-Dienstes

Das CRM-System von Contoso macht seine Kernfunktionen als Dienste verfügbar. Einer dieser Dienste ermöglicht die Registrierung einer Interaktion mit einem Kunden. Ich könnte ihn mit einer Send-Aktivität aufrufen, dies würde jedoch die manuelle Konfiguration der Aktivität und das Importieren der Dienstdatenverträge beinhalten.

Es wäre großartig, wenn ich den Dienst einfach in WF importieren und ausführen könnte. Dies ist genau das, was die „Add Service Reference“-Aktivität (Dienstverweis hinzufügen) in einem Workflowdienstprojekt macht: Ein Dienstvertrag erstellt automatisch Proxy-Aktivitäten (eine für jeden Vorgang im Dienst), die zum Aufrufen des Dienstes verwendet werden können (siehe Abbildung 8). In diesem Fall bietet der CRM-Dienstvertrag drei Vorgänge. Deshalb hat „Add Service Reference“ (Dienstverweis hinzufügen) drei Aktivitäten erstellt, die in der Toolbox angezeigt werden.

Figure 8 Adding a Service Reference to the CRM Service
Abbildung 8 Hinzufügen eines Dienstverweises zu einem CRM-Dienst

Kommunizieren des Ergebnisses

Schließlich muss ich dem Kunden die Ergebnisse vorlegen. Damit die Anwendung einfach bleibt, verwende ich nur eine ReceiveAndSendReply-Aktivität, die das Ergebnis dem Kunden verfügbar macht. Sobald der Kunde das Ergebnis liest, wird der Workflow abgeschlossen.

Dazu muss ich eine ReceiveAndSendReply-Aktivität im Flussdiagramm ablegen. Beachten Sie, dass Sie beim Ablegen der Aktivität in der Designer-Oberfläche eine reduzierte Sequenz erhalten. Dies liegt daran, dass ReceiveAndSendReply eine Aktivitätsvorlage ist. Das bedeutet, dass es sich um einen zuvor konfigurierten Satz von Aktivitäten handelt (in diesem Fall eine Sequenz mit einer Receive- und einer SendReply-Aktivität). Sie haben dies bereits zuvor gesehen, als ich das untergeordnete Flussdiagramm zum Screening hinzufügte.

Für die Konfiguration von ReceiveAndSendReply muss ich die Endpunktinformationen in der Receive-Aktivität näher analysieren und festlegen. Außerdem muss ich die Receive-Aktivität so konfigurieren, dass ich so nach Kundenidentifikation korrelieren kann, dass beim Senden einer Nachricht durch den Kunden mit seinem customerCode dieser eine Antwort erhält.

Langfristig ausgeführte Arbeit

Sobald der Workflow eine Genehmigungsanforderung an einen Anbieter sendet, läuft die Dienstinstanz im Leerlauf und wartet auf eine Antwort. Es kann Minuten, Stunden, Tage oder sogar Wochen dauern, bis die Antwort ankommt. Dies führt zu einigen interessanten Herausforderungen. Sie möchten wahrscheinlich nicht alle Instanzen im Speicher behalten, denn das würde unnötige Systemressourcen verbrauchen und ließe sich nicht skalieren. Und falls der Hostprozess abstürzt (oder in einem weniger apokalyptischen Szenario zur Wartung heruntergefahren werden muss), würden sämtliche nicht abgeschlossenen Instanzen verloren gehen.

Wäre es nicht großartig, wenn Sie eine nicht ausgelastete Instanz einfach in beständigem Speicherplatz speichern und sie aus dem Arbeitsspeicher entfernen könnten? Dies ist möglich über das WF-Persistenzframework, welches das Speichern einer Workflowinstanz in ein Speichermedium ermöglicht, das zu einem späteren Zeitpunkt abgerufen werden kann.

Das bedeutet, dass die Instanzen mit keinem bereits vorhandenen Prozess oder Computer verknüpft sind. Im Beispielworkflow kann das Screening in einem Prozess stattfinden, das Anfordern von Zinssätzen beim ersten Anbieter kann in einem anderen Prozess auftreten, und das Eintreffen einer Antwort kann wiederum in einem dritten Prozess auftreten, ohne dass dabei die Ausführung oder die Daten der Workflowinstanz beeinträchtigt werden würden. Das gewährleistet eine bessere Nutzung der Ressourcen, verbessert die Skalierbarkeit und sorgt für Beständigkeit. Ein Absturz des Hosts führt nicht zum Verlust der aktiven Instanzen, da diese an dem Punkt wieder aufgenommen werden können, an dem sie zuletzt gespeichert wurden.

Workflowinstanzen werden in einem Instanzenspeicher gesichert. WF 4 umfasst einen SQL Server-basierten Instanzenspeicher, und das Persistenzframework ist erweiterbar, sodass Sie Ihren eigenen schreiben können. (Das PurchaseProcess-Beispiel im SDK zeigt, wie z. B. ein sehr einfacher Textdatei-Instanzenspeicher geschrieben wird.)

Ich verwende den integrierten SQL Server-Instanzenspeicher zum Speichern von Instanzen des Contoso-Workflows. Die gute Nachricht ist, dass Sie für ihre Verwendung keinen Code schreiben müssen. In Workflowdiensten ist Persistenz ein Verhalten, das in der Datei „web.config“ wie folgt konfiguriert werden kann:

<!--Set up SQL Instance Store-->
<sqlWorkflowInstanceStore connectionString="Data Source=.\SQLExpress;Initial Catalog=InstanceStore;
Integrated Security=True;Asynchronous Processing=True"/>
          
<!--Set the TimeToUnload to 0 to force the WF to be unloaded. To have a durable delay, the workflow needs to be unloaded-->
<workflowIdle timeToUnload="0"/>

Die erste Zeile konfiguriert das Persistenzverhalten für die Verwendung des SQL Server-Instanzenspeichers. Die zweite Zeile weist das Persistenzframework an, Instanzen zu speichern und zu entladen, sobald sie im Leerlauf sind (dies bedeutet, beim Ausführen einer Receive-Aktivität und beim Warten auf eine Antwort im Leerlauf wird die Workflowinstanz entladen und in der Datenbank gespeichert).

Falls ein Workflow für die Persistenz und dafür auch die Korrelation konfiguriert ist, ist der Host (WorkflowServiceHost) für das Laden der richtigen Instanz verantwortlich, wenn eine Meldung basierend auf den Korrelationsinformationen ankommt.

 Angenommen, Sie verfügen über eine Instanz, die zum Korrelieren nach customerCode konfiguriert ist, z. B. customerCode = 43. Sie fragen bei einem Hypothekenanbieter einen Zinssatz an, und die Instanz bleibt erhalten, während Sie auf die Antwort warten (Persistenz beinhaltet das Speichern der Korrelationsinformationen). Wenn das Hypothekenunternehmen eine Nachricht für customerCode = 43 zurücksendet, lädt WorkflowServiceHost diese Instanz automatisch aus dem Instanzenspeicher und verteilt die Nachricht.

Beachten Sie, dass der SQL-Instanzenspeicher nicht standardmäßig installiert wird. Sie müssen ihn ausdrücklich installieren, indem Sie einen Skriptsatz ausführen, der mit .NET Framework 4 ausgeliefert wird.

Überwachen des Dienstes

So verfüge ich nun über einen langfristig ausgeführten Dienst, der mit anderen Diensten nachrichtenbasiert kommuniziert. Der Dienst ist so konfiguriert, dass er dauerhaft ist, einige der Funktionen parallel ausführt und asynchrone Aktivitäten ausführen kann. Dies scheint sehr komplex zu sein. Was ist zu tun, wenn etwas schiefläuft? Wie können Sie feststellen, welche Aktivität fehlgeschlagen ist? Was geschieht, wenn Sie einfach wissen möchten, was mit einer Instanz des Dienstes geschieht?

Visual Studio ermöglicht Debugging-Workflows (Sie können ein schrittweises Debugging im WF-Designer durch das Festlegen von Haltepunkten durchführen, wie Sie dies auch im Code machen), dies ist jedoch in Produktionsumgebungen keine Option.

Stattdessen verfügt WF über eine umfassende Überwachungsinfrastruktur, die Daten über ausgeführte Workflows liefert. Die Überwachung liefert Ihnen Informationen über Ereignisse im Workflow (Überwachungsereignisse), die einem Teilnehmer geschehen, der diese Ereignisse speichert. Überwachungsprofile ermöglichen das Filtern der Ereignisse, die ein Überwachungsteilnehmer empfängt, sodass er nur die Informationen erhält, die er benötigt.

WF 4 liefert einen Überwachungsteilnehmer, der die Daten im Windows-Ereignisprotokoll (EtwTrackingParticipant) speichert. Sie können eigene Überwachungsteilnehmer erstellen, indem Sie TrackingParticipant erweitern. Für diesen Workflow verwendete ich den standardmäßigen EtwTrackingParticipant. Sie brauchen für seine Verwendung keinen Code zu schreiben; liefern Sie einfach nur die richtige Konfiguration in der Datei „web.config“. Ich beginne mit der Konfiguration des Dienstes zur Verwendung von EtwTrackingParticipant:

<!--Set up ETW tracking -->
<etwTracking profileName="HealthMonitoring "/>

Ich lege ihn auch für die Verwendung eines HealthMonitoring-Profils fest, das Ereignisse liefert, mit denen die ordnungsgemäße Funktion unseres Dienstes bewertet wird (siehe Abbildung 9). Jetzt liefert der Dienst Informationen über Ereignisse, mit denen Sie seine ordnungsgemäße Funktion überwachen und Probleme beheben können, sobald diese auftreten. Das SDK liefert einige Beispiele, die zeigen, wie Sie Ihren eigenen Überwachungsteilnehmer erstellen und ein Problembehebungsprofil schreiben.

Abbildung 9 Festlegen des Profils für Überwachungsteilnehmer

<tracking>
  <profiles>
    <!--The health monitoring profile queries for workflow instance level records and for workflow activity fault propagation records-->
    <trackingProfile 
      name="HealthMonitoring">
      <workflow activityDefinitionId="*">
        <workflowInstanceQueries>
          <workflowInstanceQuery>
            <states>
              <state name="Started"/>
              <state name="Completed"/>
              <state name="Aborted"/>
              <state name="UnhandledException"/>
            </states>
          </workflowInstanceQuery>
        </workflowInstanceQueries>
        <faultPropagationQueries>
          <faultPropagationQuery 
            faultSourceActivityName ="*" 
            faultHandlerActivityName="*"/>
        </faultPropagationQueries>
      </workflow>
    </trackingProfile>
  </profiles>
</tracking>

Bereitstellen und Verarbeiten des Dienstes

Ich habe also einen Workflow mit dem Designer erstellt und ihn für die Verwendung von Persistenz und Überwachung konfiguriert. Die einzige verbleibende Aufgabe besteht darin, ihn zu hosten und auszuführen.

Während der Entwicklung können Sie den Dienst mit dem integrierten Webdiensthost in Visual Studio 2010 hosten. Dazu müssen Sie nur das Projekt mit dem Dienst ausführen, und das war’s.

Das Hosten des Dienstes in einer Produktionsumgebung ist nur ein wenig komplexer. Sie können WCF-Workflowdienste in IIS oder AppFabric-Anwendungsservererweiterungen hosten. Mit Visual Studio 2010 können Sie ein Paket erstellen, das direkt in IIS importiert werden kann. Falls Sie sich für die Verwendung von AppFabric entscheiden, können Sie Features wie das Dashboard verwenden, das Zusammenfassungen über die Instanzen Ihres Dienstes liefert, und die aufgezeichnete Überwachung abfragen.

Der letzte Schritt besteht darin, den Dienst tatsächlich zu nutzen. In diesem Szenario wollte Contoso eine webbasierte Oberfläche für die Interaktion von Benutzern mit dem Dienst schaffen. Der Dienst wird also von einer ASP.NET-Anwendung aus verarbeitet.

Der WCF-Beispielworkflowdienst, den Sie hier gesehen haben, ist wie jeder andere WCF-Dienst, den Sie in reinem Code schreiben können. Zum Verarbeiten müssen Sie im Clientprojekt einen Dienstverweis hinzufügen. Dieser Dienstverweis erstellt die Clientproxies zum Aufrufen des Dienstes.

Wenn Sie über den Verweis verfügen, können Sie den Dienst aufrufen. Der Client für diesen Dienst verfügt über einen Vorgang für jede Receive-Aktivität im Dienst. Abbildung 10 zeigt den Code, der zum Anfordern einer Hypothekengenehmigung verwendet wird (und deshalb zum Starten einer neuen Instanz des Dienstes).

Abbildung 10 Verarbeiten des Dienstes

protected void OnSubmit(object sender, EventArgs e) {
  using (ContosoRealEstate.ContosoRealEstateClient client = 
    new ContosoRealEstate.ContosoRealEstateClient()) {

    string message = "";        
    string result = client.EvaluateMortgage(
      out message,
      this.txtId.Text,
      Convert.ToInt32(this.txtHousePrice.Text),
      Convert.ToInt32(this.txtDownpayment.Text),
      Convert.ToInt32(this.txtYears.Text),
      Convert.ToInt32(this.txtSalary.Text),
      this.chkCreditHistory.Checked,
      this.chkBankrupcy.Checked,
      this.chkLawsuit.Checked,
      this.chkForeclosure.Checked);
    lblMessage.CssClass= result;
    lblMessage.Text = message + " (" + result + ")";

    this.btnSubmit.Visible = result.Equals("Incorrect");
    this.btnMonitor.Visible = result.Equals("Approved");
  } 
}

Abschließende Hinweise

Wie Sie bereits gesehen haben, bietet .NET Framework 4 einen großen Funktionsumfang, der zum Erstellen von komplexen Lösungen aus der Praxis verwendet werden kann, indem die bereits vorhandenen Komponenten zusammengestellt werden. Das Framework bietet auch Erweiterungspunkte, um diese Komponenten an bestimmte Anforderungen anzupassen, die eine große Vielzahl von Szenarien berücksichtigen.

Mit den WCF-Workflowdiensten können Sie einen langfristig ausgeführten, dauerhaften und instrumentierten Prozess deklarativ beschreiben, indem Sie einfach die bereits vorhandenen Aktivitäten zusammenstellen und den Dienst konfigurieren. Sie können aber bei Bedarf auch eigenen Code schreiben.

In diesem Artikel kombinierte ich mehrere Features in WF 4 und WCF 4, um einen Dienst zu erstellen, der einige Aufgaben alleine durchführt und Konversationen mit anderen bereits vorhandenen Diensten koordiniert. Ich erstellte den gesamten Dienst, ohne Code zu schreiben und einschließlich eines neuen Artefakts (eine benutzerdefinierte Aktivität).

Mit diesen .NET Framework 4-Technologien stehen noch viele andere Möglichkeiten zur Verfügung.

Leon Welicki ist ein Programm-Manager im WF-Team bei Microsoft, der sich mit Aktivitäten und der WF-Runtime beschäftigt. Bevor er zu Microsoft kam, arbeitete er als leitender Entwicklungsmanager für ein großes spanisches Telekommunikationsunternehmen und als externer außerordentlicher Professor an der Graduiertenfakultät für Informatik an der Pontifical University of Salamanca bei Madrid.

Wir danken den folgenden technischen Experten für die Überprüfung dieses Artikels: Dave Cliffe, Vikram Desai, Kavita Kamani und Bob Schmidt.