Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 12 Min.

Workflow-Engine für .NET Core

Arbeitsabläufe in Softwareanwendungen in eine separate Softwarekomponente auslagern.
© dotnetpro
Eine wiederkehrende Aufgabe in der Softwareentwicklung ist die Abbildung von Geschäftsprozessen, sei es ein Benutzerantrag, eine Freigabe von Dokumenten oder sonst irgendein Ablauf, an dem meist sogar mehrere Benutzer beteiligt sind. Klassisch kann ein solcher Ablauf manuell implementiert werden. Dieses Vorgehen ist jedoch fehleranfällig und erfordert grundlegende Überlegungen zur zugrunde liegenden Architektur, um Erweiterbarkeit oder Anpassungsfähigkeit zu gewährleisten.Im Folgenden lernen Sie einen anderen Weg kennen, ­einen Arbeitsablauf softwareseitig abzubilden.

Was ist eine Workflow-Engine? 

Die Workflow-Engine ist Teil eines Gesamtkomplexes, des sogenannten Workflow-Management-Systems. Dabei handelt es sich um eine Softwarelösung zur Modellierung und Ausführung von Geschäftsprozessen. Die Workflow-Engine entspricht dabei dem ausführenden Teil, nimmt also Defini­tio­nen entgegen, interpretiert diese und führt die entsprechenden Schritte im Prozess aus. Als Beispiel sei die Modellierung eines Urlaubsantragssystems genannt: Zunächst wird der Anwender einen Antrag im System stellen. Daraufhin wird der Workflow gestartet: Der Datensatz wird in einer Datenbank angelegt und eine E-Mail an den freigebenden Mitarbeiter versandt. Dieser kann im System nun die Freigabe durchführen oder ablehnen. Je nachdem, welche Aktion durchgeführt wird, wird ein neuer Status gesetzt und eine Benachrichtigung an den Antragsteller versandt. Bei Freigabe wird zusätzlich noch die entsprechende Anzahl an Tagen vom Urlaubskontingent des Antragstellers abgezogen.

Wozu  benötige ich die Workflow-Engine?

Grundsätzlich ist ein solches System sinnvoll, wenn eine Form von festgelegten Prozessschritten in Software integriert werden soll. Die Workflow-Engine übernimmt hier die Steue­rung der Aufgaben. Statt umständlich und fehleranfällig Statusübergänge selbst zu programmieren, wird die Workflow-Engine mit einer Prozessdefinition und einem Ausführungskontext versorgt. Auch Änderungen können recht einfach durch Anpassung der Definition durchgeführt werden.Nicht zu vernachlässigen ist auch der Vorteil, den die meisten Lösungen bieten: Diese stellen einen Server zur Verfügung, über den dediziert unterschiedliche Arbeitsabläufe für verschiedene Programme ausgeführt werden können. So besteht die Möglichkeit, die Ausführung der Arbeitsabläufe komplett von der Softwarelösung zu entkoppeln.

Exkurs: Deterministische endliche Automaten und Kellerautomaten

Wie viele Konstrukte hat auch die Workflow-Engine ihre Wurzeln in der theoretischen Informatik. Hier unterscheidet man zwischen verschiedenen Rechnermodellen, denen gemeinsam ist, dass sie Aufgaben ausführen können und Teil einer Hierarchie, der sogenannten Chomsky-Hierarchie, sind (siehe [1]). Diese beschreibt eine Struktur formaler Grammatiken, anhand derer formale Sprachen erzeugt werden können. Formale Sprachen werden zur exakten Beschreibung von Zeichenketten verwendet. Unter Verwendung dieser Konstrukte lässt sich entscheiden, ob ein Problem zu einer Problemklasse gehört oder nicht. Formale Grammatiken beschreiben die Regeln, unter denen formale Sprachen erzeugt werden können. Je weiter unten ein Grammatiktyp in der Chomsky-Hierarchie steht, desto stärker sind die Einschränkungen, denen die Grammatiken auf der entsprechenden Ebene unterliegen. Das klingt zunächst einmal sehr abstrakt, lässt sich aber recht einfach auf den Alltag übertragen. Betrachten Sie etwa reguläre Ausdrücke. Mit diesen lässt sich entscheiden, ob eine Zeichenkette ein Teilwort enthält oder nicht. Übersetzen wir den regulären Ausdruck in ein Automatenmodell, einen sogenannten deterministischen endlichen Automaten (DEA), so lässt sich anhand der Darstellung erkennen, dass der Automat nur Eingaben akzeptiert, die zum regulären Ausdruck passen. Der Stern-Operator, auch Kleene-Stern genannt, wird durch null oder mehr Wiederholungen im Automaten gekennzeichnet. In einem solchen Modell, dem Typ 3 in der Chomsky-Hierarchie, ist kein Zählen möglich. Ein diesem Typ zugrunde liegender Rechner könnte zwar Aufgaben ausführen, besitzt aber keine Informationen über das bereits ausgeführte Programm – es existiert kein Speicher, auf dem gearbeitet wird, es handelt sich lediglich um eine Folge von Zuständen, die irgendwann in einem akzeptierenden oder verwerfenden Zustand endet. Übertragen lässt sich dieses Modell auf die in diesem Artikel zu implementierende Workflow-Engine.Ein Beispiel für einen solchen DEA und den zugrunde liegenden regulären Ausdruck ist in Bild 1 zu sehen. Dies lässt sich so interpretieren, dass das Lesen eines Zeichens der Eingabe einem Statusübergang entspricht.
Regulärer Ausdruckaaa* und zugehöriger DEA(Bild 1) © Autor
Weiter unten in der Hierarchie stehen die sogenannten kontextfreien Grammatiken. Sicherlich haben Sie einmal mit einer Stack-Datenstruktur gearbeitet, auch Keller genannt. Diese bilden die kontextfreien Grammatiken ab. Erweitern Sie den DEA um Push-, Pop- und Top-Operationen, so besitzen Sie in einem geringfügigen Maß die Möglichkeit zu zählen. Möchten Sie etwa prüfen, ob eine Eingabe von der Form a^nb^n ist, also etwa aaaabbbb, so können Sie für jedes gelesene a einen Push auf dem Stack durchführen. Für jedes gelesene b wird ein Pop durchgeführt. Ist der Stack am Schluss leer, wurden ebenso viele a wie b gelesen.Die kontextfreien Grammatiken bestehen aus entsprechenden Produktionsregeln. Ein Kellerautomat lässt sich als kontextfreie Grammatik beschreiben. Dasselbe gilt für die andere Richtung. Daher sind diese Modelle gleich mächtig. Eine Nutzung für die Implementierung einer Workflow-En­gine ist auch hier möglich, wird jedoch nur der Vollständigkeit halber aufgenommen. Während des Arbeitsablaufs wird der Stapel aufgebaut. Der Arbeitsablauf ist dann erfolgreich beendet, wenn der Stapel leer ist. Ist die Eingabe vollständig abgearbeitet, der Stapel aber nicht leer, wird die Eingabe verworfen, der Workflow läuft nicht erfolgreich durch.Falls Sie sich übrigens fragen, welches Modell Ihren Computer beschreibt: Es handelt sich um das abstrakte Modell der Turingmaschine. Wenn auch formal recht umständlich zu beschreiben, lässt sich beweisen, dass ein Computer nicht in der Lage ist, komplexere Aufgaben auszuführen, als es das Turingmaschinen-Modell hergibt. Gängige Programmiersprachen wie C# oder Python sind turingvollständig, können also selbst turingvollständige Programme ausführen [2]. Es ist beispielsweise möglich, einen Python-Interpreter in Python zu schreiben. Programmiersprachen wie C++ sind sogar zur Kompilierzeit turingvollständig: Durch Templates ist es möglich, vollständige Programme durch den Compiler erzeugen zu lassen [3].Das Turingmodell hat allerdings Grenzen: Beispielsweise ist es nicht möglich, ein Programm zu erstellen, das eine allgemeine (!) Aussage darüber treffen kann, ob ein Programm terminiert. Dabei handelt es sich um das sogenannte Halteproblem. Natürlich ist das fallweise möglich, doch erarbeitet die theoretische Informatik allgemeingültige Aussagen. Auch solche Fälle sind bei der Implementierung einer Workflow-Engine zu berücksichtigen: Endet der Workflow in einer Endlosschleife, dann kann der Computer ohne entsprechende Validierung hierüber keine Aussage treffen.

Komponenten eines Workflows

Ein Workflow enthält stets Knoten oder auch Aktivitäten. Diese beschreiben einen Zustand. Ein Workflow befindet sich immer in einem Zustand, ob Start-, End- oder ausführender Zustand. Einem Zustand kann eine Aktion zugeordnet werden, die ausgeführt wird, wenn dieser erreicht wird.Von einem Zustand aus kann es eine oder mehrere Transitionen oder Statusübergänge geben. Jeder Statusübergang muss einen gültigen Start- und Endknoten haben. Es sollte keine zirkulären Referenzen geben, ein Workflow darf also nicht ohne entsprechende Konditionierung Übergänge der Form Start -> Knoten -> Start modellieren, da man sonst in ­einer Endlosschleife landet. Ein Statusübergang kann entweder immer ausgeführt werden, also unter der konstanten Kondition wahr stehen, oder eine auszuwertende Übergangsfunktion haben. Oft wird eine Aktion definiert, die beim Übergang von einem Zustand zum nächsten auszuführen ist.Eine Transition kann durch einen Trigger ausgelöst werden. Dabei kann es sich beispielsweise um einen Timer oder eine Benutzeraktion handeln, aber auch um einen automatischen Prozess bei Erreichen eines Knotens, für den die Transition ausgehende Kante ist. Hierdurch wird der Übergang zwischen zwei Zuständen konkret gesteuert.Um den Workflow während seiner Ausführung mit Daten zu versorgen, existiert der Kontext. Dieser wird initial in Form einer Objektinstanz definiert und an den Workflow übergeben. Die Workflow-Engine sorgt dafür, dass alle relevanten Komponenten Zugriff auf den Kontext haben und den Zustand verändern können, etwa um eine Benutzereingabe zu speichern und an anderer Stelle auszuwerten. Zusätzlich muss stets eindeutig klar sein, ob eine Aktion in einem gegebenen Rahmen ausführbar ist oder nicht.An letzter Stelle stehen die sogenannten Runner. Meist ist die Modellierung eines einzelnen Arbeitsablaufs nicht ausreichend, vielmehr werden diese durch mehrere Teilworkflows zusammengesetzt. Runner können nun genutzt werden, um etwa sequenzielle, also nacheinander ausgeführte Workflows auszuführen. Ein anderes Beispiel sind Workflows, die mindestens n-mal ausgeführt werden müssen. Oft genutzt werden auch parallel ausgeführte Workflows.

Bestandteile der Workflow-Engine

Die für diesen Artikel entwickelte Workflow-Engine ist in der Lage, einfache und kombinierte Arbeitsabläufe auszuführen und die errechneten Daten zwischenzuspeichern. Die Im­plementierung erfolgte für .NET Core, eine Portierung nach .NET Standard sollte unproblematisch sein. Natürlich kann dieses System nicht mit kommerziellen Lösungen mithalten, die eigene Beschreibungssprachen, Schnittstellen und sogar asynchrone Ausführbarkeit mit sich bringen. Ziel dieses Artikels ist es, in die Grundlagen der Funktionalität einer solchen Systemkomponente einzuweihen. Nachfolgend werden daher die einzelnen zu implementierenden Komponenten beschrieben (siehe Bild 2).
Klassendiagrammder Workflow-Engine(Bild 2) © Autor

Die Workflow-Klasse

Der Workflow ist das Herzstück der Arbeitsablaufdefinition. Von dieser Basisklasse erbt jeder konkrete Workflow. Hier wird über den aktuellen Zustand Buch geführt: Es werden Informationen über den Startzustand und alle möglichen Übergänge gespeichert. Ein Workflow muss initialisiert werden. Dabei werden die Referenzen auf den Startknoten und den aktuellen Knoten (anfänglich gleich dem Startknoten) festgesetzt. Erst dann ist das Objekt einsatzbereit. Innerhalb der Methode Progress() wird aus der Liste der Übergänge jeweils der erste ausgewählt, der im derzeitigen Zustand ausführbar ist. Das Ausführen eines Statusübergangs gibt den entsprechenden Folgeknoten zurück. Dieser wird genutzt, um den aktuellen Zustand im Workflow zu überschreiben. Handelt es sich um einen Endknoten, wird dessen Aktion ausgeführt und der Workflow beendet. Ansonsten wird mit den Informationen über den neuen Zustand fortgefahren, bis der Workflow beendet ist. Nachfolgend wird die Progress()-Methode des Workflows beschrieben:
public void Progress() 
{ 
  if (!initialized) 
  { 
    throw new Exception("Workflow was not yet 
      initialized."); 
  } 

  if (currentNode == null) 
  { 
    throw new ArgumentNullException("Current node 
      not defined."); 
  } 

  if (currentNode is EndNode) 
  { 
    currentNode.Execute(); 
    return; 
  } 
  
  var firstTransition = transitionPool.FirstOrDefault(
    f => f.NodeFrom.Equals(currentNode) && 
    f.CanTransition.Invoke()); 
  if (firstTransition != null) 
    currentNode = firstTransition.Execute(); 
  } 
  
  if (currentNode != null) 
  { 
    currentNode.Execute(); 
  } 

    Progress(); 
} 

Der Workflow-Kontext

Um die Daten zu einem Arbeitsablauf zu speichern, die für den weiteren Verlauf des Workflows entscheidend sind, wird der Workflow-Kontext genutzt. Dabei handelt es sich um eine­ Basisklasse, die einige generische Methoden enthält, um den Zugriff auf die Daten- und Property-Member der konkreten Implementierung mittels Reflection zu vereinfachen. So lässt sich ohne größeren Boilerplate-Code die Benutzereingabe in einem Zustand im Kontext speichern und anschließend für die Entscheidung, welche Transition ausgeführt werden soll, nutzen. Beispielsweise kann die aktuelle Benutzereingabe wie folgt gespeichert werden:
context.SetValueForProperty("Decision", decision); 
Die Implementierung wird exemplarisch gezeigt, möglich wäre es beispielsweise auch, alle Attributwerte in einem Dictionary zu speichern.
public T GetValueForProperty<T>(string propertyName) 
{ 
  var typeInfo = this.GetType(); 
  var propertyInfo = typeInfo.GetProperty(propertyName); 

  if (propertyInfo != null) 
  { 
    return (T)propertyInfo.GetValue(this); 
  } 

  return default(T); 
} 

public void SetValueForProperty<T>(
    string propertyName, T value) 
{ 
  var typeInfo = this.GetType(); 
  var propertyInfo = typeInfo.GetProperty(propertyName); 

  if (propertyInfo != null) 
  { 
    propertyInfo.SetValue(this, value); 
  } 
} 
Zusätzlich wurde eine Methode Reset() implementiert, um den Kontext auf seinen Anfangszustand zurückzusetzen.

Knoten/Aktivitäten

Ein Knoten oder auch eine Aktivität stellt einen Zustand im Arbeitsablauf dar. Damit dieser terminiert, müssen je ein ausgezeichneter Start- und Endknoten existieren. Die Aktivitäten werden als Klassen, abgeleitet von ActionNode, modelliert. Diese Klassen beinhalten eine von Subklassen zu überschreibende Methode Execute(). Diese Methode beschreibt den zu definierenden Prozessschritt, der bei Erreichen des Zustands ausgeführt werden soll. Jeder Knoten hat Zugriff auf den Kontext des Workflows und kann diesen verändern. Ausgehend von dem hier beschriebenen atomaren Knoten mit einer Aktion wird auch zusätzlich noch die Subklasse MultiStepNode definiert. Diese erlaubt, eine Liste von sequenziell aufeinanderfolgenden Schritten bei Erreichen des Zustands auszuführen.

Übergänge

Übergänge sind das Herzstück in Form einer Verbindung zweier Zustände. Jeder Übergang besitzt einen Start- und ­einen Endknoten. Zusätzlich wird noch eine Func-Property CanTransition angegeben, die nach Auswertung beschreibt, ob ein Übergang durchgeführt werden kann oder nicht. Hierzu ist es oft notwendig, den Kontext des Workflows abzufragen, um auf Basis des aktuellen Zustands Entscheidungen zu treffen. Zusätzlich wird noch angegeben, welche Aktion beim Durchführen eines Übergangs ausgeführt wird. Die Execute()-Methode des Übergangs gibt einen ActionNode zurück: Kann der Übergang ausgeführt werden, so arbeitet die Workflow-Engine mit dem Endknoten des Übergangs weiter, ansonsten wird der Startknoten zurückgegeben. Im nachfolgenden Codeabschnitt wird die Execute()-Methode dargestellt:
public ActionNode Execute() 
{ 
  if (this.CanTransition != null) 
  { 
    bool result = this.CanTransition.Invoke(); 
    if (result) 
    { 
      ActionForward?.Invoke();  
    } 

    return NodeTo; 
  } 

  return NodeFrom; 
} 

Runner

Im Normalfall wird ein Arbeitsablauf nicht aus einigen wenigen Schritten bestehen, sondern es werden mehrere Teilworkflows miteinander verbunden. Um dieses und weitere Konzepte zu implementieren, werden Runner genutzt: Im Beispielprojekt sind sowohl Runner für sequenzielle Workflows als auch für die Wiederholung einzelner Workflows definiert. Letztere können beispielsweise genutzt werden, um mehrfach Versuche zur Dokumentengenehmigung zu unternehmen. Der Runner ist schlussendlich auch dafür verantwortlich, die notwendigen Schritte zum Ablauf eines Workflows durchzuführen. Ein Einzelschritt des Runners wird durch die RunStep()-Methode durchgeführt:
public void RunStep(Workflow workflow) 
{ 
  workflow.Progress(); 
} 
Ausschlaggebend für die Ausführung ist jedoch die abstrakte Methode Run(), die von den konkreten Runnern implementiert wird. Während SequentialRunner alle Workflows, die in der Basisklasse in einer Liste gehalten werden, durchläuft, zählt der RepeatedRunner mit:
public override void Run() 
{ 
  while (executionCount < times) 
  { 
    foreach (Workflow workflow in workflows) 
    { 
      RunStep(workflow); 
    } 

    ++executionCount; 
  } 
} 

Einsatz in der Praxis

Um den Einsatz unserer kleinen Workflow-Engine in der Praxis zu testen, werden wir einen Antragsworkflow abbilden (siehe Bild 3). Ausgehend von einem Startzustand soll der entsprechende Freigeber per E-Mail über ein neues Dokument benachrichtigt werden. Anschließend benutzt dieser das System und kann die Entscheidung bezüglich einer Freigabe fällen oder ablehnen. Wenn diese abgelehnt wurde, wird der Prozess erneut gestartet. Im Fall einer Freigabe wird eine Nachricht ausgegeben und der Workflow beendet.
Ablaufdiagrammzum Antragsworkflow(Bild 3) © Autor
Zunächst werden wir eine Subklasse des Workflows definieren. Dieser enthält einige Transitionen, die das gewünschte Verhalten abbilden. Mithilfe von Lambdas werden wir die Möglichkeit der Statusübergänge abhängig vom aktuellen Kontext abbilden. Der Workflow-Runner sorgt nun dafür, dass die Kontrolle an den Workflow übergeben wird und das Programm wie gewünscht ausgeführt wird. Der Kontext wird dabei wie folgt implementiert: 
public class SampleDocumentApprovalWorkflowContext: WorkflowContext 
{ 
  public enum APPROVAL_STATE 
  { 
    UNAPPROVED, 
    IN_PROGRESS, 
    APPROVED 
  }; 
  
  public APPROVAL_STATE ApprovalState { get; set; } 
  public string Decision { get; set; } 
  
  public override void Reset() 
  { 
    ApprovalState = APPROVAL_STATE.UNAPPROVED; 
    Decision = null; 
  } 
} 
Dies sollte selbsterklärend sein. Interessanter wird es bei der Implementierung der Transitionen. Es existieren zwei benutzerdefinierte Knoten mit eigens implementierten Aktivitäten. Zu Beginn des Workflows wird vom Startknoten zum Freigabeknoten weitergeleitet, der eine Aktion vom Benutzer erwartet: die Eingabe accept oder decline. Der Workflow blockiert so lange, bis eine Eingabe getätigt wurde. Die Eingabe wird im Kontext gespeichert. Nachfolgend wird die Klasse für diesen Knoten dargestellt:
class DoApprovalNode: ActionNode 
{ 
  public DoApprovalNode(WorkflowContext context, string 
    name): base(context, name, TYPE.ACTION_NODE) 
  { 
  } 

  public override void Execute() 
  { 
    Console.WriteLine("Please enter 'approve' or 
      'decline'."); 
    
    string decision = Console.ReadLine().ToLower(); 
    if (decision != "approve" && decision != "decline") 
    { 
      Execute(); 
      return; 
    } 

    context.SetValueForProperty("Decision", decision); 
  } 
} 
Der Übergang von diesem Knoten zu einem Post-Freigabe-Knoten erfolgt, wenn die Eingabe accept lautet. Wird die Freigabe abgelehnt, wird in den Anfangszustand gesprungen und der Freigabeprozess wiederholt. Im Post-Freigabe-Knoten, der als MultiStepNode implementiert ist, werden anschließend noch mehrere Konsolenausgaben exemplarisch ausgeführt. Anschließend wird ohne Kondition in den Endknoten gesprungen und der Workflow beendet. Um einen Überblick zu geben, wie ein Übergang innerhalb des Workflows implementiert werden kann, wird nachfolgend der Statuswechsel von der Freigabe zur Post-Freigabe dargestellt:
AddTransition(approvalNode, postApprovalNode, 
  () => 
  { 
    string decision = context.GetValueForProperty
      <string>("Decision"); 
    var state = context.GetValueForProperty
      <APPROVAL_STATE>("ApprovalState"); 

    return decision == "approve" && state == 
      APPROVAL_STATE.IN_PROGRESS; 
  }, 
  () => 
  { 
    Console.WriteLine("Finishing approval workflow."); 
  } 
); 
Nachdem alle notwendigen Abhängigkeiten deklariert wurden, ist ein Start des Workflows über den Einstiegspunkt WorkflowEngine.Execute() möglich. Dieser startet einen jeweils übergebenen Runner und übergibt diesem die Kontrolle. Die Ausgabe ist in Bild 4 zu sehen.
Ausgabebei Ausführung des Workflows(Bild 4) © Autor
SampleDocumentApprovalWorkflow wf1 = new 
  SampleDocumentApprovalWorkflow(); 
SequentialRunner sequentialRunner = new 
  SequentialRunner(); 
equentialRunner.AddWorkflow(wf1); 

Workflow.WorkflowEngine.Execute(sequentialRunner); 

Zusammenfassung und Ausblick

Der Bereich der Workflow-Engines ist bereits sehr gut erforscht und es existieren mächtige Softwarelösungen (siehe [4]). Die hier erarbeitete prototypische Lösung kann dennoch um einige Punkte erweitert werden, damit ein Praxiseinsatz relevant erscheint. Hier sind einige solcher Möglichkeiten:Um einen Workflow zu einem späteren Zeitpunkt fortzusetzen, ist eine Option zur Persistenz des Zustands nötig. Neben der Deserialisierung der Eigenschaftswerte des Workflow-Kontexts muss auch eine Möglichkeit bestehen, die zuletzt ausgeführte Aktivität wiederherzustellen. Durch Aufruf der Execute()-Methode der Workflow-Engine kann der Arbeitsablauf zu einem späteren Zeitpunkt fortgesetzt werden.Die Workflow-Engine implementiert hier eine Endlosschleife, die durch das Erreichen entweder eines finalen oder eines unerreichbaren Zustands terminiert wird. Dabei wird bei Erreichen eines Zustands nur durch das Erwarten einer Benutzereingabe der Übergang in den nächsten Zustand blockiert. Sinnvoll ist es, eine Aktivität selbst als Statusmaschine zu betrachten, die sich in einem „Wartend“-Status befinden kann. Durch einen externen Trigger kann die Workflow-Engine dann den Statusübergang anstoßen. Um dies umzusetzen, wird eine Schnittstelle benötigt, die Kommandos entgegennehmen und an die parallel wartende Workflow-Engine­ delegieren kann. Ausführliche Beschreibungen möglicher Architekturen sind beispielsweise unter [5] zu finden.

Abschluss

Schon das kleine Beispielprojekt zeigt, dass die Implementierung einer Workflow-Engine schnell sehr komplex werden, andererseits aber auch sehr viel Ärger ersparen kann. In meinen Projekten musste ich viele Arbeitsabläufe und einzelne Prozessschritte umsetzen. Dabei gab es nicht selten grundlegende Änderungen. Oft hätte ich mir gewünscht, eine Workflow-Engine als Hilfsmittel zur Verfügung zu haben. Gerade visuelle Tools helfen in der Zusammenarbeit mit Kunden, Arbeitsabläufe zu veranschaulichen und schnell Anpassungen vorzunehmen. Eine solche Software ist wiederverwendbar und erlaubt die Modellierung von Regeln. Dadurch ergibt sich auch für Nichtprogrammierer die Möglichkeit, Geschäftslogik umzusetzen. Zu guter Letzt ist die Implementierung von Workflow-Engines aus theoretischer Sicht ein sehr interessantes Thema, bei dem aus einer zunächst kleinen Idee schnell ein riesiges Projekt erwachsen kann, das viele neue Erkenntnisse mit sich bringt.
Projektdateien herunterladen

Fussnoten

  1. Chomsky-Hierarchie bei Wikipedia, http://www.dotnetpro.de/SL2012Workflow1
  2. Turing-Vollständigkeit bei Wikipedia, http://www.dotnetpro.de/SL2012Workflow2
  3. Template meta-programming with lambda calculus, http://www.dotnetpro.de/SL2012Workflow3
  4. Workflow Engine, https://workflowengine.io
  5. Bernd Rücker, Architecture options to run a workflow engine, http://www.dotnetpro.de/SL2012Workflow4

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige