MSDN Magazin > Home > Ausgaben > 2008 > February >  WF-Anleitung: Erstellen von Statuscomputern mit...
WF-Anleitung
Erstellen von Statuscomputern mit Windows Workflow Foundation
Keith Pijanowski

Themen in diesem Artikel:
  • Sequenzielle Workflows und Statuscomputerworkflows
  • Wann Statuscomputerworkflows zu verwenden sind
  • Erstellen und Entwerfen von Statuscomputerworkflows
  • Auslösen von Ereignissen in aktiven Workflows
  • Übergabe von Daten an aktive Workflows
In diesem Artikel werden folgende Technologien verwendet:
Windows Workflow Foundation, Visual Studio
Laden Sie den Code für diesen Artikel herunter: WFStateMachines2008_02.exe (177 KB)
Code online durchsuchen
In Microsoft® .NET Framework 3.0 wurden neue Features für das visuelle und deklarative Erstellen von Workflows eingeführt, die durch verwalteten Code gehostet werden können. Entwickler können mit der Standardversion von .NET Framework 3.0 sequenzielle Workflows und Statuscomputerworkflows erstellen. Über sequenzielle Workflows ist viel geschrieben worden, weil sie konventionellen Programmierverfahren stark ähneln.
Bei Statuscomputerworkflows ist die Denkweise in Bezug auf die Programmlogik dagegen ganz anders. Richtig entworfene und implementierte Statuscomputerworkflows sind genauso wertvoll wie sequenzielle Workflows. Darüber hinaus ist dieser Workflowtyp ein guter Ausgangspunkt für das Erstellen menschlicher Workflows. Statuscomputerworkflows sollten daher zur Werkzeugpalette jedes Architekten und jedes Entwicklers gehören.

Die Theorie hinter Statuscomputern
Zusätzliche Ressourcen
Der Codedownload für diesen Artikel enthält alle Workflows, Codeabbildungen und Codeausschnitte, die in diesem Artikel gezeigt werden. Der Code wurde als Sandbox bzw. Testarena für Statuscomputerworkflows entworfen und führt aus diesem Grund nur jeweils eine Instanz eines Workflows aus.
Dies ist eine Visual Studio 2005-Lösung, die die folgenden Projekte enthält:
StateMachineLibrary enthält die zwei hier vorgestellten Workflows. Diese Workflows sind der SimpleStateMachine- und der SupplyFulfillment-Workflow.
ConsoleHost ist eine Konsolenanwendung, die zum Hosten des einfachen Statuscomputerworkflows verwendet wird, der zu Beginn dieses Artikels vorgestellt wird.
WinFormHost ist eine Windows Forms-Anwendung, die zum Hosten des SupplyFulfillment-Workflows verwendet wird. In diesem Projekt wird ExternalDataExchange verwendet, um Ereignisse an einer Instanz des SupplyFulfillment-Workflows auszulösen.
ExternalDataExchange ist eine Klassenbibliothek, die die IEventService-Schnittstelle, die Implementierung dieser Schnittstelle (EventService) und die SupplyFulfillmentArgs-Klasse enthält. Dieser Dienst ermöglicht es, externe Ereignisse (und Daten) an den aktuellen Status eines Statuscomputerworkflows zu senden.

Geschäftslogik, die als Statuscomputerworkflow implementiert ist, folgt einem ganz anderen Pfad als Geschäftslogik, die als sequenzieller Workflow implementiert ist. Statt wie ein sequenzieller Workflow von Aktivität zu Aktivität überzugehen, gehen Statuscomputer von einem Status zum nächsten über. Stellen Sie sich einen Status als bekannten Schritt, als Phase oder sogar als Status in einem Geschäftsprozess vor. Status sind nützlich, weil sie anzeigen, wie viel von einem Workflow abgeschlossen ist und wie viel noch geschehen muss. Sie sind daher sehr gut für Workflows geeignet, die über einen langen Zeitraum ausgeführt werden.
Ob sich ein Geschäftsprozess gut für einen Statuscomputerworkflow eignet, lässt sich daran erkennen, ob in den Anforderungen Daten oder Logik als sich bewegende diskrete Schritte (oder Status) von einem Startpunkt zu einem Endpunkt beschrieben sind. Sehen Sie sich die folgende Beschreibung eines Geschäftsprozesses zur Anforderungsbearbeitung an, der als Statuscomputer implementiert werden könnte.
  1. Mitarbeiter, die Aufträge von Kunden bearbeiten, benötigen u. U. zusätzliches Material, um einen Auftrag erfüllen zu können. Anforderungen für zusätzliches Material müssen an ein zentrales System zur Verarbeitung gesendet werden.
  2. Nachdem eine Anforderung gesendet wurde, wird sie der Arbeitswarteschlange eines spezifischen Benutzers zur Prüfung zugewiesen.
  3. Sobald die Anforderung zugewiesen ist, wird sie basierend auf Kriterien außerhalb des Geschäftsprozesses entweder genehmigt oder abgelehnt.
  4. Wenn eine Anforderung abgelehnt wurde, wird sie basierend auf Kriterien außerhalb des Geschäftsprozesses entweder erneut zugewiesen oder storniert. Erneut zugewiesene Aufträge werden genauso wie zugewiesene Aufträge verarbeitet. Stornierte Aufträge werden als abgeschlossen betrachtet.
  5. Wenn die Mitarbeiteranforderung genehmigt wurde, wird die angeforderte Ressource bestellt.
  6. Sobald der Auftrag empfangen wurde, wird der zu diesem Auftrag gehörende Geschäftsprozess als abgeschlossen angesehen.
Die Hauptschritte dieses Geschäftsprozesses, die als Status betrachtet werden können, sind in Abbildung 1 dargestellt.
Abbildung 1 Logikentwurf des Anforderungsbearbeitungsworkflows 
Bevor mit der Erstellung dieses Workflows mit Windows® Workflow Foundation (Windows WF) begonnen wird, sollten einige wichtige Punkte erwähnt werden. Erstens: Der Workflow hat genau einen Start- und einen Endstatus, und zwar „Gesendet“ und „Abgeschlossen“. Jede Instanz eines Statuscomputerworkflows beginnt in dem Status, der als Startstatus bestimmt wurde, und endet, wenn der Workflow den Status erreicht, der als Endstatus festgelegt wurde.
Zweitens: Statusübergänge sind vordefiniert. Anders ausgedrückt: Teil der Definition jedes Status ist eine Liste der zulässigen nächsten Status. In Abbildung 2 sind die Status und die erlaubten Übergänge aufgeführt.

Status Erlaubte Übergänge
Gesendet Zugewiesen
Zugewiesen Genehmigt oder Abgelehnt
Genehmigt Bestellt
Abgelehnt Zugewiesen oder Abgeschlossen
Bestellt Abgeschlossen
Abgeschlossen (Keiner)
Drittens: Backtracking ist erlaubt. Unsere Anforderungen bestimmen, dass abgelehnte Anforderungen erneut zugewiesen werden können. Erneut zugewiesene Status hätten zwar in den logischen Entwurf eingefügt werden können, aber das wäre kein effizienter Entwurf. Die Anforderungen bestimmen, dass erneut zugewiesene Anforderungen auf die gleiche Weise wie neu zugewiesene Anforderungen zu verarbeiten sind. Es ist also nicht notwendig, eine separate Verzweigung vom Status „Abgelehnt“ für die erneut zugewiesenen Anforderungen zu erstellen. Anders ausgedrückt: Durch den Übergang eines Workflows zurück zu einem vorherigen Status ist eine bessere erneute Verwendung innerhalb des Workflows möglich.
Viertens: Statuscomputerworkflows sind für lange Prozesse geeignet. Wenn ein Statuscomputerworkflow innerhalb von Millisekunden von seinem Startstatus in seinen Endstatus übergeht und nie für eine externe Eingabe angehalten wird, könnte der Workflow mit einem sequenziellen Ansatz effizienter implementiert werden.

Statuscomputer und Windows WF
Bevor wir den oben erwähnten logischen Entwurf implementieren, möchte ich einen einfachen Windows WF-Statuscomputer beschreiben, damit Sie einen Überblick über die von WF bereitgestellten Tools erhalten. Ich werde als Einführung in die Entwurfszeit von Visual Studio® .NET und die Tools von .NET Framework 3.0 einen einfachen Statuscomputerworkflow erstellen. Alle hier gezeigten Workflows und Codeausschnitte stammen aus einer funktionierenden Visual Studio-Lösung, die als Codedownload für diesen Artikel verpackt ist. Weitere Informationen finden Sie in der Randleiste unter „Zusätzliche Ressourcen“.
Wenn Sie die Visual Studio 2005-Erweiterungen für .NET Framework 3.0 (Windows WF) über go.microsoft.com/fwlink/?LinkId=105219 installieren, erscheinen in der Visual Studio .NET 2005-Umgebung mehrere neue Projektvorlagen (siehe Abbildung 3). Wenn Sie Visual Studio 2008 verwenden, sind alle diese Projektvorlagen bereits im Kernprodukt enthalten. Sobald Sie eine Statuscomputerprojektvorlage auswählen, wird ein Visual Studio .NET-Projekt mit den richtigen Verweisen und einer Workflowdatei eingerichtet, das als Ausgangspunkt für die Entwicklung eines Statuscomputerworkflows benutzt werden kann.
Abbildung 3 Workflow Foundation-Projektvorlagen (Klicken Sie zum Vergrößern auf das Bild)
Der Designer für einen Statuscomputerworkflow ist viel eingeschränkter als der Designer für einen sequenziellen Workflow. Für die meisten Statuscomputer muss nur die Statusaktivität auf den Designer gezogen werden. (Es ist auch möglich, dem Designer eine EventDriven-Aktivität für Ereignisse hinzuzufügen, die nicht mit einem spezifischen Status verbunden sind.) Die Statusaktivität repräsentiert einen Schritt, eine Phase oder einen Status innerhalb eines Statuscomputerworkflows. Diese Aktivität wird verwendet, um den Startstatus, den Endstatus und alle potenziellen Status zu repräsentieren, die dazwischen auftreten können.
Der erste Schritt beim Erstellen eines Statuscomputers besteht darin, alle benötigten Status auf der Designoberfläche zu platzieren, indem die Statusaktivität aus der Workflowtoolbox gezogen und jedem Status ein geeigneter Name zugewiesen wird. Workflowstatus werden mithilfe des Eigenschaftendialogfelds auf genau dieselbe Weise wie Windows-Steuerelemente in einem Windows Forms-Projekt benannt. Abbildung 4 ist ein Beispiel für einen einfachen Statuscomputerworkflow, der aus drei Status besteht: Gesendet, Bestellt und Abgeschlossen.
Abbildung 4 Einfacher Statuscomputerworkflow (Klicken Sie zum Vergrößern auf das Bild)
Workflow Foundation muss zur korrekten Laufzeitverwaltung den Start- und den Endstatus kennen. Der nächste Schritt besteht daher darin, diese Status über den Eigenschaftendialog des Workflows anzugeben. Um diesen Dialog aufrufen zu können, muss der Eigenschaftendialog in Visual Studio .NET sichtbar sein. Klicken Sie anschließend auf die Designoberfläche Ihres Workflows, oder klicken Sie mit der rechten Maustaste auf den Workflowdesigner, und wählen Sie „Properties“ (Eigenschaften) aus. Unten rechts in Abbildung 4 ist der Eigenschaftendialog für einen Statuscomputerworkflow zu sehen. Die Eigenschaften „InitialStateName“ und „CompletedStateName“ dienen der Angabe des Start- und des Endstatus. Sobald diese Eigenschaften angegeben sind, ändert der Designer die grafische Abbildung der spezifizierten Status. Sehen Sie sich Abbildung 4 genau an: Auf dem Startstatus ist das grüne Symbol zu sehen, auf dem Endstatus das rote Symbol.
Die Statusaktivität ist eine zusammengesetzte Aktivität und kann also andere Aktivitäten enthalten. Auch hier sind wieder einige Einschränkungen zu berücksichtigen. Eine Statusaktivität kann nur eine einzige StateInitialization-Aktivität, nur eine einzige StateFinalization-Aktivität, eine oder mehrere EventDriven-Aktivitäten und eine oder mehrere andere Statusaktivitäten für verschachtelte Status enthalten. Dies sind die einzigen vier Standardaktivitäten, die innerhalb einer Statusaktivität platziert werden können. Verschachtelte Status würden thematisch den Umfang dieses Artikels sprengen, und die Verwendung der EventDriven-Aktivität wird im nächsten Abschnitt beschrieben. In unserem einfachen Beispiel für einen Statuscomputer werden nur die StateInitialization- und die StateFinalization-Aktivität verwendet.
Experimentieren Sie am besten ein bisschen mit der StateInitialization- und der StateFinalization-Aktivität, damit Sie ein Gefühl dafür bekommen, wie Sie mit dem Statuscomputerdesigner arbeiten können. Wenn Sie mit diesen beiden Aktivitäten ein wenig herumspielen, werden Sie außerdem besser verstehen, wie sich Statuscomputerworkflows steuern lassen.
Alle Status im einfachen Beispiel in Abbildung 4 (mit Ausnahme des abgeschlossenen Status) haben eine StateInitialization- und eine StateFinalization-Aktivität erhalten. Sobald ein Status als abgeschlossen spezifiziert ist, können ihm nämlich keine Aktivitäten mehr hinzugefügt werden. Das liegt daran, dass der Übergang zum Status „Abgeschlossen“ das Ende eines Workflowlebenszyklus signalisiert.
Wenn die Programmsteuerung an eine Statusaktivität übergeben wird und sie mit der Ausführung beginnt, überprüft die Statusaktivität, ob eine StateInitialization-Aktivität vorhanden ist. Ist eine Aktivität vorhanden, wird sie ausgeführt. Ähnlich wird, wenn eine Statusaktivität die Steuerung an einen anderen Status übergibt, überprüft, ob eine StateFinalization-Aktivität vorhanden ist. Wenn ja, wird sie ausgeführt. Sowohl die StateInitialization- als auch die StateFinalization-Aktivität sind zusammengesetzte Aktivitäten. Im Gegensatz zur Statusaktivität gibt es sehr wenige Einschränkungen in Bezug darauf, was innerhalb dieser Aktivitäten platziert werden kann. Anders ausgedrückt: Alle Aktivitäten, die in einem sequenziellen Workflow verwendet werden können, können innerhalb dieser Aktivitäten platziert werden. Visual Studio bietet eine andere Entwurfsansicht für die Platzierung von Logik in diesen zusammengesetzten Aktivitäten. In Abbildung 5 ist die Entwurfsansicht zu sehen, die nach einem Doppelklick auf die StateInitialization-Aktivität des in Abbildung 4 gezeigten Status „Gesendet“ angezeigt wird. Hier hat der Status „Gesendet“ eine StateInitialization-Aktivität namens „SubmittedInitialization“. Über die Entwurfsansicht können zusätzliche Aktivitäten innerhalb der StateInitialization-Aktivität platziert werden. Im Beispiel in Abbildung 5 wurden eine Codeaktivität und eine SetState-Aktivität innerhalb der SubmittedInitialization-Aktivität platziert. Der folgende Code wurde in das Execute-Ereignis der Codeaktivität gesetzt:
Abbildung 5 Entwurfsansicht für eine StateInitialization-Aktivität 
private void codeSubmittedInitialization_ExecuteCode(object sender, 
    EventArgs e)
{
    Console.WriteLine("The Submitted state has been initialized at " + 
    DateTime.Now.ToString() + ".");
}
Mit der SetState-Aktivität (setStateOrdered in Abbildung 5) wird die Steuerung an einen anderen Status im StateMachine-Workflow übergeben. Für die Verwendung dieser Aktivität ist kein Code notwendig. In Abbildung 6 ist der Eigenschaftendialog für setStateToOrdered zu sehen. Die Eigenschaft „TargetStateName“ muss auf einen gültigen Status im StateMachine-Workflow gesetzt werden. Die StateFinalization-Aktivität des aktuellen Status wird sofort, nachdem diese Aktivität ausgeführt wird, ausgeführt, und die Steuerung wird an den Status „Bestellt“ übergeben. Innerhalb der SubmittedInitialization-Aktivität werden keine zusätzlichen Aktivitäten ausgeführt. Daher muss darauf geachtet werden, dass diese Aktivität die letzte Aktivität ist. Die StateFinalization-Aktivität für unseren Status „Gesendet“ wurde mit einer einzelnen Codeaktivität mit dem folgenden Code in seinem Execute-Ereignis konfiguriert:
Abbildung 6 Eigenschaften für eine SetState-Aktivität (Klicken Sie zum Vergrößern auf das Bild)
  private void 
  codeSubmittedFinalization_  ExecuteCode(
  object sender, EventArgs e)
  {
    Console.WriteLine("The Submitted " +
    "state has been finalized at " + 
    DateTime.Now.ToString() + ".");
  }
Wichtiger Hinweis: Eine SetState-Aktivität kann nicht innerhalb einer StateFinalization-Aktivität platziert werden. Das würde auch keinen Sinn ergeben, da eine StateFinalization-Aktivität nur ausgeführt werden kann, wenn zuvor ein SetState ausgeführt wurde. Eine SetState-Aktivität kann sich nur innerhalb einer StateInitialization- oder einer EventDriven-Aktivität befinden.
Um im Designer wieder zur ursprünglichen Entwurfsansicht zurückzukehren, die den ganzen Workflow anzeigt, klicken Sie einfach auf den Namen des Workflows, der in der linken oberen Ecke des Designers zu sehen ist (siehe Abbildung 5). Dieser Bereich des Designers wird für die Navigation verwendet. Wenn Sie auf „SimpleStateMachine“ klicken, wird statt der Entwurfsansicht wieder die ursprüngliche Ansicht angezeigt, die alle Status im Workflow zeigt. Wenn Ihr Statuscomputer sehr kompliziert ist und viele Ebenen verschachtelter Status enthält, zeigt Ihnen dieser Navigationsbereich des Designers genau, wo Sie sich gerade im Workflow befinden.
Der Statuscomputerdesigner erkennt jetzt Statusübergänge, die über die setState-Aktivitäten spezifiziert wurden, und zeichnet die entsprechenden Übergangspfeile auf der Entwurfsoberfläche. Die Eigenschaft „TargetStateName“ für SetState-Aktivitäten kann auf zwei Weisen geändert werden. Die erste, die gerade beschrieben wurde, besteht darin, den Eigenschaftendialog zu verwenden. Die Eigenschaft „TargetStateName“ kann auch direkt von der Entwurfsoberfläche des Workflows aus festgelegt werden, indem das Pfeilende eines Übergangspfeils zur gewünschten Statusaktivität gezogen und dort abgelegt wird.
Der Status „Bestellt“ in unserem einfachen Statuscomputerworkflow (Abbildung 5) wurde auf ähnliche Weise wie der Status „Gesendet“ eingerichtet. Anders ausgedrückt: Sowohl in der StateInitialization- als auch in der StateFinalization-Aktivität wurde zum Schreiben einer Meldung an die Konsole eine Codeaktivität verwendet. Zusätzlich wurde in der StateInitialization-Aktivität zur Übergabe der Steuerung an den Status „Abgeschlossen“ im Statuscomputerworkflow eine SetState-Aktivität verwendet.
Der Workflow kann jetzt verwendet werden. Der Code zum Instanziieren der Workflowlaufzeit, zum Erstellen einer Instanz dieses Workflows und zum Starten des Workflows von einer Konsolenanwendung ist hier dargestellt:
static void Main(string[] args)
{
    // Create the workflow runtime.
    using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        WorkflowInstance instance =
            workflowRuntime.CreateWorkflow(typeof(SimpleStateMachine));
        instance.Start();

        Console.ReadLine();
    }
}
Sobald dieser Code ausgeführt wird, erscheint im Konsolenausgabefenster folgende Ausgabe:
The Submitted state has been initialized at 8/6/2007 7:40:36 PM.
The Submitted state has been finalized at 8/6/2007 7:40:36 PM.
The Ordered state has been initialized at 8/6/2007 7:40:36 PM.
The Ordered state has been finalized at 8/6/2007 7:40:36 PM.
Der in diesem Abschnitt beschriebene Workflow enthält drei der benötigten Status (Gesendet, Bestellt und Abgeschlossen) für den Anforderungsbearbeitungsworkflow, der zu Beginn des Artikels beschrieben wurde. Ich werde jetzt die anderen Status (Zugewiesen, Genehmigt und Abgelehnt) in diesen Workflow einfügen, um das Backtracking sowie Status zu illustrieren, die in mehr als einen möglichen Status übergehen können. Außerdem werde ich Ereignisse hinzufügen.

Kommunikation mit Statuscomputerworkflows
Nach diesem ersten etwas theoretischeren Teil folgt nun ein Teil mit stärkerem Praxisbezug. Statuscomputer in der realen Welt laufen oftmals über einen langen Zeitraum, wobei sie die meiste Zeit in einem bestimmten Status pausieren und auf eine Eingabe warten, die von außerhalb des eigentlichen Workflows kommen muss. Ein ausführender Status kann über die EventDriven-Aktivität angehalten werden, um auf externe Informationen zu warten. Wie bereits weiter oben erklärt, ist die EventDriven-Aktivität eine der wenigen Aktivitäten, die in eine Statusaktivität gesetzt werden kann (die anderen sind StateInitialization und StateFinalization). Externe Informationen werden über Ereignisse an die EventDriven-Aktivität übergeben. Genauer gesagt: Ereignisse werden über einen externen Datendienst ausgelöst und von der EventDriven-Aktivität empfangen. Es ist nicht so leicht, die EventDriven-Aktivität einzurichten, aber wenn Sie sich an die folgenden Schritte halten, wird dieser Vorgang ein wenig einfacher.
  1. Legen Sie die Ereignisse fest, die für den Datenaustausch und für Statusübergänge erforderlich sind.
  2. Definieren Sie eine externe Datenaustauschschnittstelle.
  3. Fügen Sie dem Statuscomputerworkflow EventDriven-Aktivitäten hinzu.
  4. Erstellen Sie einen Verweis auf die externe Datenaustauschschnittstelle.
  5. Implementieren Sie die externe Datenaustauschschnittstelle.
  6. Fügen Sie der Workflowlaufzeit die externe Datenaustauschschnittstelle hinzu.
  7. Tauschen Sie Daten und Übergangsstatus über die externe Datenaustauschschnittstelle aus.
In Abbildung 7 ist genau zu sehen, wie sich die in den vorherigen Schritten erwähnten Komponenten zu einem Gesamtgebilde zusammenfügen.
Abbildung 7 Konfiguration und Einsatz eines Statuscomputerworkflows (Klicken Sie zum Vergrößern auf das Bild)

Für den Datenaustausch und Statusübergänge erforderliche Ereignisse
Der erste Schritt besteht darin, festzulegen, welche Ereignisse von jedem Status im Statuscomputerworkflow benötigt werden. Statuscomputerereignisse führen typischerweise zur Änderung von Status im Workflow. Um herauszufinden, welche Ereignisse benötigt werden, ist es daher am besten, zunächst die Anforderungen zu ermitteln und dann nach Schlüsselwörtern zu suchen, die Statusübergänge anzeigen. Denken Sie an den logischen Entwurf in Abbildung 1 zurück: Um diesen logischen Entwurf zu erstellen, mussten wir uns zunächst die Anforderungen ansehen und dann darauf aufbauend die notwendigen Status und Statusübergänge ermitteln. Anhand dieser Informationen kann auch ermittelt werden, welche Ereignisse benötigt werden. Abbildung 8 baut auf den Daten in Abbildung 2 auf, in der die Statusübergänge für jeden Status im Anforderungsbearbeitungsworkflow aufgeführt sind. Abbildung 8 zeigt jeden Status im Workflow, die Ereignisse, auf die jeder Status wartet, sowie den Status, in den für jedes aufgeführte Ereignis übergegangen wird. Wenn von der Workflowinstanz zum Wechsel in einen neuen Status Daten benötigt werden, bietet Workflow Foundation Funktionen, mit denen Informationen als Ereignisparameter übergeben werden können.

Status Ereignisname Übergang
Gesendet OnAssigned Zugewiesen
Zugewiesen OnApproved Genehmigt
Zugewiesen OnRejected Abgelehnt
Genehmigt OnOrdered Bestellt
Abgelehnt OnReassigned Zugewiesen
Abgelehnt OnCanceled Abgeschlossen
Bestellt OnOrderReceived Abgeschlossen
Der Status „Zugewiesen“ wartet auf zwei Ereignisse. Der Status „Zugewiesen“ wartet simultan auf diese beiden Ereignisse. Der Statuswechsel hängt vom empfangenen Ereignis ab. Externe Entitäten können auf diese Weise den Pfad bestimmen, dem ein Statuscomputerworkflow folgt. (Der Status „Abgelehnt“ wartet ebenfalls auf zwei Ereignisse.)

Definition einer externen Datenaustauschschnittstelle
Der nächste Schritt besteht darin, diese Ereignisse innerhalb einer .NET-Standardschnittstelle zu definieren. In Abbildung 9 ist die für den Anforderungsbearbeitungsworkflow benötigte Schnittstelle zu sehen. Abbildung 10 zeigt die benutzerdefinierte EventArgs-Klasse, über die Daten an eine Instanz eines Workflows übergeben werden, wenn eines dieser Ereignisse ausgelöst wird.
namespace ExternalDataExchange
{
    [Serializable]
    public class SupplyFulfillmentArgs : ExternalDataEventArgs
    {
        public SupplyFulfillmentArgs(System.Guid InstanceId) : 
            base(InstanceId) { }

        private string assignedTo;
        private string orderID;

        public string AssignedTo
        {
            get { return assignedTo; }
            set { assignedTo = value; }
        }

        public string OrderID
        {
            get { return orderID; }
            set { orderID = value; }
        }
    }
}

namespace ExternalDataExchange
{
    [ExternalDataExchange()]
    public interface IEventService
    {
        event EventHandler<SupplyFulfillmentArgs> Assigned;
        event EventHandler<SupplyFulfillmentArgs> Approved;
        event EventHandler<SupplyFulfillmentArgs> Rejected;
        event EventHandler<SupplyFulfillmentArgs> Reassigned;
        event EventHandler<SupplyFulfillmentArgs> Canceled;
        event EventHandler<SupplyFulfillmentArgs> Ordered;
        event EventHandler<SupplyFulfillmentArgs> OrderReceived;
    }
}

Zur Schnittstelle ist einiges anzumerken. Dies betrifft zum einen die Verwendung des ExternalDataExchange-Attributs. Eine Klasse, die eine mit dem ExternalDataExchange-Attribut markierte Schnittstelle implementiert, kann dem Workflowlaufzeitmodul genau wie jeder andere Dienst hinzugefügt werden. (Persistenz und Nachverfolgung sind Beispiele für andere Dienste, die der Workflowlaufzeit hinzugefügt werden können.)
Außerdem zu beachten ist, dass SupplyFulfillmentArgs, das als Parameter in den in der Schnittstelle deklarierten Ereignissen verwendet wird, von ExternalDataEventArgs erben muss. Darüber hinaus erfordert ExternalDataEventArgs, dass die Workflowinstanz-ID an seinen Konstruktor übergeben wird, damit das Ereignis an der richtigen Workflowinstanz ausgelöst wird. Schließlich muss SupplyFulfillmentArgs als serialisierbar markiert werden, wenn die Workflowlaufzeit es für den beständigen Speicher serialisieren muss.

Hinzufügen von EventDriven-Aktivitäten
Sobald die Schnittstelle für den externen Datenaustausch eingerichtet ist, besteht der nächste Schritt darin, dem Statuscomputer EventDriven-Aktivitäten hinzuzufügen. Ähnlich wie die StateInitialization- und die StateFinalization-Aktivität ist die EventDriven-Aktivität eine zusammengesetzte Aktivität. Ihr Zweck besteht also darin, andere Aktivitäten zu enthalten. Sobald die EventDriven-Aktivität einer Statusaktivität hinzugefügt worden ist, kann die Aktivität auf die gleiche Weise wie die StateInitialization- und die StateFinalization-Aktivität geöffnet werden, um zusätzliche Logik zu definieren. Im Unterschied zur StateInitialization- und zur StateFinalization-Aktivität müssen bei der Platzierung in der EventDriven-Aktivität allerdings einige Regeln befolgt werden. Die EventDriven-Aktivität erbt von der Sequence-Aktivität und fügt die Beschränkung hinzu, dass die erste untergeordnete Aktivität eine Aktivität sein muss, die die öffentliche IEventActivity-Schnittstelle implementiert. Alle folgenden Aktivitäten können beliebigen Typs sein. Im hier gezeigten Beispiel wird die HandleExternalEvent-Aktivität verwendet. Diese Aktivität kann ein Ereignis empfangen, das sich außerhalb der Workflowlaufzeit befindet. Zwei andere Aktivitäten, die ebenfalls die IEventActivity-Schnittstelle implementieren, sind die Delay- und die WebServiceInput-Aktivität.
Im SupplyFulfillment-Workflow gibt es sieben logische Ereignisse, die eine EventDriven-Aktivität erfordern. In Abbildung 8 sind die Informationen zu sehen, die zum Setzen der EventDriven-Aktivitäten in den richtigen Status benötigt werden. Logik, die innerhalb dieser Aktivitäten platziert wird, führt letztendlich zu den Statusänderungen. In Abbildung 11 ist die Designeransicht des SupplyFulfillment-Statuscomputers zu sehen, nachdem alle EventDriven-Aktivitäten hinzugefügt wurden. Die Übergangspfeile beginnen bei den EventDriven-Aktivitäten und enden bei den Statusaktivitäten. In Abbildung 12 ist die in der EventDriven-Aktivität „OnAssigned“ enthaltene Aktivität zu sehen.
Abbildung 11 EventDriven-Aktivitäten in einem Statuscomputerworkflow (Klicken Sie zum Vergrößern auf das Bild)
Abbildung 12 Logik in einer EventDriven-Aktivität 
Technisch gesehen werden die in Abbildung 11 gezeigten StateInitialization- und StateFinalization-Aktivitäten nicht mehr benötigt. Sie sind hier nur zu Demonstrationszwecken mit aufgenommen und enthalten Konsolenmeldungen.
An dieser Stelle sollte erwähnt werden, dass die visuelle Darstellung des Anforderungsbearbeitungsworkflows in Abbildung 11 genauso leicht wie das logische Diagramm in Abbildung 1 zu lesen ist, das mit Microsoft Visio® erstellt wurde. Entwicklungsartefakte, die Entwickler, Architekten und Endbenutzer leicht verstehen und überprüfen können, sind ein wichtiger Aspekt bei der Verwaltung von Geschäftsprozessen.

Erstellen eines Verweises auf die externe Datenaustauschschnittstelle
Sobald die EventDriven-Aktivitäten eingerichtet und die untergeordneten Aktivitäten für jede EventDriven-Aktivität auf ähnliche Weise wie in Abbildung 11 konfiguriert sind, besteht der nächste Schritt darin, die HandleExternalEvent-Aktivitäten zu konfigurieren. Sie erinnern sich: Eine der Konstruktionsregeln beim Einrichten einer EventDriven-Aktivität ist, dass die erste untergeordnete Aktivität eine Aktivität wie die HandleExternalEvent-Aktivität sein muss. Das ist in der Logik in Abbildung 12 zu sehen, bei der eine EventDriven-Aktivität namens „OnAssigned“ als erste untergeordnete Aktivität eine HandleExternalEvent-Aktivität namens „handleAssigned“ gefolgt von einer SetState-Aktivität namens „SetStateAssigned“ hat.
Durch die HandleExternalEvent-Aktivität wird ein StateMachine-Workflow blockiert, während auf die Verarbeitung eines Ereignisses gewartet wird, das von einem externen Datenaustauschdienst ausgelöst wird. Das spezifische Ereignis, auf das eine HandleExternalEvent-Aktivität wartet, wird im Eigenschaftendialog spezifiziert (siehe Abbildung 13). Die erste Eigenschaft, die festgelegt werden muss, ist die Eigenschaft „InterfaceType“, die auf eine Schnittstelle gesetzt werden muss, die mit dem Attribut „ExternalDataExchange“ markiert ist. Im Fall des Anforderungsbearbeitungsworkflows ist diese Schnittstelle die in Abbildung 9 gezeigte IEventService-Schnittstelle. Sobald die Eigenschaft „InterfaceType“ festgelegt ist, kann die Eigenschaft „EventName“ spezifiziert werden. Welcher Eigenschaftendialog angezeigt wird, hängt von der über die Eigenschaft „InterfaceType“ spezifizierten Schnittstelle ab. Der Dialog enthält ein Dropdownfeld für die Eigenschaft „EventName“. Der in Abbildung 13 gezeigte Dialog ist für das Ereignis „OnAssigned“ des Anforderungsbearbeitungsworkflows.
Abbildung 13 handleAssigned-Eigenschaften (Klicken Sie zum Vergrößern auf das Bild)
Bevor dieser Dialog geschlossen wird, ist ein weiterer Punkt zu beachten. Sie erinnern sich, dass alle Ereignisse in der ExternalDataExchange.IEventService-Schnittstelle ein SupplyFulfillmentArgs-Argument benötigen. Dieses Argument kann zur Weitergabe von Daten an eine Instanz eines Workflows verwendet werden, wenn ein externes Ereignis ausgelöst wird und der Workflow das Ereignis empfängt. Es gibt zwei Möglichkeiten, diesen Datentyp für andere Aktivitäten innerhalb des Workflows zugänglich zu machen. Eine Möglichkeit ist, die in Abbildung 13 gezeigte Eigenschaft „e“ zu verwenden. Über diese Eigenschaft können Sie eine Eigenschaft innerhalb des Workflows spezifizieren, die zum Halten des vom Ereignis übergebenen Arguments verwendet werden kann. Sobald dieser Ereignisparameter in einer Workfloweigenschaft festgelegt ist, kann er von anderen Aktivitäten im Workflow verwendet werden. Natürlich muss die angegebene Eigenschaft vom gleichen Typ wie der Ereignisparameter sein. Im Fall des SupplyFulfillment-Workflows wäre das der Typ „SupplyFulfillmentArgs“. Alternativ kann die Eigenschaft „Invoked“ verwendet werden, um einen Ereignishandler innerhalb des Workflows zu spezifizieren. Dieser Ereignishandler wird aufgerufen, nachdem das externe Ereignis empfangen wurde. An ihn wird ein Parameter des Typs „ExternalDataEventArgs“ übergeben, der in den richtigen Typ (SupplyFulfillmentArgs) umgewandelt werden kann.
An dieser Stelle ist zu beachten, dass die HandleExternalEvent-Aktivität nur mit der ExternalDataExchange-Schnittstelle und nicht mit einer echten Implementierung der Schnittstelle arbeitet.

Implementieren eines externen Datenaustauschdiensts
Zur erfolgreichen Implementierung eines externen Datenaustauschdiensts müssen Sie die Schnittstelle implementieren, auf die von den HandleExternalEvent-Aktivitäten im Workflow verwiesen wird. Insbesondere die IEventService-Schnittstelle muss implementiert werden. Der folgende Code erstellt die EventService-Klasse und implementiert die Schnittstelle:
[Serializable]
public class EventService : IEventService
{
    public event EventHandler<SupplyFulfillmentArgs> Assigned;
    public event EventHandler<SupplyFulfillmentArgs> Approved;
    public event EventHandler<SupplyFulfillmentArgs> Rejected;
    public event EventHandler<SupplyFulfillmentArgs> Reassigned;
    public event EventHandler<SupplyFulfillmentArgs> Canceled;
    public event EventHandler<SupplyFulfillmentArgs> Ordered;
    public event EventHandler<SupplyFulfillmentArgs> OrderReceived;
    ...
 }
Da Ereignisse nur von innerhalb jener Klasse ausgelöst werden können, in der sie definiert sind, müssen wir zur leichteren Auslösung von Ereignissen Hilfsfunktionen hinzufügen. Diese Klasse benötigt eine Hilfsfunktion pro Ereignis. Der folgende Code zeigt die Hilfsfunktion für das Assigned-Ereignis:
public void RaiseAssignedEvent(System.Guid instanceId, string 
    assignedTo)
{
      // Check to see if event is defined
    if (this.Assigned != null)
    {
        // Create the EventArgs for this event
        LocalService.SupplyFulfillmentArgs args = new 
            LocalService.SupplyFulfillmentArgs(instanceId);
        args.AssignedTo = assignedTo;

        // Raise the event
        this.Assigned(this, args);
    }
}
Wenn das Ereignis ausgelöst wird, werden an alle registrierten Delegaten zwei Parameter übergeben. Der erste Parameter ist der Absender. Der obige Code gibt die aktuelle Instanz der EventService-Klasse weiter, die als serialisierbar markiert werden muss, damit eine Instanz davon an den Absender übergeben werden kann. Geschieht dies nicht, wird die Fehlermeldung zurückgegeben, dass das Ereignis nicht übergeben werden konnte. Hier ist ein Beispiel für diese Fehlermeldung:
  Event "Assigned" on interface type 
  "ExternalDataExchange.IEventService"
  for instance id "0f9e8545-39bf-48b6-b890-
  c12dec11cb9f" cannot be delivered.
Der zweite Parameter ist der SupplyFulfillmentArgs-Parameter. Wenn diese Klasse instanziiert wird, erfordert sie die Workflowinstanz-ID, also die GUID (Global Unique Identifier), die generiert wurde, als der Workflow zuerst instanziiert wurde. Diese GUID wird von der Workflowlaufzeit verwendet, um die Workflowinstanz zu finden, die das Ereignis erhalten soll. Damit das passiert, muss aber eine Instanz der EventService-Klasse der Workflowlaufzeit als externer Dienst hinzugefügt werden.

Hinzufügen eines externen Datenaustauschdiensts zur Workflowlaufzeit
Da die Workflowlaufzeit die Ausführung und Interaktion aller instanziierten Workflows verwaltet, muss die Klasse, die gerade erstellt wurde, der Workflowlaufzeit als externer Datenaustauschdienst hinzugefügt werden. Der folgende Code zeigt, wie der Workflowlaufzeit eine Instanz der EventService-Klasse als ExternalDataExchange-Dienstklasse hinzugefügt wird:
// Create a new instance of the local service and host it in an 
//ExternalDataExchangeService.
ExternalDataExchangeService externalDataSvc = new 
    ExternalDataExchangeService();
wr.AddService(externalDataSvc);
eventService = new EventService();
externalDataSvc.AddService(eventService);
Die nachstehend beschriebene Vorgehensweise muss genau befolgt werden. Zunächst muss der externe Datendienst erstellt und der Workflowlaufzeit hinzugefügt werden. Danach kann die EventService-Klasse der ExternalDataExchangeService-Klasse hinzugefügt werden. Wenn Sie versuchen, das ExternalDataExchangeService-Objekt zu verwenden, bevor es der Workflowlaufzeit hinzugefügt wird, wird die Fehlermeldung zurückgegeben, dass der WorkflowRuntime-Container keinen ExternalDataExchangeService enthält.
Anschließend finden Ereignisse, die von der Instanz der EventService-Klasse ausgelöst wurden, ihren Weg zur richtigen Instanz eines Workflows und zur richtigen HandleExternalEvent-Aktivität innerhalb des Workflows.

Verwenden des externen Datenaustauschs
Jetzt ist alles eingerichtet und der externe Datenaustausch kann zum Austauschen von Daten und Ändern der Status im Workflow verwendet werden. Die Verwendung des externen Datenaustauschs ist so einfach wie das Aufrufen der Hilfsfunktionen, die wie weiter oben gezeigt in der EventService-Klasse eingerichtet wurden. Der folgende Codeausschnitt zeigt die Verwendung der Hilfsfunktion, die den Workflowstatus von „Gesendet“ in „Zugewiesen“ ändert. An die Funktion werden die Workflowinstanz-ID und ein assignTo-Parameter übergeben. Beide Parameter werden in eine Instanz der SupplyFulfillmentArgs-Klasse verpackt, damit sie über das Ereignis „Zugewiesen“ an den Workflow übergeben werden können. Wie bereits erwähnt, wird der workflowInstanceID-Parameter von der Workflowlaufzeit verwendet, um das Assigned-Ereignis an der richtigen Workflowinstanz auszulösen. Der assignTo-Parameter („Joe“) wird direkt an den Workflow übergeben, der während der Workflowausführung verwendet werden soll:
eventService.RaiseAssignedEvent(workflowInstanceId, "Joe");
Ein wichtiger Hinweis: Ein aktiver Statuscomputerworkflow wartet immer nur auf Ereignisse innerhalb der aktuellen Statusaktivität. Werden andere Ereignisse ausgelöst, empfängt der aufrufende Code eine Ausnahme. Ein Beispiel: Wenn der SupplyFullfilment-Workflow instanziiert ist, befindet er sich in seinem Startstatus (dem Status „Gesendet“). Der Workflow wartet also darauf, dass das Assigned-Ereignis ausgelöst wird. Wird eine andere Hilfsfunktion aufgerufen, die andere Ereignisse – Approved (Genehmigt), Rejected (Abgelehnt), Reassigned (Erneut zugewiesen), Canceled (Abgebrochen), Ordered (Bestellt) und OrderReceived (Bestellung erhalten) – auslöst, wird die Fehlermeldung zurückgegeben, dass das Ereignis nicht übergeben werden konnte. Das folgende Beispiel zeigt eine Fehlermeldung, die auftritt, wenn sich der Workflow in einem anderen Status als „Genehmigt“ befindet und das Ordered-Ereignis aufgerufen wird:
Event "Ordered" on interface type "ExternalDataExchange.IEventService" for instance id "59657ed0-1532-42c5-8abe-6523bf121fff" cannot be delivered.
Wie Sie sehen können, tritt diese generische Fehlermeldung auf, wenn ein Ereignis nicht übergeben werden konnte. In dieser Meldung befinden sich keine Informationen, aus denen entnehmbar ist, was genau nicht funktioniert hat.
Natürlich fragt man sich jetzt, wie man stabilen Workflowcode schreiben kann. Oder: Wie kann Ihr Code den aktuellen Status einer Statuscomputerinstanz ermitteln, damit Sie programmgesteuert sicherstellen können, dass das richtige Ereignis an den Workflow gesendet wird? Es gibt einige nützliche APIs, die vom Code für einen Statuscomputerworkflow verwendet werden können.

Nützliche Statuscomputer-APIs
WF enthält eine Dienstprogrammklasse namens „StateMachineWorkflowInstance“, die speziell für die Verwaltung von Statuscomputerworkflowinstanzen konzipiert wurde. Abbildung 14 enthält eine kurze Beschreibung des Konstruktors, der Eigenschaften und der Methoden der StateMachineWorkflowInstance-Klasse.

Öffentlicher Konstruktor
Name Beschreibung
StateMachineWorkflowInstance Dies ist der Konstruktor. Er erfordert zwei Parameter. Der erste ist eine Instanz der Workflowlaufzeit. Der zweite ist eine GUID, die die Statuscomputerinstanz repräsentiert, die von den Eigenschaften und Funktionen dieser Klasse abgefragt oder verwaltet wird.
Öffentliche Eigenschaften
Name Beschreibung
CurrentState Schreibgeschützt. Gibt ein StateActivity-Objekt für den aktuellen Status zurück.
CurrentStateName Schreibgeschützt. Gibt eine Zeichenfolge zurück, die den Namen der aktuellen Statusaktivität repräsentiert.
InstanceID Schreibgeschützt. Gibt eine GUID zurück, die den Statuscomputerworkflow eindeutig innerhalb der Workflowlaufzeit identifiziert.
PossibleStateTransitions Schreibgeschützt. Gibt ReadOnlyCollection<Zeichenfolge> zurück, das die möglichen Statusübergänge vom aktuellen Status repräsentiert.
StateHistory Schreibgeschützt. Gibt ReadOnlyCollection<Zeichenfolge> zu den Statusübergängen zurück, die vom aktuellen Workflow bereits durchgeführt wurden. Für diese Eigenschaft muss der Workflowlaufzeit ein Nachverfolgungsdienst hinzugefügt werden.
StateMachineWorkflow Schreibgeschützt. Gibt einen StateMachineWorkflowActivity-Typ zurück. Dies ist eine Kopie der Workflowdefinition und nicht die Liveinstanzstruktur. Daher sollte diese Eigenschaft nie zum Abrufen von Laufzeitwerten verwendet werden.
Status Schreibgeschützt. Gibt eine ReadOnlyCollection<Zeichenfolge>-Auflistung aller Status in der Definition des aktuellen Workflows zurück. Wie die StateMachineWorkflow-Eigenschaft enthält diese Eigenschaft nur Definitionen und keine Livedaten.
WorkflowInstance Schreibgeschützt. Gibt den aktuellen WorkflowInstance-Typ zurück, der die aktuelle Instanz repräsentiert. Diese Eigenschaft bietet Zugriff auf die Liveinstanzstruktur.
Öffentliche Methoden
Name Beschreibung
EnqueueItem Sendet eine Meldung an die Warteschlange eines Statuscomputerworkflows. Wird in der Regel nicht benötigt. Die HandleExternalEvent-Aktivität, die weiter oben beschrieben wurde, reiht Meldungen mit einem Programmiermodell, das weniger fehleranfällig ist, in eine Warteschlange ein.
SetState Sorgt für einen Übergang zu einem Status, der über den einzigen Parameter angegeben wird. Kann verwendet werden, um zu einem beliebigen Status im Workflow überzugehen, selbst wenn zum angegebenen Status nicht bei einer normalen Ausführung des Workflows übergegangen werden könnte.
Beachten Sie aber Folgendes, wenn Sie diese Klasse verwenden: Erstens: Statuscomputer, die ereignisgesteuert sind (wie der SupplyFulfillment-Workflow) sind inhärent asynchron. Wenn also die in Abbildung 14 gezeigten öffentlichen Eigenschaften sofort nach dem Auslösen eines Ereignisses an einer Statuscomputerinstanz abgefragt werden, geben sie den Status des Workflows nicht akkurat wider. Ereignisgesteuerte Workflows werden angehalten, sobald sie das aktuelle Ereignis verarbeitet haben, und warten auf das nächste Ereignis. Daher ist das OnWorkflowIdled-Ereignis der Workflowlaufzeit ein guter Ort, um eine Instanz eines Statuscomputers mit diesen Eigenschaften abzufragen.
Zweitens: Für die StateHistory-Eigenschaft muss der Workflowlaufzeit ein Nachverfolgungsdienst hinzugefügt werden. Wird diese Eigenschaft ohne Nachverfolgungsdienst verwendet, wird die folgende Fehlermeldung zurückgegeben:
'StateHistory' property requires the 'System.Workflow.Runtime.Tracking.SqlTrackingService' service.
Drittens: Überlegen Sie sich genau, welchen Endbenutzern Sie die Funktionalität der SetState-Methode erklären. Diese Methode kann zu einem Übergang in jeden Status im Workflow führen und sollte am besten von Administratoren oder Managern verwendet werden, die mit Szenarios arbeiten, die vom Standardszenario abweichen.

Weitere wichtige Punkte
In diesem Artikel wurden die Theorie hinter Statuscomputern, die Entwurfszeit und die grundlegenden Aktivitäten behandelt, die zum Erstellen eines nutzbaren Statuscomputers benötigt werden. Darüber hinaus sind aber noch einige weitere Punkte zu berücksichtigen. Erstens: Wenn ein Statuscomputer in einer Serverumgebung ausgeführt werden soll, muss er während der Ausführung Systemressourcen optimieren und darf nicht durch Systemneustarts beeinflusst werden. Außerdem könnte es wünschenswert sein, Verlaufsdaten nachzuverfolgen und zu speichern, damit Geschäftsprozesse basierend auf Nachverfolgungsberichten optimiert werden können. Wenn zum Beispiel der Anforderungsbearbeitungsworkflow in diesem Artikel in einem kleinen Unternehmen eingesetzt werden würde, wäre es interessant zu erfahren, wie lange der Übergang vom Status „Bestellt“ bis zum Status „Abgeschlossen“ bei jedem Workflow dauert. Verletzt ein bestimmter Lieferant fortwährend die Servicelevelverträge, könnte der Geschäftsprozess für den Einkauf neuer Materialien optimiert werden, indem der jeweilige Lieferant einfach weggelassen wird.
Ein weiteres interessantes Thema, das allerdings den Umfang dieses Artikels sprengt, sind menschliche Workflows. Statuscomputer sind ein guter Ausgangspunkt für die Erstellung menschlicher Workflows. Wenn ein Statuscomputer zur Verwaltung von Geschäftsprozessen mit menschlichem Input verwendet werden soll, müssen beim Erstellen der Benutzeroberfläche bestimmte Aspekte berücksichtigt werden. Der Benutzer sollte den gewünschten Pfad durch den Statuscomputer problemlos überschauen können und nur die Optionen sehen, die für den aktuellen Status relevant sind.

Keith Pijanowski ist Plattformstrategieberater für das Microsoft Entwickler- und Plattformteam, das Kunden dabei unterstützt, neue Ideen und Technologien zur Lösung ihrer Geschäftsprobleme umzusetzen. Keith ist außerdem regelmäßig als Referent bei Microsoft-Veranstaltungen in New Jersey und im Raum New York anzutreffen. Er ist über www.KeithPij.com erreichbar.

Page view tracker