25. NATIVEACTIVITY public class ReadString2 : NativeActivity { public OutArgument<string> Name { get; set; } protected override bool CanInduceIdle { get { return true; } } protected override void Execute(ActivityExecutionContext context) { context.CreateNamedBookmark("input", new BookmarkCallback(this.OnBookmarkCallback)); } void OnBookmarkCallback(ActivityExecutionContext context, Bookmark bookmark, object obj) { this.Name.Set(context, (string)obj); } }
26. NATIVEACTIVITY ... workflowApp.Run(); //Get a string from the console and resume the bookmark called “input” string text = Console.ReadLine(); workflowApp.ResumeBookmark("input", text); syncEvent.WaitOne(); ...
In aceasta sesiune vom discuta in jurul ideii de Workflow, vom vedea cum functioneaza WF si cum putem sa integram workflow-uri in aplicatiile noastre.
Focusul va fi pe: Crearea unui workflow Executarea lui din aplicatii Expunerea unui workflow ca un serviciu, prin Workflow Services Prezentarea unor servicii de care in mod sigur avem nevoie cand dezvoltam aplicatii complexe, precum persistenta si tracking. Inainte de toate, vreau sa intreb cati dintre voi au folosit sau folosesc WF 3.5 in aplicatii? … Cati s-au jucat deja cu WF 4 beta 2? … OK. La origini, termenul de ‘Workflow processing’ provine de la ‘document processing’, de la scenarii in care documentele trebuie sa treaca prin diferite departamente, pentru aprobare sau review. Dar notiunea de a executa un set specific de taskuri, impreuna cu luarea unor decizii (precum aprobat sau neaprobat), este ceva ce putem generaliza. De fapt, daca ati scris vreodata software care procesa informatii, lua decizii bazate pe input-uri si lua in considerare si reguli, atunci pot sustine ca ati scris un workflow! ---- The origins of Workflow processing come from document processing, where documents need to go from place to place for approval or review. But the notion of executing a specific set of tasks coupled with decision making (such as approved or not approved), is something we can generalize. In fact, if you’ve ever written a piece of software that processed information, made decisions based on system inputs, and took into account the rules and practices of the system in which de software executed, I’d argue that you’ve written workflow software.
Exista un whitepaper scris de David Chappell despre WF 4.0. Este o introducere in WF 4.0 in care mie mi-a placut cum sunt explicate conceptele, si am sa pornesc si eu cu aceeasi abordare. David Chappel incepea cu o intrebare: Ce face ca o aplicatie server sa fie reusita? Oricine scrie cod vrea sa scrie soft de calitate. Daca acel soft este o aplicatie server, pentru a fi de calitate trebuie sa fie scalabil, sa lucreze cu volume mari de date sau requesturi, fara a consuma prea multe resurse. De asemenea, o aplicatie buna ar trebui sa fie cat mai usor de inteles, atat de cei care o creeaza, cat si de cei care o intretin. Nu este usor sa realizezi ambele lucruri. Abordari care fac aplicatia scalabila tind sa o separe pe componente care devin greu de inteles. Pe de alta parte, avand toata logica intr-un singur loc, eventual intr-un singur executabil, fac scalabilitatea aproape imposibila. Ar fi nevoie de un mod in care sa pastram logica aplicatiei unita, facand-o mai usor de inteles, dar in acelasi timp lasand aplicatia sa scaleze. Vom vedea ca acesta este si principalul obiectiv al Windows Workflow Foundation. Si demonstram asta facand o mica comparatie cu o abordare clasica. --- Everybody who writes code wants to build great software. If that software is a server application, part of being great is scaling well, handling large loads without consuming too many resources. A great application should also be as easy as possible to understand, both for its creators and for the people who maintain it. Achieving both of these goals isn’t easy. Approaches that help applications scale tend to break them apart, dividing their logic into separate chunks that can be hard to understand. Yet writing unified logic that lives in a single executable can make scaling the application all but impossible. What’s needed is a way to keep the application’s logic unified, making it more understandable, while still letting the application scale. Achieving this is a primary goal of Windows Workflow Foundation (WF). By supporting logic created using workflows, WF provides a foundation for creating unified and scalable applications. Along with this, WF can also simplify other development challenges, such as coordinating parallel work, tracking a program’s execution, and more.
WF este un set de tipuri care vin impreuna cu .Net Framework. Sunt 3 aspecte importante ale WF-ului: Activitatile : - sunt un fel de unit of work - cu activitati imi pot construi WF-ul, care nu este altceva decat o colectie de activitati Dar un graf de obiecte nu este destul. Vreau sa fac ceva cu el, si pentru asta avem nevoie de un Runtime . Sarcina runtime-ului este de a executa WF-ul, de a face schedule la activitati, precum si de a oferi unele servicii. Aici runetime-ul devine interesant, pentru ca avem posibilitatea de a opta pentru tracking, sau pentru persistenta. O modalitate de a crea un WF este printr-un tool grafic, cum este designer-ul. Partea frumoasa este ca acest Tooling este inclus in Framework. Deci, putem lua designer-ul si integra in aplicatiile noastre. Si atunci, cum construiesc un Workflow? Trebuie intai sa construiesc niste activitati Luate impreuna, aceste activitati vor forma WF-ul Si in final nu am decat sa las runtime-ul sa se ocupe de rularea activitatilor
Windows Workflow Foundation 4.0 (WF4) is a complete rewrite of the workflow infrastructure introduced with .NET 3.0 in 2006. This rewrite changes the way that many features are used and exposed – from data flow to deployment, from execution to persistence.
WF 4.0 rescrie complet workflow-ul care a fost introdus odata cu .Net 3.0, in 2006. Datorita acestei rescrieri, se schimba modul in care multe functionalitati sunt expuse si folosite, de la flow-ul de date la deployment, de la executie la persistenta. --- Windows Workflow Foundation 4.0 (WF4) is a complete rewrite of the workflow infrastructure introduced with .NET 3.0 in 2006. This rewrite changes the way that many features are used and exposed – from data flow to deployment, from execution to persistence.
Inainte sa ne jucam cu un demo, haideti sa intai sa vedem ce tipuri de workflow-uri exista, ce activitati avem la dispozitie si cum se poate realiza flow-ul de date intre ele. In WF 4.0, exista doua tipuri de workflow-uri: sequential si flowchart. Daca sequential exista si in versiunile anterioare, flowchart este ceva nou introdus. In schimb, o mare diferenta in WF 4 este ca a disparut State Machine. Dar hai sa vedem pe scurt cele 2 tipuri de WF.
Activities are the units of work that are composed to produce workflow based functionality. The Standard Activity Library (those activities that are in the toolbox by default) is quite different from version 3.5. Often used activities, such as the CodeActivity are gone whereas a number of low level activities are introduced. These low level activities include Assign: that allows you to map data between arguments and variables or variable to variable using potentially complex expressions AddToCollection, RemoveFromCollection, ClearCollection: these and others are for manipulating collections of items (including iteration through the collection) InvokeMethod: allows the execution of an arbitrary instance or static CLR method
Flow-ul de date este asigurat prin 3 lucruri: variabile, argumente si expresii. Daca e sa ne gandim la un workflow ca la o clasa, putem spune ca variabilele sunt campurile iar argumentele sunt parametrii metodelor. Argumentele reprezinta modul prin care aducem datele in si din activitati. Exista 3 clase care pot fi folosite pentru declararea argumentelor:… Datele sunt apoi mapate de la o activitate la alta prin salvarea lor in variabile ale activitatilor parinte. Iar expresiile pot primi unul sau mai multe argumente ca input, executa niste operatii pe aceste argumente si returneaza o valuare. Si ele pot fi mapate pe variabile. --- In WF4, activities explicitly declare their inputs and outputs via arguments . There are three classes for declaring arguments: InArgument<T>, OutArgument<T> and InOutArgument<T>. Data is then mapped between activity arguments by storing it on variables on parent activities. Expressions = Takes one or more input arguments, performs some operation on those input arguments, and then returns a value. Can be bound to variables.
Windows Workflow Foundation (WF) provides several methods of hosting workflows. WorkflowInvoker provides a simple way for invoking a workflow as if it were a method call and can be used only for workflows that do not use persistence. WorkflowApplication provides a richer model for executing workflows that includes notification of lifecycle events, execution control, bookmark resumption, and persistence. WorkflowServiceHost provides support for messaging activities and is primarily used with workflow services.
WorkflowInvoker provides a model for executing a workflow as if it were a method call. To invoke a workflow using WorkflowInvoker , call the Invoke method and pass in the workflow definition of the workflow to invoke. Great way to unit test our workflows. When a workflow is invoked using WorkflowInvoker , the workflow executes on the calling thread and the Invoke method blocks until the workflow is complete, including any idle time. To configure a time-out interval in which the workflow must complete, use one of the Invoke overloads that takes a TimeSpan parameter. In this example, a workflow is invoked twice with two different time-out intervals. The first workflow complets, but the second does not. WorkflowInvoker also provides asynchronous versions of the invoke method. For more information, see InvokeAsync and BeginInvoke .
WorkflowApplication in schimb este mult mai puternic. E de fapt un wrapper thread safe in jurul instantei de workflow, care incapsuleaza si runtime-ul. De asemenea, ne ofera si control din host asupra wokflow-ului, avand metode pentru crearea si incarcarea instantelor, pause, resume, terminate sau notificari la evenimente din ciclul de viata al unui workflow. -- WorkflowApplication provides a rich set of features for workflow instance management. WorkflowApplication acts as a thread safe proxy to the actual WorkflowInstance , which encapsulates the runtime, and provides methods for creating and loading workflow instances, pausing and resuming, terminating, and notification of lifecycle events. To run a workflow using WorkflowApplication you create the WorkflowApplication , subscribe to any desired lifecycle events, start the workflow, and then wait for it to finish. In this example, a workflow definition that consists of a WriteLine activity is created and a WorkflowApplication is created using the specified workflow definition. Completed is handled so the host is notified when the workflow completes, the workflow is started with a call to Run , and then the host waits for the workflow to complete. When the workflow completes, the AutoResetEvent is set and the host application can resume execution, as shown in the following example. WorkflowApplication Lifecycle Events In addition to Completed , host authors can be notified when a workflow is unloaded ( Unloaded ), aborted ( Aborted ), becomes idle ( Idle and PersistableIdle ), or an unhandled exception occurs ( OnUnhandledException ). Workflow application developers can handle these notifications and take appropriate action, as shown in the following example.
There are two ways to build custom activities in code: a streamlined simplified model and mode that gives you full access to the underlying workflow infrastructure. Which you use depends on your requirements. Base class depends on needs CodeActivity for simple work AsyncCodeActivity for asynchronous IO NativeActivity for full control The base class CodeActivity (not to be confused with the CodeActivity from WF 3.5) is for creating simple synchronous custom activities, i.e. those that start running and execute to completion without entering a wait state. Consider this example Conclusion The approach that WF4 takes to creating custom activities is a far simpler one to that in WF 3.5. The composite approach caters for many scenarios while for most building block activities using the CodeActivity as base class provides a simple solution. However, if you do need the full power of the workflow infrastructure it is available via the NativeActivity.
Deriving from CodeActivity The base class CodeActivity (not to be confused with the CodeActivity from WF 3.5) is for creating simple synchronous custom activities, i.e. those that start running and execute to completion without entering a wait state. Consider this example… The custom activity derives from the CodeActivity base class. It then declares its inputs and outputs as arguments (in this case there are only one out argument). Finally it overrides Execute to do its work. Notice that the argument value is set by referencing through the context (in this case a CodeActivtityContext). This acts as a look up to the state of this currently executing workflow. This kind of custom activity has two main use cases: simple synchronous activities and as a migration path for people to move code that was previously encoded in the WF 3.5 CodeActivity (I suspect the naming of the base class to the same name as the 3.5 activity was not a coincidence).
Cateodata modelul simplificat expus de CodeActivity nu este de ajuns. In aceste cazuri exista o alta clasa de baza de la care putem deriva, si se numeste NativeActivity. Ea expune toata functionalitatea din WF runtime. In particular, ofera acces si la bookmark-uri pentru a crea activitati asincrone. Acest lucru este foarte important pentru a oferi scenarii de long running workflow. Activitatile care intra intr-o stare de asteptare vor permite workflow-ului sa fie descarcat de catre aplicatia gazda (host). Deriving from NativeActivity Sometimes the simplified model exposed by CodeActivity is not enough. For this reason there is another base class you can derive from called NativeActivity. NativeActivity exposes all of the functionality of the WF4 runtime infrastructure. In particular it provides access to the bookmark infrastructure for creating asynchronous activities. This is hugely important for creating activities that fit with workflow’s long running model. Activities that can go into a wait state allow the workflow to be unloaded by the host. Consider the example of an activity that is waiting for a file to arrive in a specific directory. public class FileDropActivity : NativeActivity { public InArgument<string> WatchDirectory { get; set; } public InArgument<string> FileMask { get; set; } public OutArgument<string> FileName { get; set; } string bookmarkName = Guid.NewGuid().ToString(); protected override void Execute(ActivityExecutionContext context) { context.CreateNamedBookmark(bookmarkName, OnFileCreated); FileDropExtension fde = context.GetExtension<FileDropExtension>(); fde.WaitForFile(bookmarkName, WatchDirectory.Get(context), FileMask.Get(context)); } void OnFileCreated(ActivityExecutionContext context, Bookmark bookmark, object value) { FileName.Set(context, (string)value); } } Here the activity is passed the directory and file mask to wait for as in arguments and sets the arrived file name as its output. The activity now overrides Execute. Notice that the return type of Execute is void – this contrasts with WF 3.5 where the activity had to pass back its execution status from Execute. In 4.0, WF knows whether you are waiting for something to happen based on whether you create a bookmark or not. In this case we see the creation of a bookmark stating that the OnFileCreated method should be called when the bookmark is resumed. The activity then hands off to a custom extension (extensions were known as workflow services in 3.5) calling its WaitForFile method. Internally this method sets up a FileSystemWatcher and an event handler for when the file arrives. When the file is created in the directory it resumes the bookmark. Here’s the code for the extension class FileDropExtension { WorkflowInstance instance; FileSystemWatcher fsw; string bookmarkName; public FileDropExtension(WorkflowInstance instance) { this.instance = instance; } public void WaitForFile(string bookmarkName, string dir, string filter) { this.bookmarkName = bookmarkName; fsw = new FileSystemWatcher(dir, filter); fsw.Created += new FileSystemEventHandler(FileCreated); fsw.EnableRaisingEvents = true; } void FileCreated(object sender, FileSystemEventArgs e) { instance.ResumeBookmark(bookmarkName, e.FullPath); fsw.Dispose(); } } As you can see, the bookmark is resumed via the WorkflowInstance under which the activity is executing. When the bookmark is resumed, the activity’s OnFileCreated method is fired and it sets its output argument to the created file name (passed to the OnFileCreated method in its value parameter). If you contrast this to the incredibly complex job of creating robust asynchronous activities in WF 3.5 you will see that the WF4 model is relatively simple.
Persistenta poate fi initiata in 3 moduri: workflow-ul insusi spune ca trebuie sa persiste, asta se poate realiza prin utilizarea unei PersistActivity. De obicei exista moduri mai bune in care se poate asigura persistenta. Este ceva de genul GCCollect: nu este un best practice sa o folosesti, dar metoda exista in caz ca ai nevoie Policy based persistence – daca WF este idle de ceva timp Controlata de catre Host. Acesta poate sa ii spuna aplicatiei: hey, trebuie sa persisti!
In incheiere… 1. Am vazut despre ce este vorba in Windows Workflow Foundation Am si creat cateva WF Am discutat despre cele 3 moduri de a rula WF in aplicatiile voastre Am vorbit despre crearea de activitati custom 2. Am evidentiat si unele avantaje pe care le aduce WF, acesta ar fi unul dintre ele… 3. Cu ce am vazut astazi puteti sa incepeti sa creati propriile aplicatii cu WF: WF Invoker, New Sequence, WriteLine si gata!