[WF] Sviluppare una Custom DynamicInvokeWorkflowActivity
Ultimamente sto smanettando parecchio con Windows Workflow Foundation. Lo ammetto, la mia conoscenza in materia è ancora molto carente ma mi sto attrezzando
.
Nel pacchetto di activities che WF "regala" c'è la InvokeWorkflowActivity che consente di invocare un secondo workflow da uno esterno, ma il tutto deve essere impostato a design-time. La mia particolare esigenza è quella di voler invocare un determinato workflow dipendentemente dal messaggio che ricevo in input (e te pareva che non andava a finire che parlavo di WCF
). Ho preso la palla al balzo per iniziare ad approfondire WF e mi sono costruito una Activity che risponde semplicemente alla mia esigenza.
In pratica nel momento in cui il controllo passa a questa activity, viene generato un evento ed esternamente deve essere impostato il tipo del workflow da richiamare. Riporto qui il codice dell'Activity:
1 [ActivityValidator(typeof(DinamicallyInvokeWorkflowActivityValidator))]
2 [DefaultEvent("InitializeTargetWorkflow")]
3 public partial class DinamicallyInvokeWorkflowActivity : Activity
4 {
5 public static readonly DependencyProperty InitializeTargetWorkflowEvent = DependencyProperty.Register("InitializeTargetWorkflow", typeof(InitializeTargetWorkflowEventHandler), typeof(DinamicallyInvokeWorkflowActivity));
6
7 public DinamicallyInvokeWorkflowActivity()
8 {
9 InitializeComponent();
10 }
11
12 #region Designer generated code
13
14 private void InitializeComponent()
15 {
16 this.Name = "DinamicallyInvokeWorkflowActivity";
17 }
18
19 #endregion
20
21 public class InitializeTargetWorkflowEventArgs : EventArgs
22 {
23 public Type TargetWorkflow { get; set; }
24 }
25
26 public delegate void InitializeTargetWorkflowEventHandler(InitializeTargetWorkflowEventArgs e);
27
28 public event InitializeTargetWorkflowEventHandler InitializeTargetWorkflow
29 {
30 add
31 {
32 base.AddHandler(InitializeTargetWorkflowEvent, value);
33 }
34 remove
35 {
36 base.RemoveHandler(InitializeTargetWorkflowEvent, value);
37 }
38 }
39
40 protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
41 {
42 InitializeTargetWorkflowEventHandler[] handlers = this.GetInvocationList<InitializeTargetWorkflowEventHandler>(InitializeTargetWorkflowEvent);
43 InitializeTargetWorkflowEventHandler handler = handlers[0] as InitializeTargetWorkflowEventHandler;
44 InitializeTargetWorkflowEventArgs e = new InitializeTargetWorkflowEventArgs();
45 handler(e);
46
47 if (e.TargetWorkflow == null)
48 {
49 throw new InvalidOperationException("La proprietà TargetWorkflow non è stata impostata correttamente o è nulla.");
50 }
51
52 if (!TypeProvider.IsAssignable(typeof(Activity), e.TargetWorkflow))
53 {
54 throw new InvalidOperationException("L'oggetto impostato non è un tipo di workflow valido.");
55 }
56
57 IStartWorkflow startWorkflow = executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow;
58 startWorkflow.StartWorkflow(e.TargetWorkflow, null);
59
60 return ActivityExecutionStatus.Closed;
61 }
62 }
63
Successivamente gli aggiungiamo anche il validatore per verificare che l'evento InitializeTargetWorkflow sia stato correttamente valorizzato:
1 private class DinamicallyInvokeWorkflowActivityValidator : ActivityValidator
2 {
3 public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
4 {
5 ValidationErrorCollection errors = new ValidationErrorCollection();
6 DinamicallyInvokeWorkflowActivity activity = obj as DinamicallyInvokeWorkflowActivity;
7 if (activity == null)
8 {
9 throw new InvalidOperationException();
10 }
11
12 if (activity.Parent == null)
13 {
14 return base.Validate(manager, obj);
15 }
16
17 if ((activity.GetInvocationList<InitializeTargetWorkflowEventHandler>(DinamicallyInvokeWorkflowActivity.InitializeTargetWorkflowEvent).Length == 0)
18 && (activity.GetBinding(DinamicallyInvokeWorkflowActivity.InitializeTargetWorkflowEvent) == null))
19 {
20 Hashtable hashtable = activity.GetValue(WorkflowMarkupSerializer.EventsProperty) as Hashtable;
21 if ((hashtable == null) || (hashtable["InitializeTargetWorkflow"] == null))
22 {
23 errors.Add(ValidationError.GetNotSetValidationError("InitializeTargetWorkflow"));
24 }
25 }
26 errors.AddRange(base.Validate(manager, obj));
27 return errors;
28 }
29 }
Ho definito un evento che riceve in input il tipo InitializeTargetWorkflowEventArgs. Il gestore dell'evento ha la responsabilità di impostare la proprietà TargetWorkflow. Questo è un workflow di esempio:
L'evento InitializeTargetWorkflow contiene un codice simile:
1 private void dinamicallyInvokeWorkflowActivity1_InitializeTargetWorkflow(DinamicallyInvokeWorkflowActivity.InitializeTargetWorkflowEventArgs e)
2 {
3 if (this.ReceivedMessage.Headers.Action == "http://tempuri.org/myfirstaction")
4 {
5 e.TargetWorkflow = typeof(Workflow1);
6 }
7 else
8 {
9 e.TargetWorkflow = typeof(Workflow2);
10 }
11 }
Se il messaggio ricevuto contiene l'action http://tempuri.org/myfirstaction allora verrà invocato il Workflow1, altrimenti verrà invocato il Workflow2.
Spero possa essere di aiuto a qualcuno ...