MSDN Magazin > Home > Ausgaben > 2006 > December >  Windows Workflow: Erstellen Sie benutzerdefinie...
Windows Workflow
Erstellen Sie benutzerdefinierte Aktivitäten, um Ihre Workflows zu erweitern
Matt Milner

Dieser Artikel basiert auf einer Vorabversion von .NET Framework 3.0. Änderungen an allen Informationen in diesem Artikel sind vorbehalten.
Themen in diesem Artikel:
  • Erstellen grundlegender und zusammengesetzter Aktivitäten
  • Asynchrone und Ereignis-basierte Aktivitäten
  • Anpassen des Designs
  • Validierung und Fehlerbehandlung
In diesem Artikel werden folgende Technologien verwendet:
.NET Framework 3.0
Laden Sie den Code für diesen Artikel herunter: Workflow2006_12.exe (178 KB)
Code online durchsuchen
Benutzerdefinierte Workflow-Aktivitäten sind einer der wichtigsten Aspekte der Windows® Workflow Foundation. Beim Erstellen müssen viele Funktionen beachtet werden. In ihrem Artikel „Simplify Development with the Declarative Model of Windows Workflow Foundation“, der im Januar 2006 in der englischen Ausgabe des MSDN Magazins erschienen ist, erläutern Don Box und Dharma Shukla die wichtigsten Aspekte beim Erstellen von Workflows und die Interaktionen zwischen der Workflowlaufzeit und Aktivitäten. (Siehe msdn.microsoft.com/msdnmag/issues/06/01/WindowsWorkflowFoundation/default.aspx). Der vorliegende Artikel konzentriert sich auf die wichtigsten Komponenten, die zum Erstellen von benutzerdefinierten Aktivitäten für Ihre Geschäftsdomäne benötigt werden, unter anderem Laufzeitaufgaben, Entwurfszeit und asynchrone Aktivitätenentwicklung.
Beim Erstellen einer benutzerdefinierten Aktivität müssen Sie sich zuerst entscheiden, ob Sie eine einfache oder eine zusammengesetzte Aktivität erstellen möchten. Bei einfachen oder grundlegenden Aktivitäten sind Logik und Ausführung im Code der Aktivität verankert. Beispiele für einfache Aktivitäten sind die SendEmail-Aktivität im Windows SDK oder eine Aktivität zur Datenabfrage einer Datenbank.
Zusammengesetzte Aktivitäten hingegen benötigen untergeordnete Aktivitäten, um die Aufgaben durchzuführen. Sie können zusammengesetzte Aktivitäten je nach Anforderung auf zwei Arten erstellen. Zum einen können Sie eine zusammengesetzte Aktivität erstellen, der Benutzer während der Entwurfszeit untergeordnete Aktivitäten hinzufügen können und die die Ausführung dieser untergeordneten Aktivitäten steuert. Beispiel: Mit der While-Aktivität von Windows Workflow Foundation können Sie eine untergeordnete Aktivität hinzufügen und anschließend die Schleifenfunktion der While-Aktivität konfigurieren. Die wichtigste Aufgabe der zusammengesetzten While-Aktivität ist die Verwaltung der Ausführung ihrer untergeordneten Aktivitäten. Zum anderen können Sie eine zusammengesetzte Aktivität erstellen, die auf einer bestehenden zusammengesetzten Aktivität basiert, z. B. die Sequence-Aktivität, und dieser eine Gruppe an Aktivitäten als untergeordnete Aktivitäten hinzufügen, um eine wieder verwendbare Komponenten zu definieren.
Eine wiederverwendbare Aktivität, z. B. eine Aktivität zur Genehmigung durch den Manager, hat mehrere Schritte, die Sie am einfachsten anhand einer Sammlung bestehender Aktivitäten entwerfen können. Die Aktivität zur Genehmigung durch den Manager könnte beispielsweise Aktivitäten wie IfElse verwenden, um zu bestimmen, ob der Manager online ist. Wenn er online ist, könnte eine Sofortnachricht gesendet werden, anderenfalls würde eine E-Mail ausreichen. Diese Aktivität enthält die gesamte komplexe Logik zur Genehmigungsanforderung, bei der es sich allein schon um einen Workflow handelt. Benutzern dieser Aktivität bleiben die Komplexität und die Aufgabe, den Manager selbst zu kontaktieren, erspart, wenn sie diese zusammengesetzte Aktivität in ihrem Workflow einsetzen.
Werfen Sie als erstes einen Blick auf eine grundlegende Aktivität, um die zum Erstellen von Aktivitäten benötigten Konzepte zu verstehen, und bauen Sie diese Aktivität dann langsam zu einer komplexeren Aktivität aus. In diesem Artikel werden zwei Grundaktivitäten verwendet, um diese Konzepte zu erläutern: eine Aktivität zum Erstellen eines Benutzers im ASP.NET-Mitgliedschaftsspeicher und eine benutzerdefinierte Switch-Aktivität, um eine Ausführung ähnlich wie das Code-Konzept mit dem gleichen Namen zu entwerfen. Dem vollständigen Quellcode für diese Aktivitäten sowie weitere Beispiele finden Sie im Abschnitt mit Code-Downloads (eventuell in englischer Sprache) für diesen Artikel.

Erstellen einer grundlegenden Aktivität
Das Erstellen einer Aktivität unterscheidet sich in vielerlei Hinsicht kaum vom Erstellen einer Komponente. Eine Aktivität ist letztlich eine wiederverwendbare Komponente, die die Funktionen von Windows Workflow Foundation, dem Framework, in dem sie ausgeführt wird, nutzt. Der erste Schritt beim Erstellen einer Aktivität besteht darin, die Funktion und die Schnittstelle zu bestimmen. Die CreateUser-Aktivität hat beispielsweise die Funktion, einen Benutzer mithilfe des Mitgliedschaftsanbietermodells von ASP.NET zu erstellen. Für die Schnittstelle sind die folgenden Eigenschaften zum Erstellen eines Benutzers notwendig: z. B. E-Mail-Adresse, Benutzername und Kennwort.
Der Code für die Funktionen einer grundlegenden Aktivität wird in die überschriebene Execute-Methode der zugrunde liegenden Activity-Klasse geschrieben. Neben dem funktionsspezifischen Code der Aktivität haben Sie als Aktivitätsentwickler die Verantwortung, den Status der Aktivität zurückzugeben. Für grundlegende Aktivitäten handelt es sich dabei meist um den Status „Closed“. Wenn „Closed“ zurückgegeben wird, gibt dies der Workflowlaufzeit an, dass die Ausführung der Aktivität abgeschlossen wurde und die Laufzeit die nächste Aktivität des Workflows planen kann. Abbildung 1 zeigt eine grundlegende Aktivität, mit der ein Benutzer im Mitgliedschaftssystem von ASP.NET 2.0 erstellt wird. Weitere Informationen zum Aktivitätenlebenszyklus und Vertrag zwischen Laufzeit und Aktivitäten erhalten Sie im zuvor erwähnten Artikel von Don Box und Dharma Shukla.
public string Password
{
    get { return _password; } set {_password = value; }
}
 
public string Email
{
    get { return _email; } set{ _email = value; }
}
 
public string UserName
{
    get { return _username; } set{ _username = value; }
}

public string MembershipProviderName
{
    get { return _provider; } set{ _provider = value; }
}

protected override ActivityExecutionStatus Execute(
    ActivityExecutionContext executionContext)
{
    MembershipProvider mp = String.IsNullOrEmpty(MembershipProviderName) 
        ? Membership.Provider : 
        Membership.Providers[MembershipProviderName];
     
    MembershipCreateStatus status;
    mp.CreateUser(UserName, Password, Email, null, null, true, 
        Guid.NewGuid(), out status);

    return ActivityExecutionStatus.Closed;
}


Abhängigkeitseigenschaften
Das Bereitstellen von Eigenschaften für eine Aktivität ist wichtig, damit Benutzer der Aktivität die Ausführung konfigurieren können. Bei Microsoft® .NET-Standardeigenschaften oder -feldern, wie im vorherigen Beispiel gezeigt, muss der Benutzer einer Aktivität den Code in den Workflow schreiben, um die Werte der Eigenschaft festzulegen. Stellen Sie sich jedoch ein Szenario vor, in dem Sie einen Mechanismus für weniger technisch bewandte Mitarbeiter bereitstellen möchten, mit dem diese Workflows erstellen können. Die Benutzer sollen nicht alle Code schreiben müssen, nur um Daten aus einer Aktivität mit einer anderen zu verbinden. Mit dem deklarativen Windows Workflow Foundation-Modell sind solche Szenarien leichter umsetzbar, und die Abhängigkeitseigenschaften sind eine der Funktionen, die dieses Modell unterstützen.
Mithilfe von Abhängigkeitseigenschaften können Sie Werte einer Aktivität oder einen Workflow-Status speichern. Anders als Standardeigenschaften, bei denen der Wert in der Klasse gespeichert wird, wird der Wert einer Abhängigkeitseigenschaft in einem Wörterbuch gespeichert, das von der DependencyObject-Basisklasse verwaltet wird.
Abhängigkeitseigenschaften aktivieren mehrere Funktionen, die wichtigste von allen ist vermutlich die Aktivitätsbindung. Wie der Name bereits sagt, handelt es sich bei der Aktivitätsbindung um die Bindung einer Eigenschaft einer Aktivität an eine Eigenschaft einer anderen Aktivität bzw. eines Workflows. Wenn Sie die Abhängigkeitseigenschaft an eine andere Eigenschaft binden, wird der Wert automatisch für Sie übertragen. Wenn beispielsweise ein Workflow über eine Eigenschaft verfügt, die für den zu erstellenden Benutzernamen definiert wurde, und Sie eine UserName-Eigenschaft als Abhängigkeitseigenschaft definiert haben, dann können Sie die UserName-Eigenschaft an die Eigenschaft im Workflow binden. Wenn der Workflow mit Parametern gestartet wird, wird der an den Workflow übergebene Wert automatisch über die Bindung an Ihre Aktivität übergeben. Abbildung 2 spiegelt diese Beziehung wider.
Abbildung 2 Bindung mit Abhängigkeitseigenschaften 
Dieser Bindungstyp gibt Komponenten das gleiche leistungsstarke Modell, auf das viele bei der Benutzeroberflächenentwicklung vertrauen. Ähnlich wie die Datenbindung in ASP.NET und Windows Forms vereinfacht die Aktivitätsbindung die Verbindung von Komponenten. Dadurch verliert auch die Vorstellung, dass Nichtprogrammierer einen Workflow erstellen, ihren Schrecken. Bei gut entwickelten Aktivitäten sollten Benutzer in der Lage sein, sie auf eine Designfläche zu ziehen und die Werte zwischen Aktivitäten zu verbinden, ohne Code schreiben zu müssen.
Das Definieren von Abhängigkeitseigenschaften in Ihrer Aktivität ist ein zweistufiger Vorgang. Im ersten Schritt bestimmen und registrieren Sie die Definition der Abhängigkeitseigenschaft, indem Sie eine statische Variable erstellen und den Wert über die Register-Methode der DependencyProperty-Klasse festlegen. Im zweiten Schritt definieren Sie eine .NET-Standardeigenschaft mit get- und set-Methoden, wobei die Basisklasse den Wert der Abhängigkeitseigenschaft speichert und abruft. Es gibt einen Codeabschnitt für Visual Studio® 2005, der diesen Vorgang vereinfacht. Der in Abbildung 3 dargestellte Code zeigt die UserName-Eigenschaft, die als Abhängigkeitseigenschaft neu definiert wurde.
public static DependencyProperty UserNameProperty = 
    System.Workflow.ComponentModel.DependencyProperty.Register(
        "UserName", typeof(string), typeof(CreateUserActivity));

[Description("The new username for this user")]
[Category("User")]
[Browsable(true)]
[DesignerSerializationVisibility(
    DesignerSerializationVisibility.Visible)]
public string UserName
{
    get { return (string)base.GetValue(
              CreateUserActivity.UserNameProperty); }
    set { base.SetValue(CreateUserActivity.UserNameProperty, value); }
}
Beachten Sie auch, dass die .NET-Eigenschaft in diesem Beispiel selbst Markierungen aufweist, die angeben, wie die Eigenschaften im Eigenschaften-Browser angezeigt werden sollten. Dies ist vor allem im Visual Studio-Designer erkennbar, in dem die Kategorie und Beschreibung angezeigt werden, sobald die Aktivität markiert wird. Diese Attribute sind standardmäßige .NET-Designerattribute. In der MSDN®-Bibliothek erhalten Sie viele Dokumente zu diesen Attributen.
Die Aktivitätenbindung ist eine der Funktionen, die über die Abhängigkeitseigenschaften aktiviert wird. Es gibt jedoch noch weitere Funktion, z. B. Eigenschaftenheraufstufung, Änderungsbenachrichtigung und Statusverwaltung. Da die Werte der Eigenschaften in einem zentralen Wörterbuch gespeichert werden, kann der Aktivitätsstatus leichter serialisiert werden. Dieser zentrale Speicherort erleichtert zudem die Überwachung der Änderungen an den Eigenschaften, sodass andere Aktivitäten oder Workflowcode sich für Änderungen registrieren können und ausgeführt werden, sobald ein bestimmter Wert verändert wird.
Häufig tritt die Frage auf, wann ein Entwickler Abhängigkeitseigenschaften anstelle von .NET-Standardeigenschaften verwenden soll. Die einfache Antwort ist, dass Abhängigkeitseigenschaften für alle Eigenschaften verwendet werden sollten, die von einer Bindung an eine andere Eigenschaft oder ein anderes Feld profitieren. In Wahrheit gibt es jedoch kein gutes Argument dafür, Abhängigkeitseigenschaften nicht zu verwenden, und dank des Codeausschnitt-Supports können Sie sie mühelos schreiben.

Erstellen zusammengesetzter Aktivitäten
Grundlegende Aktivitäten sind zwar sehr nützlich, manchmal möchten Sie jedoch komplexere, wieder verwendbare Komponenten bereitstellen. Eine solche Komponente ist die wieder verwendbare Aktivität, die mehrere grundlegende Aktivitäten umfasst und somit eine wieder verwendbare Interaktion oder einen wieder verwendbaren Logikfluss darstellt. Eine Aktivität, die erst die Genehmigung von einem Manager anfordert, bevor ein Benutzer erstellt wird, ist eine zusammengesetzte Aktivität. Diese eine Aktivität würde die Genehmigungsanforderung, den Antwortempfang und das Erstellen des Benutzers umfassen. Das Ziel beim Erstellen dieser zusammengesetzten Aktivität wäre es, dem Benutzer zu ermöglichen, sie einem Workflow hinzuzufügen, ohne dass er sich um die Komplexität des Genehmigungsvorgangs oder die Funktionsweise Gedanken machen muss.
Dieser einfache Typ einer zusammengesetzten Aktivität nutzt die Ausführungssteuerung einer bestehenden Basisklasse, häufig die SequenceActivity-Klasse. Dieses Szenario tritt so häufig auf, dass Visual Studio Extensions for Windows Workflow Foundation mit einem visuellen Designer für diesen Aktivitätstyp ausgeliefert wird. Fügen Sie Ihrem Projekt eine neue Aktivität hinzu, dann erhalten Sie die Grundlage für eine zusammengesetzte Aktivität basierend auf der Sequence-Aktivität. Darüber hinaus können Sie die Schritte in Ihrer wieder verwendbaren Komponente ähnlich wie die Definition eines Workflows definieren. Mithilfe des Eigenschaften-Browsers können Sie die Basisklasse in eine andere zusammengesetzte Aktivität ändern, um die Ausführungssemantik zu ändern und dabei weiterhin den Designer zur Entwicklung der Aktivitätslogik zu nutzen. Abbildung 4 zeigt den Aktivitätsdesigner, mit dem eine neue zusammengesetzte Aktivität basierend auf der Sequence-Aktivität erstellt wird.
Abbildung 4
Wenn Sie Aktivitäten einkapseln, müssen Sie die Eigenschaften der enthaltenen Aktivitäten für die Benutzer Ihrer zusammengesetzten Aktivität freilegen. Im vorherigen Beispiel muss der Benutzer der zusammengesetzten Aktivität in der Lage sein, die Werte für Benutzername, E-Mail-Adresse, Rollen und andere Angaben, die zur ordnungsgemäßen Konfiguration der enthaltenen Aktivitäten benötigt werden, bereitzustellen. Visual Studio Extensions bietet einen Mechanismus zur Eigenschaftenheraufstufung, um diesen Vorgang zu erleichtern. Wenn Sie den Designer für zusammengesetzte Aktivitäten verwenden, klicken Sie mit der rechten Maustaste auf eine Aktivität. Das Kontextmenü enthält eine Option, mit der Sie die Eigenschaften der Aktivität, die gebunden werden können, hochstufen. Wenn Sie diese Option wählen, werden die Abhängigkeitseigenschaften in der zusammengesetzten Aktivität deklariert, und die Eigenschaften der enthaltenen Aktivität werden an diese Werte gebunden. Damit werden die Eigenschaften, die gesetzt werden müssen, freigelegt, ohne dass Sie Code, der diese Werte verbindet, schreiben müssen. Sie können festlegen, wie die freigelegte Eigenschaft für Benutzer Ihrer zusammengesetzten Aktivität genannt wird, und weiterhin die Implementierungsdetails Ihrer Aktivität verbergen.
Wenn Sie mehr Steuerung über die Ausführung der untergeordneten Aktivitäten erhalten möchten, können Sie eine Aktivität schreiben, die auf CompositeActivity beruht und in der Execute-Methode die Ausführungsplanung der untergeordneten Aktivitäten verarbeitet. Betrachten Sie beispielsweise die Switch-Aktivität. Die IfElse-Aktivität ist Bestandteil von .NET Framework 3.0 und bietet das Modell für die bedingte Ausführung eines einzelnen Aktivitätenzweigs. Die Parallel-Aktivität bietet ein Modell zur Ausführung aller Zweige. Nur die ConditionedActivityGroup-Aktivität (CAG) bietet ein Modell zur bedingten Ausführung mehrerer Zweige. Switch ist weniger komplex als CAG. Sie bietet einen guten Mechanismus, mit dem Sie zeigen können, wie die Ausführung von untergeordneten Aktivitäten für eine bedingte Ausführung mehrerer Zweige von Aktivitäten basierend auf Regeln oder Codeentscheidungen gesteuert werden kann. Abbildung 5 zeigt die Nutzung der Switch-Aktivität in einem Workflow. Beachten Sie, dass jeder Aktivitätszweig eine Eigenschaft mit dem Namen „Condition“ hat, die als deklarative Regelbedingung oder als Codebedingung festgesetzt werden kann, wie die Bedingungen für einen Zweig einer IfElse-Aktivität. Nur wenn die Bedingung erfüllt ist und bei der Auswertung den Wert „True“ erhält, wird dieser Aktivitätszweig ausgeführt.
Abbildung 5 Bedingte Ausführung mit der Switch-Aktivität (Klicken Sie zum Vergrößern auf das Bild)
Als zusammengesetzte Aktivität besteht die Switch-Aktivität aus mehreren Sequenzen, die bedingt ausgeführt werden. Daher besteht der erste Schritt darin, eine andere Aktivität zu erstellen, die SwitchBranch-Aktivität, die auf der Sequence-Aktivität beruht und eine ActivityCondition-Eigenschaft mit dem Namen „Condition“ definiert. Mit dieser Eigenschaft können Benutzer den Code oder die deklarative Regelbedingung festlegen, der bzw. die angibt, ob die Sequenz ausgeführt werden soll. Die SwitchBranch-Aktivität nutzt die Basisaktivität und stellt keine eigene Ausführungslogik bereit.
In der Execute-Methode der Switch-Aktivität wird jede der aktivierten untergeordneten Aktivitäten überprüft und die Bedingung wird ausgewertet. Wenn diese Bedingung als „True“ festgelegt und ausgewertet wurde, muss dieser untergeordnete Zweig für die Ausführung geplant werden. Dies wird über den Aufruf der ExecuteActivity-Methode für ActivitiyExecutionContext durchgeführt. Der Unterschied zwischen zusammengesetzten Aktivitäten tritt in am ehesten bei der Verwaltung der untergeordneten Aktivitäten während dieses Vorgangs auf. Unabhängig davon, ob Sie sie in paralleler, sequentieller oder umgekehrter Reihenfolge planen möchten, die Execute-Methode ist der Moment, an dem Sie den Plan identifizieren und bestimmen können, welche untergeordneten Aktivitäten ausgeführt werden sollen.
Die Execute-Methode für die Switch-Aktivität gibt den Status „Executing“ an die Laufzeit zurück. Dies bedeutet, dass die Aktivität die untergeordneten Aktivitäten geplant hat, aber die Aufgaben nicht abgeschlossen sind. Somit wird die Ausführung der nächsten Aktivität durch die Laufzeit verhindert, bis sie darüber benachrichtigt wird, dass die Aktivität abgeschlossen wurde. Wenn alle untergeordneten Aktivitäten abgeschlossen wurden, muss die Switch-Aktivität die Laufzeit darüber informieren können, dass sie abgeschlossen wurden. Bevor Sie also die Ausführung eines untergeordneten Zweigs planen, registriert die Switch-Aktivität sich für eine Änderungsbenachrichtigung in der Aktivität, sodass sie weiß, wann die untergeordnete Aktivität abgeschlossen wurde. Abbildung 6 zeigt den Code, mit dem die Benachrichtigungsregistrierung durchgeführt wurde. Beachten Sie, dass diese Änderungsbenachrichtigung die Überwachung der Änderungen an Abhängigkeitseigenschaften, wie zuvor beschrieben, nutzt. Die Aktivität muss die IActivityEventListener-Schnittstelle implementieren, um über diese Änderungen benachrichtigt zu werden.
foreach(Activity child in EnabledActivities)
{
    SwitchBranchActivity childBranch = child as SwitchBranchActivity;
    if (childBranch != null && 
        childBranch.Condition.Evaluate(childBranch, executionContext))
    {
        childBranch.Closed += OnChildClosed;
        executionContext.ExecuteActivity(childBranch);
    }
}
return ActivityExecutionStatus.Executing;

Mit der OnEvent-Methode der IActivityEventListener-Schnittstelle wird bei Benachrichtigung über den Abschluss eines untergeordneten Zweigs überprüft, ob weitere untergeordnete Elemente ausgeführt werden sollen. Falls keine vorliegen, kann die Aktivität ActivityExecutionContext auffordern, sie zu schließen. Dies entspricht der Rückgabe des Status „Closed“ aus der Execute-Methode, wodurch die Laufzeit darüber informiert wird, dass die Aktivität alle Aufgaben abgeschlossen hat. Dies ist ein anderer Vorgang, an dem häufig Unterschiede auftreten, da jede Aktivität die bestimmten Bedingungen, unter denen sie die Aufgaben abgeschlossen hat, bestimmen muss.
Jede zusammengesetzte Aktivität hat höchstwahrscheinlich eine andere Semantik zur Ausführung der untergeordneten Aktivitäten, um die Anforderungen von Autor und Geschäftsfall zu erfüllen. Das hier gezeigte Beispiel soll einen Einblick in die wichtigsten Bereiche für Aktivitätsentwickler beim Erstellen von zusammengesetzten Aktivitäten bieten. Beachten Sie diese Bereiche beim Erstellen von Aktivitäten und erwägen Sie, ob dieses Beispiel für Ihren speziellen Fall gilt.

Asynchrone und Ereignis-basierte Aktivitäten
Während einige Aktivitäten die Aufgaben auf einfache, synchrone Weise abschließen, gibt es viele Fälle, in denen eine Aktivität bestimmte Aufgaben beginnt und dann auf die Antwort wartet. Dementsprechend müssen Sie eventuell eine Aktivität erstellen, die auf ein externes Ereignis wartet, z. B. die Erstellung einer neuen Datei oder die Auslösung eines Windows Management Instrumentation-Ereignisses (WMI). Aufgrund der Art und Weise, wie Workflows in der Laufzeit verwaltet werden, sollten Sie keine Ereignishandler für externe Ressourcen direkt in Ihren Aktivitäten erstellen. Wenn Sie beispielsweise einen Ereignishandler für Änderungen am Dateisystem in Ihrer Aktivität registriert haben und der Workflow einen seriellen Leerlaufzustand einnehmen muss, führt der Handler diesen aus. Alle ausgelösten Ereignisse werden dann nicht an Ihre Aktivität geleitet.
Windows Workflow Foundation bietet eine Infrastruktur, mit der das derzeit noch andauernde Problem beim Kommunizieren mit einem Workflow reduziert werden kann. Das Kommunikationsmodell beruht auf einem Warteschlangensystem: Aktivitäten, die im Allgemeinen registriert werden, um Nachrichten in einer Warteschlange zu empfangen, und Dienste in der Hostanwendung, um Nachrichten in einer Warteschlange zu senden. Ihre benutzerdefinierten Aktivitäten können dieses Modell sowohl zum Bearbeiten externer Ereignisse als auch zum Benachrichtigen über den Abschlusses der asynchronen Aktivitätsausführung nutzen. Damit wird Ihre Aktivität bis zu einem bestimmten Punkt ausgeführt und wartet dann dort auf eine Eingabe, um die Ausführung fortzusetzen. In Abbildung 7 wird das Kommunikationsmodell zwischen dem Code in der Hostanwendung und dem Code bzw. den Aktivitäten im Workflow dargestellt.
Abbildung 7: Asynchrones Kommunizieren mit Aktivitäten 
Damit die Aktivität Nachrichten abhören kann, die in einer Warteschlange ankommen, müssen Sie sich zunächst vergewissern, dass die Warteschlange vorhanden ist. Wenn sie nicht vorhanden ist, müssen Sie sie erstellen. Dies geschieht in der Regel über die Initialize- oder die Execute-Methode der Aktivität, je nachdem, wann die Warteschlange für das Empfangen von Nachrichten verfügbar sein soll. Der WorkflowQueuingService liefert die Methoden, die zum Erstellen, Auffinden oder Löschen von Workflow-Warteschlangen benötigt werden. Schließlich muss Ihre Aktivität registriert werden, um diese Benachrichtigungen empfangen zu können. Dazu muss sie für das QueueItemAvailable-Ereignis in der Workflow-Warteschlange selbst registriert werden. Nachdem Sie sichergestellt haben, dass die Warteschlange vorhanden ist und Sie die Warteschlange für die Ereignisse registriert haben, wird Ihre Aktivität benachrichtigt, wenn Elemente in der Warteschlange vorhanden sind. Sie können dann das Element aus der Warteschlange entfernen und es verarbeiten.
Zum Erstellen einer asynchronen Aktivität verwenden Sie die soeben beschriebenen Schritte, um die Aktivität für das Empfangen von Nachrichten in der Warteschlange vorzubereiten. Wenn Ihre asynchrone Aktivität abgeschlossen ist, stellen Sie eine Nachricht in die Warteschlange, um Ihre Aktivität zu benachrichtigen und optional die resultierenden Daten an sie zu senden. Da die OnEvent-Methode eine Referenz auf ActivityExecutionContext über den Parameter „Sender“ empfängt, kann die Aktivität durch Aufrufen der CloseActivity-Methode geschlossen werden.
Dies soll am Beispiel einer einfachen ReadLine-Aktivität demonstriert werden. In diesem Beispiel erstellt die ReadLine-Aktivität eine Warteschlange in ihrer Execute-Methode und wird für eine Benachrichtigung bei Eingang von Daten registriert, die bei der Warteschlangenimplementierung der IActivityEventListener-Schnittstelle ankommen. Die Hostanwendung oder ein benutzerdefinierter Laufzeitdienst rufen Benutzereingaben aus der Konsole ab und stellen sie in die Warteschlange für die Aktivität. Ein Beispiel für eine solche ReadLine-Aktivität ist im Code zu diesem Artikel enthalten und nutzt dieses Muster zur Implementierung.
Um eine Aktivität zu erstellen, die als Ereignissenke fungieren kann (wie beispielsweise die HandleExternalEvent-Aktivität), können Sie auch die IEvent­Activity-Schnittstelle implementieren. Diese Schnittstelle definiert die zentralen Aufgaben Ihrer Aktivität beim Abhören von Ereignissen:
public interface IEventActivity
{
	void Subscribe(ActivityExecutionContext parentContext,
		IActivityEventListener<QueueEventArgs> parentEventHandler);
	void Unsubscribe(ActivityExecutionContext parentContext, 
	   IActivityEventListener<QueueEventArgs> parentEventHandler);

	IComparable QueueName { get; }
}
Die QueueName-Eigenschaft muss einen IComparable-Wert ausgeben, der Ihre Aktivität eindeutig identifizieren kann, wenn Nachrichten in die Warteschlagen gestellt werden. Der Name dieser Warteschlange muss von dem Code verwendet werden, der die Nachricht in die Warteschlange der Workflowlaufzeit stellt.
Diese Schnittstelle ermöglicht es, dass die Aktivität angewiesen wird, Ereignisse zu abonnieren, bevor sie ausgeführt wird, und ermöglicht es der Aktivität zu bestimmen, wann sie das Abonnement beenden soll. Bei den Subscribe- und Unsubscribe-Methoden ist es Aufgabe der Aktivität sicherzustellen, dass eine Warteschlange unter Verwendung von QueueName erstellt und nach Beendigung der Verarbeitung wieder gelöscht wird. Darüber hinaus bietet dies die Gelegenheit für Ihre Aktivität, Informationen bei allen lokalen Diensten zu registrieren, die Logik im Namen der Aktivität ausführen und durch Einstellen einer Nachricht in die Warteschlange reagieren.
Ein lokaler Dienst ist eine Klasse, die Sie definieren und vom Host aus zu der Workflowlaufzeit hinzufügen. Der lokale Dienst kann Ereignishandler oder andere Listener verwalten, solange die Hostanwendung ausgeführt wird, und anschließend durch Einstellen der Nachricht in den Workflow sicherstellen, dass die erforderlichen Daten in den Workflow gelangen. Die Daten, die Sie an den lokalen Dienst weitergeben, sollten den Namen der Warteschlange, die Workflowinstanz-ID sowie alle Informationen umfassen, die der Dienst benötigt, um die Arbeit zu starten oder ein Ergebnis an Ihre Aktivität auszugeben.
Der Beispielcode zu diesem Artikel enthält eine benutzerdefinierte Ereignisaktivität, die eine Warteschlange erstellt und einen Handler registriert, um benachrichtigt zu werden, wenn ein Ereignis in die Warteschlange kommt. Das Hostprogramm stellt einfach nach einer kurzen Wartezeit ein Element in die Warteschlange, um zu demonstrieren, wie Elemente in die Warteschlange gestellt werden. In einem realen Szenario wäre wahrscheinlich Ihr lokaler Dienst verantwortlich für das Senden der Daten, aber das Beispiel zeigt, dass auch der Host Daten für eine Aktivität in die Warteschlange stellen kann.
Beim Arbeiten mit Ereignis-basierten Aktivitäten wird im Allgemeinen so vorgegangen, dass nach Elementen in der Warteschlange der Execute-Methode gesucht wird, und dann, wenn keine Daten vorhanden sind, Elemente abonniert werden, die in der Warteschlange verfügbar sind und den Status der Ausführung zurückgeben. Im Handler für die ankommenden Elemente werden dann die Daten aus der Warteschlange ausgelesen und optional alle Ereignisse in Ihrer Aktivität ausgelöst, bevor die Aktivität geschlossen wird.
Durch Implementieren dieser Schnittstellen kann Ihre Aktivität nun in unterschiedlichen Weisen am Workflow teilnehmen. So kann Ihre Aktivität beispielsweise in einem Statusmechanismusworkflow das Ereignis sein, das als erste Aktivität in einer ereignisgetriebenen Sequenz angezeigt wird. Auf diese Weise kann Ihr Ereignis eine Sequenz von Aktivitäten und möglicherweise einen Übergang zu einem neuen Status auslösen. Ein vollständiges Beispiel für diese Art von Aktivität liefert die FileWatcher-Aktivität im Windows SDK.

Umgang mit Fehlern
Eine weitere Aufgabe für Entwickler von Aktivitäten ist der Umgang mit Fehlerbedingungen. Das Fehlermanagement bei Aktivitäten hat viele Ähnlichkeiten mit diesem Vorgang bei jeder anderen Art von Code, aber es sind einige Besonderheiten bei der Ausführung von Aktivitäten zu beachten. Wenn ein Fehler in der Ausführungslogik der Aktivität auftritt, sollte eine Ausnahme ausgelöst werden, die so viele Einzelheiten wie nötig liefert, so wie bei jeder anderen Komponente. Auf diese Weise wird der Laufzeit signalisiert, dass ein Fehler aufgetreten ist. Sie kann dann mit Aktivitäten im Workflow interagieren, damit diese sauber herunterfahren können, oder die Laufzeit kann spezielle Handler für Fehler aufrufen.
Die HandleFault-Methode einer Aktivität wird immer dann aufgerufen, wenn eine Ausnahme vom Ausführungscode der Aktivität ausgelöst wird. In die HandleFault-Methode sollten Sie den Code schreiben, der benötigt wird, um Ressourcen freizugeben oder asynchrone Vorgänge zu beenden, die Ihre Aktivität gestartet haben kann. Beachten Sie, dass die Ausnahme weiterhin in der Laufzeit ausgelöst wird. Diese Methode dient ausschließlich dazu, Ihrer Aktivität eine Bereinigung zu gestatten. Zusammengesetzte Aktivitäten unterstützen auch FaultHandler, spezielle angehängte untergeordnete Elemente, die zur Arbeitserleichterung nach der Verarbeitung ausgeführt werden, sobald die zusammengesetzte Aktivität vom Fehlerstatus in den geschlossenen Status übergegangen ist. Sie können die FaultHandler-Ansicht verwenden, um den Umgang mit Fehlern zu modellieren, die aus untergeordneten Aktivitäten stammen. Wenn Sie auf diese Weise spezielle Ausnahmen für Probleme gestalten, kann dies im Workflow einen besseren Fehlerbehandlungscode ermöglichen.
Die Standardvorgehensweise der HandleFault-Methode wie in der Aktivitätsklasse definiert besteht darin, die Cancel-Methode für die Aktivität aufzurufen. Dadurch wird das Bereinigen von Ressourcen zentralisiert, aber ein solches Vorgehen ist möglicherweise nicht immer angemessen, da je nach Art des ausgelösten Ausnahmetyps die Aktivität eventuell spezielle Ressourcen bereinigen muss. Wenn Sie keine speziellen Anforderungen an die Behandlung von Ressourcen, die Durchführung von anderen Protokollierungen oder Bereinigungen haben, sind die Standardvorgehensweisen in den meisten Fällen geeignet.
Beachten Sie, dass im Allgemeinen ein Abbruch verwendet wird, um eine Semantik zu implementieren, durch die eine zusammengesetzte Aktivität eine Anzahl untergeordneter Aktivitäten erzeugt. Um die gewünschte Semantik zu erfüllen, muss die laufende Ausführung einiger untergeordneter Aktivitäten abgebrochen werden. Der Abbruch ist eine positive Vorgehensweise, die verwendet wird, um die weitere Ausführung zu unterstützen, während Fehler ein Negativum sind, die zur Implementierung von Ausnahmen verwendet werden. Abbruch und Fehlerbehandlung sind zwei völlig verschiedene Dinge, und die Basisklassenimplementierung von HandleFaults ruft die Cancel-Methode nur auf, um sehr grundlegende Szenarios zu aktivieren.

Entwurfserlebnis
Viele Aktivitäten wurden für die Verwendung in einer modellbasierten Benutzeroberfläche entwickelt, beispielsweise der Designer, der in den Visual Studio-Erweiterungen für Windows Workflow Foundation enthalten ist. Das Entwurfserlebnis für Aktivitäten ist in vielerlei Hinsicht wichtiger als die Grundlagen der Ausführung, da dies für andere Entwickler und Consumer Ihrer Aktivität am deutlichsten sichtbar sind. Windows Workflow Foundation ermöglicht die Darstellung von Workflows in vielen verschiedenen Szenarios, nicht nur bei der Entwicklung. Daher ist es nicht nur wichtig, dass Ihre Aktivität die Semantik der damit verbundenen Aufgaben überträgt, sondern auch für Benutzer logisch und nützlich erscheint.
Das Entwurfszeiterlebnis umfasst mehrere Komponenten, zu denen Darstellung, Interaktivität und Validierung gehören. Diese Entwurfskomponenten sind selbst .NET-Klassen und mit der Aktivität über benutzerdefinierte Attribute verbunden, die über benutzerdefinierte Attribute auf die Aktivitätsklasse angewendet werden. Die erste dieser Klassen ist der Aktivitätsdesigner, der den zentralen Entwicklereinstiegspunkt für das Erstellen eines umfassenden Entwurfszeiterlebnisses liefert. Die Designerklasse ermöglicht eine Beteiligung am Entwurfserlebnis durch Interaktion mit dem Eigenschaften-Browser, Kontextmenüs, Mausklicks und Bewegungen sowie die tatsächliche Darstellung der Aktivität auf der Entwurfsoberfläche.
Sie erstellen einen Designer, indem Sie eine Klasse erstellen, die aus der ActivityDesigner-Basisklasse oder einer beliebigen Anzahl von den in den Windows Workflow Foundation-Bibliotheken verfügbaren Designern für zusammengesetzte Aktivitäten abgeleitet ist. In diesem Beispiel wird der SwitchActivityDesigner auf die Switch-Aktivität angewendet:
[Designer(typeof(SwitchActivityDesigner),
    typeof(IDesigner))]
public partial class SwitchActivity :
    System.Workflow.ComponentModel.CompositeActivity,
    IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
...
Im Mittelpunkt sollen eine Reihe wichtiger Funktionen stehen, die am häufigsten bei benutzerdefinierten Designern verwendet werden. Die erste dieser Funktionen ist die Möglichkeit, benutzerdefinierte Kontextmenüelemente für Ihre Aktivität bereitzustellen, die es dem Benutzer ermöglichen, eine Aktion zu starten. Durch Überschreiben der Verbs-Eigenschaft in Ihrem Designer können Sie eine Auflistung von Menüelementen angeben, die zu den Kontextmenüs für Ihre Aktivität hinzugefügt werden sollen. Dies ermöglicht es dem Benutzer, das Kontextmenü durch Klicken mit der rechten Maustaste oder in anderer Weise einzublenden und die Aktion zu starten. Für jedes Verb, das Sie zu der Auflistung hinzufügen, stellen Sie einen Ereignishandler bereit, der aufgerufen wird, wenn ein Benutzer auf das Element im Menü klickt. Zusätzlich fügen Sie einen Member der DesignerVerbGroup-Enumeration ein, der angibt, wie das jeweilige Verb im Kontextmenü gruppiert werden soll. Dies ermöglicht es, verwandte Aktivitäten nach ihrem Zweck zu gruppieren, beispielsweise dem Bearbeiten oder Einstellen von Optionen. Im Beispielcode für die Switch-Aktivität wird ein Verb hinzugefügt, das es dem Benutzer ermöglicht, alle Bedingungen in den untergeordneten Zweigen zurückzusetzen. Das Verb wird mit folgendem Code zum Kontextmenü hinzugefügt:
protected override ActivityDesignerVerbCollection Verbs
{
   get
   {
       ActivityDesignerVerbCollection newVerbs = 
            new ActivityDesignerVerbCollection();
        newVerbs.AddRange(base.Verbs);
       newVerbs.Add(new ActivityDesignerVerb(this, 
            DesignerVerbGroup.Edit, "Clear all conditions", 
           new EventHandler(ClearConditions)));
        return newVerbs;
   }
}
Neben der Verbs-Eigenschaft können Sie auch die DesignerVerbs-Eigenschaft überschreiben. Damit können Sie Verben zum Fehlerkontextmenü hinzufügen, die Probleme mit der aktuellen Konfiguration angeben. Schließlich können Sie auch die SmartTagVerbs-Eigenschaft überschreiben, um Elemente zu dem Smarttag hinzuzufügen, den Sie unter den Namen der meisten zusammengesetzten Aktivitäten finden. Dieses Element wird normalerweise nur verwendet, wenn Sie eine alternative Ansicht Ihrer Entwurfsoberfläche präsentieren müssen, ähnlich den Abbruchs- und Fehlerhandleransichten.
Ein Aktivitätsentwickler muss, und diese Möglichkeit wird zur Entwurfszeit wahrscheinlich am dringendsten benötigt, in der Lage sein, die Darstellung einer Aktivität auf der Entwurfsoberfläche anzupassen. Windows Workflow Foundation liefert mehrere Mechanismen zum Erstellen der gewünschten Darstellung, von sehr einfachen Optionen, bei denen Sie nur wenige Eigenschaften festlegen, bis hin zu äußert robusten Möglichkeiten, mit denen Sie die Aktivität direkt unter Verwendung eines System.Drawing.Graphics-Objekts zeichnen können. Zunächst werden die einfachsten Optionen erläutert, die in vielen Situationen ausreichen.
Ein äußerst wichtiger Punkt, den es bei der Darstellung einer Workflow-Aktivität zu verstehen gilt, ist der, dass die Darstellung Teil dessen ist, was man als ein Designer-Thema oder Design bezeichnet. Ein Design definiert einfach, wie jede Aktivität im Designer aussehen sollte. Wenn Sie die Visual Studio-Erweiterung für Windows Workflow Foundation installiert haben und im Menü „Extras“ den Befehl „Optionen“ wählen, wird eine Kategorie für den Workflowdesigner angezeigt, die zwei installierte Designs zeigt. Klicken Sie auf die Schaltfläche „Neu“. Sie sehen dann die Eigenschaften, die für jede Aktivität verfügbar sind. Sie können ein Design speichern und es im Designer in Visual Studio anwenden, aber Sie können es auch verwenden, wenn Sie die Workflowdesignersteuerung in Ihre eigene Anwendung rehosten. Unter Verwendung von Designs können Sie die Workflowentwurfsoberfläche und jede im Designer gehostete Aktivität vollständig ändern.
Das Standarddesign für den Designer prüft eine Aktivität und gestattet es ihr, Designinformationen zu liefern. Bei Ihrer Aktivitätsentwicklung erledigen Sie das, indem Sie ein benutzerdefiniertes DesignerTheme unter Verwendung eines Attributs mit Ihrem benutzerdefinierten Designer verknüpfen. Im Konstruktor für Ihr Design können Sie anschließend Werte für Eigenschaften wie Back­Color­Start, BackColorEnd, ForeColor und BackgroundStyle festlegen, um die Farbe der Aktivität und ihren Text zu ändern. CreateUserActivity­DesignerTheme liefert ein Beispiel für die Aktualisierung dieser Werte:
public class CreateUserActivityDesignerTheme : ActivityDesignerTheme
{
    public CreateUserActivityDesignerTheme(WorkflowTheme theme)
        : base(theme)
    {
        this.BackColorEnd = Color.BurlyWood;
        this.BackColorStart = Color.Bisque;
        this.BackgroundStyle = LinearGradientMode.ForwardDiagonal;
        this.ForeColor = Color.Black;
 }
}
Neben der Farbe und dem Entwurf können Sie auch festlegen, dass ein Symbol an der Standardposition in der Aktivität gezeichnet wird. Das Symbol wird über das Attribut ToolboxBitmap und unter Angabe einer Bilddatei (normalerweise eine 16x16-Bitmap- oder PNG-Datei), die als eingebettete Ressource in die Assembly eingebaut wird, mit der Aktivität verbunden. Das Bild wird nicht nur im Designer verwendet, sondern auch angezeigt, wenn die Aktivität manuell oder durch ein Installationsprogramm zur Toolbox hinzugefügt wird, was angesichts des Namens des Attributs sinnvoll ist. Abbildung 8 zeigt die CreateUser-Aktivität in einem Workflow mit Design- und Symbolunterstützung.
Abbildung 8 Benutzerdefiniertes Design und Symbol für eine Aktivität (Klicken Sie zum Vergrößern auf das Bild)
Beim Erstellen von Designern für zusammengesetzte Aktivitäten müssen Sie nicht nur Probleme im Zusammenhang mit Design und Symbolen bewältigen, sondern möglicherweise auch Verbindungen zwischen den untergeordneten Aktivitätsdesignern herstellen oder in anderer Weise die Darstellung der Einbindung dieser untergeordneten Elemente ändern. Es gibt jedoch mehrere Basisklassen, die die Funktionalität liefern können, die zur Reduzierung der zu schreibenden Codemenge benötigt werden. Für die Switch-Aktivität wird der Designer beispielsweise vom ParallelActivityDesigner abgeleitet, der eine Zeichnung der einzelnen untergeordneten Aktivitäten als Zweig liefert und ein Designer-Verb zum Hinzufügen eines neuen Zweigs erstellt. Der Switch-Aktivitätsdesigner muss nur eine Methode überschreiben und eine neue SwitchBranchActivity ausgeben. Dieser Designer kann sich als nützlich für zusammengesetzte Aktivitäten erweisen, die mit Zweigen bestehen, und er wird intern von den Aktivitäten IfElse, Parallel und Listen verwendet.
Die Basisklasse für die ParallelActivityDesigner-Klasse ist die StructuredCompositeActivityDesigner-Klasse, die einen Großteil der Renderinglogik für Verbindungen liefert, wenn Ihre zusammengesetzte Aktivität andere Designer enthält. Eine der Klasse StructuredComposite­ActivityDesigner nebengeordnete Klasse ist FreeFormActivityDesigner. Dieser Designer ist die Basis für den StateMachine-Workflowdesigner. Er kann verwendet werden, wenn die untergeordneten Aktivitäten frei in der zusammengesetzten Aktivität platziert werden können und keiner bestimmten Struktur folgen müssen. Verwenden Sie einen dieser zwei Designer als Basis für Ihren eigenen Designer.
Eine letzte Anmerkung: Wenn Sie eine zusammengesetzte Aktivität unter Verwendung des Aktivitätsdesigners erstellen, wird die Aktivität auf der Entwurfsoberfläche zusammen mit allen ihren untergeordneten Aktivitäten angezeigt. Auf diese Weise sieht ein Consumer Ihrer zusammengesetzten Aktivität alle internen Aktivitäten Ihrer Implementierung. Dies können Sie auch verhindern, indem Sie einen Designer für Ihre zusammengesetzte Aktivität erstellen, der von der ActivityDesigner-Basisklasse abgeleitet wird. Dies ermöglicht ein einfaches Rendering einer einzelnen Aktivität. Sie können ein Design und ToolboxBitmap-Attribute anhängen, um das Aussehen weiter anzupassen und eine echte Kapselung liefern.

Validierung
Beim Erstellen einer Aktivität oder einer Komponente entspricht es der bewährten Praxis, die Eingaben des Benutzers zu validieren und sicherzustellen, dass Ihre Komponente ordnungsgemäß konfiguriert ist. Es wäre sogar noch besser, wenn Sie den Benutzer daran hindern könnten, Ihre Komponente falsch zu konfigurieren. In zwei Schlüsselbereichen der Entwicklung haben Sie die Möglichkeit sicherzustellen, dass die Aktivität ordnungsgemäß konfiguriert wird, nämlich im Designer und mit einer benutzerdefinierten Validierung Ihrer Aktivität.
Beim Erstellen eines benutzerdefinierten Designers für Ihre Aktivität steuern Sie die Aktivitäten, die zu Ihrer zusammengesetzten Aktivität hinzugefügt werden können, oder die Aktivitäten, zu denen Ihre Aktivität hinzugefügt werden kann. Beachten Sie, dass dieses Verhalten nur für die Entwurfsumgebung gilt und keine Auswirkungen hat, wenn Ihre Aktivität über Code hinzugefügt wird.
Durch Überschreiben der CanBeParentedTo-Methode der Activity­Designer-Basisklasse können Sie die Typen von Aktivitäten filtern, zu denen Ihre Aktivität hinzugefügt werden kann. Wenn diese Methode False ergibt, wird für den Benutzer ein roter Strich angezeigt (das internationale Symbol für Nein), d. h. Ihre Aktivität kann nicht hinzugefügt werden. So lässt beispielsweise die SwitchBranch-Aktivität nur eine Unterordnung unter eine SwitchActivity zu. Damit wird sichergestellt, dass diese Aktivität nur im richtigen Kontext ausgeführt wird. Durch Überschreiben der CanInsertActivities-Methode der CompositeActivityDesigner-Klasse können Sie steuern, ob eine bestimmte Aktivität oder ein Satz von Aktivitäten zu Ihrer zusammengesetzten Aktivität hinzugefügt werden kann. Diese zwei Methoden ermöglichen es Ihnen, die Aktivitätsstruktur zu steuern, die mit Ihrer Aktivität verbunden ist. Dies wird sehr wichtig, wenn Sie die Ausführungsanforderungen Ihrer Aktivität betrachten, da Sie auf diese Weise die Möglichkeit bekommen sicherzustellen, dass die Ausführung erfolgreich ist.
Eine weitere Möglichkeit zur Validierung Ihrer Aktivität besteht darin, einen benutzerdefinierten Validator zu erstellen. Die Validatorklasse ist verantwortlich dafür, Ihre Aktivität zu prüfen und sicherzustellen, dass sie gemäß Ihren Anforderungen konfiguriert ist. Diese Validierung wird vorgenommen, unabhängig davon, ob Sie einen Designer verwenden, um Ihre Aktivität zu einem Workflow hinzuzufügen. Sie können sich nun sicher bereits denken, wie ein Validator erstellt wird: Sie erstellen eine Klasse, die von ActivityValidator abgeleitet wird, und überschreiben dann die Validate-Methode. Anschließend verwenden Sie das ActivityValidatorAttribute, um Ihren Validator mit Ihrer Aktivität zu verbinden.
Die CreateUser-Aktivität verfügt über eine Eigenschaft, mit der ein Kennwort festgelegt werden kann. Es ist jedoch davon abzuraten, das Kennwort statisch im Workflow zu konfigurieren. Stattdessen stellt die Validatorkomponente sicher, dass die Kennworteigenschaft mit einem anderen Wert verbunden wird, und dieser Wert wird zur Laufzeit festgelegt. Abbildung 9 zeigt, wie die CreateUserValidator-Klasse die Eigenschaft testet, um die Verbindung sicherzustellen.
public override ValidationErrorCollection Validate(
    ValidationManager manager, object obj)
{
    ValidationErrorCollection baseErrors = base.Validate(manager, obj);

    CreateUserActivity user = obj as CreateUserActivity;
    if (user == null) throw new ArgumentException(
        "Activity must be a CreateUser activity");

    // make sure we are in a valid designer experience
    if (user.Parent != null &&
        !user.IsBindingSet(CreateUserActivity.PasswordProperty))
    {
        baseErrors.Add(new ValidationError(
            "Password must be set using activity binding",
            1, false, "Password"));
        baseErrors.Add(new ValidationError("Oops", 2, true));
    }
    return baseErrors;
}

Der Code validiert zuerst, dass die zu validierende Aktivität den richtigen Typ aufweist und dass sie in einem anderen Kontext als ihrer eigenen Kompilierung validiert wird. Wenn Sie die übergeordnete Aktivität nicht auf Null prüfen, können Sie Ihre Aktivität zunächst nicht erstellen, da der Validator beim Kompilieren Ihrer Aktivität ausgeführt wird. Validation­ErrorCollection wird verwendet, um eine Auflistung von Fehlern an den Designer zurückzugeben, damit die passenden Fehlermeldungen zu der Benutzeroberfläche hinzugefügt werden können.

Schlussbemerkung
Wie Sie sehen können, liefert Windows Workflow Foundation eine umfassende Umgebung zum Erstellen wiederverwendbarer, mühelos gestaltbarer Aktivitäten zur Verwendung in Ihren Workflows, ob Blattaktivitäten (wichtig für die Implementierung Domänen-spezifischer Logik) oder zusammengesetzte Aktivitäten (wichtig für das Erstellen von Ablaufsteuerungsmustern, die Interaktionen zwischen Einheiten in der realen Welt widerspiegeln). Windows Workflow Foundation behandelt seine integrierten Aktivitäten nicht anders als die von Ihnen geschriebenen benutzerdefinierten Aktivitäten.
Von der Ausführung der Aktivitäten bis zum Entwurfserlebnis haben Sie Zugriff auf dieselben Ressourcen wie das Microsoft Team, das die Basisaktivitätenbibliothek erstellt hat. Durch das Erstellen robuster Aktivitäten können Sie Ihre Anwendungen und Dienste dem Verarbeitungsmodell von Windows Workflow Foundation zugänglich machen und alle Dienste nutzen, die Windows Workflow Foundation zu bieten hat. Nutzen Sie die Community-Website (wf.netfx3.com), um nach Aktivitäten zu suchen und eigene Aktivitäten vorzulegen, die Sie erstellt haben.

Matt Milner ist ein unabhängiger Software Consultant, der sich auf Microsoft-Technologien wie .NET, Webdienste, Windows Workflow Foundation, Windows Communication Foundation und BizTalk Server spezialisiert hat. Als Schulungsleiter für Pluralsight gibt Matt Milner Kurse über Workflow, BizTalk Server und Windows Communication Foundation. Matt Milner lebt mit seiner Frau Kristen und seinen beiden Söhnen im US-Bundesstaat Minnesota. Sie können mit Matt über seinen Weblog Kontakt aufnehmen.

Page view tracker