Windows Workflow Foundation
Podstawowe pojęcia Proces biznesowy jest kolekcją wzajemnie powiązanych zadań, inicjowaną w odpowiedzi na konkretne zdarzenie, prowadzącą do powstania określonego produktu/usługi dla klienta procesu. Definicja procesu obejmuje całościowe i wyczerpujące opisanie przebiegu procesu w postaci powiązanego zbioru czynności, relacji między tymi czynnościami, warunku rozpoczęcia i zakończenia procesu, szczegółowego opisu czynności składowych, uczestników procesu, wymienianych bądź modyfikowanych danych za pomocą wybranego języka i/lub przyjętej konwencji reprezentacji graficznej Workflow - automatyzacja procesu biznesowego w całości lub w części podczas której dokumenty, informacje lub zadania są przesyłane od jednego uczestnika do następnego celem ich realizacji zgodnie z określonymi zasadami postępowania
Standard WfMC 1 5 Usługa powołująca instancje procesów, wykonująca je i zarządzająca nimi 4 2i3 Workflow Management Coalition to organizacja zrzeszająca producentów oprogramowania wspomagającego zarządzanie procesów pracy, użytkowników, analityków i uniwersyteckie grupy badawcze
Workflow (def. /instancja) Workflow - grupa czynności WorkflowChanges -Twórca workflow może określić czy i w jakim zakresie może on zostać zmodyfikowany w takcie jego wykonywania (np. dodanie, usunięcie kroku) Niektóre procesy mogą być długotrwałe, więc musi być możliwość zapisania stanów instancji workflow i wznowienia go do działania
Activity (definicja / instancja) Czynność prosta Czynność złożona System.Workflow.Activities.dll
Typy workflow sekwencyjny wykonuje czynności zgodnie ze zdefiniowaną kolejnością (może zawierać rozwidlenia, pętle itp.); maszyna stanów o wykonaniu czynności w określonym czasie decyduje bieżąca kombinacja stanów i odebrane zdarzenie;
Konfiguracja środowiska Windows.NET Framework 3.0 i Visual Studio 2005 Extensions for Windows Workflow Foundation lub Visual studio 2008
Komponenty WF Workflow runtime Wymaga aplikacji hosta Jest uzależniony od dodatkowych usług
Komponenty WF... WorkflowRuntime runtime = new WorkflowRuntime(); runtime.addservice(...) WorkflowInstance instance = runtime.createworkflow(...); instance.start(); Guid id = instance.instanceid;...
Workflow Designer http://msdn2.microsoft.com/en-us/library/ aa480213.aspx
Markup Only Markup + Code Code only XAML XAML C#/VB C#/VB Workflow Compiler Markup Only XAML C#/VB Compiler NET Assembly Workflow Instance Workflow Runtime Workflow Designers (À la ASP.NET Designer) tworzy nowe workflow y Activity Designer (À la UserControl Designer) tworzy nowe czynności
Workflow w XAML (*.xoml) <SequentialWorkflowActivity x:class="doorsworkflow.workflow1" x:name="workflow1" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"> <IfElseActivity x:name="ifelseactivity1"> <IfElseBranchActivity x:name="ifelsebranchactivity1"> <IfElseBranchActivity.Condition> <CodeCondition Condition="Test" /> </IfElseBranchActivity.Condition> <CodeActivity x:name="codeactivity1" ExecuteCode="DoSomething" /> </IfElseBranchActivity> <IfElseBranchActivity x:name="ifelsebranchactivity2"> <CodeActivity x:name="codeactivity2" ExecuteCode="DoSomethingElse" /> </IfElseBranchActivity> </IfElseActivity> </SequentialWorkflowActivity>
Przykład Witaj Projekt typu Sequential Workflow Console Application Dla CodeActivity właściwość obowiązkowa to ExecuteProperty private void codeactivity1_executecode(object sender, EventArgs e) { Console.WriteLine("Hello World"); Console.ReadKey(); }
Biblioteka podstawowych czynności IfElse: wykonanie czynności zawarte w 2 lub więcej ścieżkach zależnie od spełnienia warunku; While: wykonanie w pętli 1 lub więcej czynności dopóki warunek=true; Sequence: wykonuje grupę czynności jeden raz według zdefiniowanej kolejności; Parallel: wykonanie 2 lub więcej grup czynności równolegle;
Podstawowe czynności (2) Code: wykonuje zdefiniowany kawałek kodu; ExecuteCode dowiązać metodę do wykonania; Listen: oczekiwanie na określone zdarzenie, wiele gałęzi, wykonanie 1 lub wielu czynności gdy zdarzenie zaistniało (implementujących IEventActivity np.. DelayActivity, HandleExternalEventActivity, WebServiceInputActivity); InvokeWebService: wywołanie usługi sieciowej z wykorzystaniem ASP.NET Web Services.
Podstawowe czynności (3) State: reprezentuje stan w workflow owej maszynie stanów; EventDriven: definiuje przejście zawierające 1 lub więcej czynności które powinny być wykonane gdy określone zdarzenie zaistnieje podczas trwania w określonym stanie; Policy: pozwala na wykonanie reguł biznesowych utrzymywanych w silniku reguł Wykorzystywanie tych czynności jest opcjonalne, każdy może zbudować sobie zestaw własnych
Model wykonywania czynności kolejne stany public class CreateTask : Activity { public string Assignee {... } public DateTime DueDate {... } } protected override ActivityExecutionStatus Execute( ActivityExecutionContext context) { ActivityExecutionStatus używane // tu wywołuje metodę _ExecuteCode return ActivityExecutionStatus.Closed; przez runtime do określenia np. } kiedy czynność się zakończyła pomyślnie, ciągle trwa,.
Czynności - cechy opcjonalne Companion Classes Designer [Designer(typeof(MyDesigner))] Validator [Validator(typeof(MyValidator))] Serializer [Serializer(typeof(MySerializer))] [CodeGenerator(typeof(MyCodeGen))] [ToolboxItem(typeof(MyToolboxItem))] Code Generator ToolboxItem Behaviors [SupportsTransaction] [SupportsExceptionHandlers] public class MyActivity: Activity {... } Transactions
Custom Activities (composite) DaysOfWeekActivity SequenceActivty: Monday, Tuesday, Wednesday, Thursday, Friday <other activites as appropriate> SequenceActivity: Saturday, Sunday <other activites as appropriate> [Flags] [Editor(typeof(FlagsEnumEditor), typeof(uitypeeditor))] public enum WeekdayEnum : byte { None = 0x00, Sunday = 0x01, Monday = 0x02, Tuesday = 0x04, Wednesday = 0x08, Thursday = 0x10, Friday = 0x20, Saturday = 0x40 }
Custom Activities def.(2) public class DaysOfWeekActivity : CompositeActivity { /// <summary> /// Get/Set the day of week property /// </summary> [Browsable(true)] [Category("Behavior")] [Description("Bind to a DateTime property, set a specific date time, or leave blank for DateTime.Now")] [DefaultValue(typeof(DateTime),"")] public DateTime Date { get { return (DateTime)base.GetValue(DaysOfWeekActivity.DateProperty); } set { base.setvalue(daysofweekactivity.dateproperty, value); } } /// <summary> /// Register the DayOfWeek property /// </summary> public static DependencyProperty DateProperty = DependencyProperty.Register("Date", typeof(datetime), typeof(daysofweekactivity)); }
Custom Activities Designer (3) public class DaysOfWeekDesigner : ParallelActivityDesigner { public override bool CanInsertActivities (HitTestInfo insertlocation, ReadOnlyCollection<Activity> activities) { foreach (Activity act in activities) { if (!(act is SequenceActivity)) return false; } return base.caninsertactivities(insertlocation, activitiestoinsert); } protected override CompositeActivity OnCreateNewBranch() { return new SequenceActivity(); } } [Designer(typeof(DaysOfWeekDesigner))] public class DaysOfWeekActivity : CompositeActivity {... }
Custom Activities- Toolbox(4) [Serializable] public class DaysOfWeekToolboxItem : ActivityToolboxItem { public DaysOfWeekToolboxItem(Type t) : base(t) { this.displayname = "DaysOfWeek"; } private DaysOfWeekToolboxItem(SerializationInfo info, StreamingContext context) { this.deserialize(info, context); } protected override IComponent[] CreateComponentsCore(IDesignerHost host) { CompositeActivity parent = new DaysOfWeekActivity(); parent.activities.add(new SequenceActivity()); parent.activities.add(new SequenceActivity()); return new IComponent[] { parent }; } } [Designer(typeof(DaysOfWeekDesigner))] [ToolboxItem(typeof(DaysOfWeekToolboxItem))] public class DaysOfWeekActivity : CompositeActivity { }
Attached Properties (5) To właściwość zdefiniowana w jednej klasie a wyświetlana / ustawiana w innej Definicja w klasie DaysofWeekActivity: public static DependencyProperty WeekdayProperty = DependencyProperty.RegisterAttached("Weekday", typeof(weekdayenum), typeof(daysofweekactivity), new PropertyMetadata(DependencyPropertyOptions.Metadata)); Wyświetlana i ustawiana w podgałęzi SequenceActivity: Jeżeli w designerze ustawimy Weekday na Saturday, Sunday to odpowiada to kodowi: this.sequenceactivity1.setvalue (DaysOfWeekActivity.WeekdayProperty, ((WeekdayEnum)((WeekdayEnum.Sunday WeekdayEnum.Saturday))));
Attached Properties set/get(6) public static void SetWeekday(Activity activity, object value) { if (null == activity) throw new ArgumentNullException("activity"); if (null == value) throw new ArgumentNullException("value"); activity.setvalue(daysofweekactivity.weekdayproperty, value); } public static object GetWeekday(Activity activity) { if (null == activity) throw new ArgumentNullException("activity"); return activity.getvalue(daysofweekactivity.weekdayproperty); }
Attached Properties (7) udostępnienie w projektancie public class DaysOfWeekDesigner : ParallelActivityDesigner {... protected override void Initialize(Activity activity) { base.initialize(activity); IExtenderListService iels = base.getservice(typeof(iextenderlistservice)) as IExtenderListService; if (null!= iels) { bool extenderexists = false; foreach (IExtenderProvider provider in iels.getextenderproviders()) { if (provider.gettype() == typeof(weekdayextenderprovider)) { extenderexists = true; break; } // jest ExtenderProvider naszego typu } if (!extenderexists) { IExtenderProviderService ieps = base.getservice(typeof(iextenderproviderservice)) as IExtenderProviderService; //utwórz usługę IExtenderProvider a if (null!= ieps) ieps.addextenderprovider(new WeekdayExtenderProvider()); } //dodaj do niego exteder naszego typu } }... }
Kod naszego Extender Provider a (8) [ProviderProperty("Weekday", typeof(sequenceactivity))] public class WeekdayExtenderProvider : IExtenderProvider { bool IExtenderProvider.CanExtend(object extendee) { bool canextend = false; if ((this!= extendee) && (extendee is SequenceActivity)) { Activity parent = ((Activity)extendee).Parent; if (null!= parent) canextend = parent is DaysOfWeekActivity; } return canextend; } public WeekdayEnum GetWeekday(Activity activity) { WeekdayEnum weekday = WeekdayEnum.None; Activity parent = activity.parent; if ((null!= parent) && (parent is DaysOfWeekActivity)) weekday = (WeekdayEnum)DaysOfWeekActivity.GetWeekday(activity); return weekday; } public void SetWeekday(Activity activity, WeekdayEnum weekday) { Activity parent = activity.parent; if ((null!= parent) && (parent is DaysOfWeekActivity)) DaysOfWeekActivity.SetWeekday(activity, weekday); } }
Przekazywanie parametrów do instancji workflow public class OrderProcessingWorkflow: SequentialWorkflowActivity { public int OrderID { get { return _orderid; } set { _orderid = value; } } private int _orderid; } WorkflowRuntime runtime = new WorkflowRuntime (); Dictionary<string,object> parms = new Dictionary<string,object>(); parms.add("orderid", 12345) ; WorkflowInstance instance = runtime.createworkflow (typeof(orderprocessingworkflow), parms); instance.start(); Na bazie par klucz wyszukiwane są właściwości publiczne jeżeli przypasowanie odnaleziono wołany jest set przypisujący wartość jeżeli nie to przy próbie utworzenia instancji generowany wyjątek
Pobieranie wyników z instancji using(workflowruntime workflowruntime = new WorkflowRuntime()) { AutoResetEvent waithandle = new AutoResetEvent(false); workflowruntime.workflowcompleted += delegate(object sender, WorkflowCompletedEventArgs e) { waithandle.set(); foreach (KeyValuePair<string, object> parm in e.outputparameters) {Console.WriteLine("{0} = {1}", parm.key, parm.value); } }; WorkflowInstance instance =workflowruntime.createworkflow (typeof(workflow1)); instance.start(); waithandle.waitone(); //oczekiwanie na zakończenie wykonywania instancji }
Wiązanie parametrów public TimeSpan oczekiwanie { get { return ocz_value; } set { ocz_value = value; } } private TimeSpan ocz_value; public TimeSpan TimeoutDuration { get { return (TimeSpan)base.GetValue(DelayActivity.TimeoutDurationProperty); } set { base.setvalue(delayactivity.timeoutdurationproperty, value); } }
Hosting Windows Workflow Foundation Środowisko uruchomieniowe - WorkflowRuntime instancje tworzy się raz w aplikacji, CreateWorkflow() - tworzy instancję workflow GetLoadedWorkflows() daje kolekcję załadowanych instancji workflow dostarcza usługi potrzebne do wykonywania instancji AddService() dodanie usługi do runtime GetAllServices(Type servicetype) zwraca kolekcje usług o określonym typie) zbiór zdefiniowanych zdarzeń występujących w trakcie wykonywania instancji workflow
Workflow-enabled services Usługa jest klasą potrzebną przy wykonywaniu instancji workflow (poszczególnych czynności) protected override ActivityExecutionStatus Execute (ActivityExecutionContext executioncontext) { ICustomService myservice = executioncontext.getservice<icustomservice>();... Do something with the service }
Standardowe usługi związane (2) using(workflowruntime workflowruntime = new WorkflowRuntime()) { workflowruntime.startruntime(); bool s = workflowruntime.isstarted; ReadOnlyCollection<Object> x = workflowruntime.getallservices(typeof(object)); foreach (Object a in x) { Console.WriteLine( a.tostring()); } }
Workflow Execution (3) bezczynny! Workflow Runtime Workflow Instance Runtime Services Loader XAML Persistence Host Application Po ponownym uruchomieniu Workflow Runtime mogą zostać przywrócone instancje workflow (z bazy persistance), które wykonywały się przy ostatnim jego działaniu ale nie zostały zakończone; Workflow Instance
Dodawanie usług do runtime (4) Jeszcze przed wystartowaniem runtime w przeciwnym wypadku wyjątek using(workflowruntime workflowruntime = new WorkflowRuntime()) { workflowruntime.addservice( new SqlWorkflowPersistenceService(conn, true, new TimeSpan(1,0,0), new TimeSpan(0,10,0))); workflowruntime.addservice(new SqlTrackingService(conn));... workflowruntime.startruntime(); }
Dodawanie usług do runtime(5) <?xml version="1.0" encoding="utf-8"?> <configuration> <configsections> <section name="wf" type="system.workflow.runtime.configuration.workflowruntimesection, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </configsections> using(workflowruntime workflowruntime = new <WF Name="Hosting"> WorkflowRuntime("WF")) {... } <CommonParameters/> <Services> <add type="system.workflow.runtime.hosting.sqlworkflowpersistenceservice, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionstring="initial Catalog=WF;Data Source=.; Integrated Security=SSPI;" UnloadOnIdle="true" LoadIntervalSeconds="2"/> <add type="system.workflow.runtime.tracking.sqltrackingservice, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionstring="initial Catalog=WF;Data Source=.; Integrated Security=SSPI;" UseDefaultProfile="true"/> </Services> </WF> </configuration>
Runtime Services- persistence (6) dziedziczy z WorkflowPersistenceService przechwytuje instancje workflow, serializuje, zrzuca i zachowuje jej stan do bazy SQL Servera lub do pliku na dysku SqlWorkflowPersistenceService() z System.Workflow.Runtime.Hosting; using(workflowruntime workflowruntime = new WorkflowRuntime()) { workflowruntime.addservice( new SqlWorkflowPersistenceService(conn, true, new TimeSpan(1,0,0), new TimeSpan(0,10,0))); // Execute a workflow here... } Wymaga uruchomienia skryptów do: utworzenia schematu bazy utworzenia procedur składowanych (C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN ) Może być wykorzystywany przez wiele środowisk wykonawczych równocześnie dany workflow dostępny jedynie przez jeden WRuntime
Tracking Services (7) Może rejestrować, które czynności się już wykonały, które gałęzie zostały wybrane, maksimum danych z wykonania konkretnej instancji Dane te służą do późniejszej weryfikacji Ułatwiają wyszukanie błędów Ich analiza może przyczynić się do podjęcia decyzji o przebudowie szablonu workflow w celu zwiększenia wydajności przy wykonywaniu instancji Implementowany jako klasa abstrakcyjna TrackingService dostępna implementacja SqlTrackingService() TrackingProfile definiuje co śledzić (zdarzenia na workflow, wykonywanie poszczególnych czynności,..)
Tracking Services (8) Odczytanie danych z bazy bezpośrednie pytania przez SqlTrackingQuery Przykład jakie instancje był śledzone w zadanym okresie czasu: public IList<SqlTrackingWorkflowInstance> GetWorkflows (DateTime startdate, DateTime enddate, string connectionstring) { SqlTrackingQuery query = new SqlTrackingQuery (connectionstring); SqlTrackingQueryOptions queryoptions = new SqlTrackingQueryOptions(); queryoptions.statusmindatetime = startdate; queryoptions.statusmaxdatetime = enddate; return (query.getworkflows (queryoptions)); }
Własne usługi (9) Def.interfejsu: [ExternalDataExchange] public interface IDoorService { void LockDoor(); void UnlockDoor(); event EventHandler<ExternalDataEventArgs> RequestEntry; event EventHandler<ExternalDataEventArgs> OpenDoor; event EventHandler<ExternalDataEventArgs> CloseDoor; event EventHandler<ExternalDataEventArgs> FireAlarm; void OnRequestEntry(Guid id); void OnOpenDoor(Guid id); void OnCloseDoor(Guid id); void OnFireAlarm(); }
Własne usługi (10) ExternalDataExchangeService - proxy dla zdarzeń od usługi do workflow, przywraca jak trzeba instancję z bazy persistence WorkflowRuntime runtime = new WorkflowRuntime(); ExternalDataExchangeService edes = new ExternalDataExchangeService(); runtime.addservice(edes); DoorService service = new DoorService(); edes.addservice(service); runtime.startruntime(); Zadrzenia wykorzystują klasę ExternalDataEventsArgs do przekazania parametrów zwrotnych do workflow (standardowo jest tam id_instancji, inne powinny być dodane do niej jako właściwości)
Zmiana definicji workflow w trakcie działania Utwórz obiekt WorkflowChanges zawierający wszystkie nowe czynności dodane do workflow (z System.Workflow.ComponentModel) WorkflowChanges a = new WorkflowChanges(rootActivity); Wywołaj metodę ApplyWorkflowChanges() na konkretnej instancji instance.applyworkflowchanges(a);
Windows WF a WCF Z jednej strony Workflow wywołuje usługi jako czynności z drugiej Usługę można zaimplementować jako workflow W.NET Framework 3.0 nie można było mieszać technologii WF i WCF W.NET Framework 3.5 można obie mieszać dzięki nowym czynnościom: Send wysłanie żądania za pomocą WCF i oczekiwanie na odpowiedź. (developer określa operacje jaka ma być wywołana i punkt z którego jest ona dostępna) Receive otrzymanie prośby nadchodzącej od WCF i wysłanie odpowiedzi (developer określa nazwę operacji odpowiadającej żądaniu)
BPEL for Windows Workflow Foundation March CTP Microsoft provides BPEL 2.0 in WF - BPEL for Windows Workflow Foundation March CTP http://www.microso ft.com/downloads/ details.aspx? FamilyID=6d0daf0 0-f689-4e61-88e6cbe6f668e6a3&dis
WS-BPEL 2.0 a WF WS-BPEL is very much a subset of what can be represented using WF. Think of WF as a "graph of activities" that can be transformed to virtually any workflow standard.
Literatura Professional C# 2005 with.net 3.0 Christian Nagel, Bill Evjen, Jay Glynn, Morgan SkinnerandKarli Watson Wrox Press 2007 (1798 pages) ISBN:9780470124727 Providing you with the ultimate guide to the C# language, this authoritative book will help you quickly write your own programs while also getting you up to speed on how the.net architecture works.
WF- sekwencyjny / WF* - maszyna stanów
Summary Windows WF What is Workflow? Workflow is the software implementation of business process or business logic What s the value of Workflow? Transparency Flexibility Extensibility Releasing in November 2006 as a part of Microsoft Windows Vista Visual Studio Designer A Workflow Activity Activity Library Workflow Runtime Engine Runtime Services Host Process