BlogServiceHost.Create()

WCF & Azure - Il blog di Fabio Cozzolino

Recent Posts

Tags

My

Twitter

Community

Archives

Email Notifications

Social Bar Widget

[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 Big Smile.

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 Stick out tongue). 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 ...

Posted: Sep 02 2008, 01:16 AM by Fabio.Cozzolino | with no comments
Filed under: