Mit dem .NET Framework 4.0 wird die neue Version der Windows Workflow Foundation verfügbar. Wie bereits frühzeitig bekannt geworden ist, wurden viele Grundlegende Bestandteile der Workflow Foundation neu entwickelt, um die an eine Workflow Engine gestellten Anforderungen zu erfüllen.
Der neue Designer
Die wohl sichtbarste Änderung in WF4 ist der neue, auf WPF basierende, Workflow Designer. Schaut man sich Abbildung 1 an, so sieht man die verschiedenen Bereiche des Workflow Designers.
(1) zeigt das DesginSurface des Designers, hier werden die Activities entsprechend den Bedürfnissen angeordnet. Eine bequeme Navigation innerhalb des Worflows ermöglicht die integrierte Breadcrump-Navigation (2), mit Ihrer Hilfe kann man durch die jeweiligen Verschachtelungstiefen des Workflows browsen. Workflow Variablen (3) können genau wie Variablen in Methoden verwendet werden um einen Status während dessen Ausführung zu persistieren oder zu manipulieren. Workflow Argumente (4) hingegen, sind für die Kommunikation des Workflows mit der Host-Anwendung gedacht. Welche Teilbereiche des .NET Frameworks verfügbar sind, kann man über die Namespaces (5) steuern. Unter (6) findet man alle Werkzeuge die man fürs Zooming des Workflows im Designer benötigt. Schlussendlich bietet der Designer unter (7) die Möglichkeit alle Activities auf- bzw. zuzuklappen.
Workflow – Eine neue Definition
In WF4 gibt es keine unterschiedlichen Workflowtypen mehr. Wenn man einen neuen Workflow zu einem Workflow-Projekt hinzufügen möchte, lässt es sich bereits erahnen…
Jeder Workflow in WF4 ist eine Activity! Unabhängig vom Ziel oder vom Kontext des Workflows ist jeder Workflow und jede Activity in der WF4 von der Klasse Activity abgeleitet.
WF4 API und Abwärtskomptabilität
Um Workflows und Anwendungen die auf dem .NET Framework 3.5 oder früher basieren nicht zu beschädigen, befinden sich alle WF4-spezifischen Klassen und Objekte in der Assembly System.Activities.dll und deren Namensräumen.
Einen einfachen Workflow schreiben
Einen kleinen und einfachen Workflow schreiben? Schnell gemacht auch ohne Designer, dank der neuen API. Ausgehend von einem neuen Workflow-Konsole-Programm werden nur wenige Zeilen Code benötigt um einen funktionierenden Workflow zu schreiben, wie Listing 1 zeigt.
1: static void Main(string[] args)
2: {
3: // a simple sample code-only-workflow
4: // remember, everything is an activity.
5: var firstCodedWorkflow = new Sequence
6: {
7: Activities = {
8: new WriteLine { Text = "Hello! This is WF4!"}
9: }
10: };
11: // start the workflow
12: WorkflowInvoker.Invoke(firstCodedWorkflow);
13:
14: // wait for user interaction
15: Console.ReadKey(false);
16: }
In Zeile 5 wird eine neue Instanz der Sequence Activity erstellt, sie stellt späteren Verlauf den Gesamtworkflow dar. Zeile zwölf wird der Workflow durch Verwendung des WorkflowInvoker’s gestartet.
Nach der Ausführung der Workflow Konsole Anwendung, wird die durch die WriteLine-Activity hinterlegte Meldung ausgegeben.
Der WorkflowInvoker
Der WorkflowInvoker ermöglicht es einfach und schnell Workflows auszuführen. Hierbei wird die Ausführung nur synchron vorgenommen. Eine Verteilung der Workflow-Ausführung auf mehrere Threads ist mit dem WorkflowInvoker nicht möglich.
Der WorkflowInvoker bietet sich sehr gut für Testingszenarien an. Listing 2 zeigt einen einfachen UnitTest für einen einfachen Workflow.
1: [TestMethod]
2: public void Test_SecondSampleWorkflow_ForCorrectResult()
3: {
4: // arrange
5: int expected = 6;
6:
7: // act
8: IDictionary<String, object> workflowResult =
9: WorkflowInvoker.Invoke(new SecondSampleWorkflow());
10:
11: // assert
12: Assert.AreEqual<int>(expected,
13: Convert.ToInt32(workflowResult["CalcResult"]));
14:
15: }
Schnell, einfach, automatisiert ausführbar, alles was man benötigt um gute UnitTests zu schreiben!
Neben der hier verwendeten Invoke Methode gibt es auch noch eine generische Variante dieser Methode. In einem der nächsten Posts zur WF4 werde ich die generische Überladung noch vorstellen und zeigen wann man diese verwendet.
PS: Näheres zum AAA-Pattern findet ihr in Gregors Post oder in diesem Buch.
WorkflowApplication – Wenn es mehr sein muss
Sobald die Workflows mehr als nur Methodenersatz werden, wird ganz klar empfohlen die Workflows durch die Verwendung der Klasse WorkflowApplication auszuführen.
Die WorkflowApplication wird auch benötigt, wenn Aktionen im Workflow asynchron ausgeführt werden sollen.
Damit die HostAnwendung über die Fertigstellung des Workflows informiert werden kann, muss das Event WorkflowCompleted implementiert werden. Listing 3 zeigt das Hosting des gleichen Workflows wie in Listing 1 nur mit Hilfe der WorkflowApplication Klasse
1: AutoResetEvent sync = new AutoResetEvent(false);
2: var firstCodedWorkflow = new Sequence
3: {
4: Activities = {
5: new WriteLine { Text = "Hello! This is WF4!"}
6: }
7: };
8:
9: WorkflowApplication wf4Application =
10: new WorkflowApplication(firstCodedWorkflow);
11:
12: wf4Application.Completed = (e) =>
13: {
14: try
15: {
16: Console.WriteLine(String.Format(
17: "Workflow finished with state '{0}'",
18: e.CompletionState));
19: Console.WriteLine("Press ENTER....");
20: Console.ReadLine();
21: }
22: catch (Exception ex)
23: {
24: /* some exception handling... */
25: }
26: finally
27: {
28: sync.Set();
29: }
30: };
31: wf4Application.Run();
32: sync.WaitOne();
Durch AutoResetEvent werden in diesem Beispiel die Threads koordiniert, so dass die Hostanwendung die Ausführung nicht terminiert, obwohl der Workflow noch nicht fertig abgearbeitet wurde.
Natürlich bringt die WorkflowApplication noch unzähliges mehr an Funktionalität mit sich (Persistence, Bookmark-Support,…) all diese Punkte werden noch in weiteren Posts erläutert.
Workflow Argumente
Wie bereits erwähnt werden Workflow Argumente verwendet, um die Kommunikation zwischen Workflow und Hostanwendung zu realisieren. In einem Workflow lassen sich Argumente sehr einfach anlegen
Wie man Abbildung 3 entnehmen kann, wird für jedes Argument noch definiert ob es sich um ein
- Eingabe-Argument
- Ausgabe-Argument
- Eingabe-und-Ausgabe-Argument
handelt. Natürlich muss auch noch ein Typ für das jeweilige Argument angegeben werden. Optional kann man noch einen Standardwert für jedes Argument hinterlegen um einer möglichen NullReferenceException vorzubeugen :)
Eingabe-Argumente angeben
Die für den Workflow definierten Eingabe-Argumente werden bei der Initialisierung des Workflows angegeben. Hierbei hat der Entwickler Compile-Time-Check und IntelliSense.
Ausgabe-Argumente abfragen
Die Ausgabe-Argumente eines Workflows werden automatisch als Instanz von IDictionary<String,object> zurückgegeben. Das gewünschte Argument ist über dessen Name im Dictionary abgelegt und muss zur volltypisierten Verwendung noch in den gewünschten Typ umgewandelt werden.
Die Basis Activity Library (BAL) der WF4
Die WF4 bietet dem Entwickler ein reichhaltiges Set an Activities, die er in seinen Workflows verwenden kann.
- Assign
- Delay
- WriteLine
- TryCatch
- Throw
- If
- While
- Parallel
- Switch
- ForEach
- Send
- Receiver
- …
Neben diesen, verfügt die WF4-BAL noch über einiges mehr an Activities. Hier findet Ihr einen guten Überblick der vorhandenen Activities.
Besondere Beachtung sollte man den FlowChart-Activities gönnen, FlowChart Activities erlauben es im Workflow rückwärts zu gehen und beliebige Activities erneut auszuführen. Näheres zu FlowChart-Activities in einem der folgenden Artikel.
Fazit
Mit WF4 hat es Microsoft geschafft, ein rundes Framework auf die Beine zu stellen. Durch die Verwendung der WF4 kann man sehr schnell komplexe Anforderungen umsetzen und behält stets den Überblick. Vergessen sind die Probleme der WF aus dem .NET FX 3…
In weiteren Posts zur WF4 werden noch einige interessante Teilbereiche der WF4 erleuchtet.