博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
坚持学习WF(10):在工作流中使用关联
阅读量:6851 次
发布时间:2019-06-26

本文共 8590 字,大约阅读时间需要 28 分钟。

一:当我们在工作流中使用本地服务的事件的时候,WF运行时引擎将入站消息映射到实例中的特定的HandleExternalEventActivity活动,对实例的映射是在将工作流实例InstanceId传递到ExternalDataEventArgs构造函数时完成的。所以当工作流实例在本地服务接口上侦听相同事件的不同实例时,就无法确定该响应哪个事件。如下图:

如何解决这个问题呢,我们就需要在工作流中使用关联,通过使用接口属性来定义关联,使用关联后通信活动会多出一个CorrelationToken属性(关联标记)。当宿主中要触发一个外部事件时,可以传递两个参数,一个是实例的ID号,一个是关联标记编号。这样就可以将事件路由到该工作流实例中正确的活动。

使用关联时要成对使用CallExternalMethodActivity与HandleExternalEventActivity。

下面看下关联的接口属性:

CorrelationParameterAttribute 

用于指定在接口中定义的方法和事件的用于关联的参数名称。 如果方法或事件包含一个与该名称匹配的形参,则该参数定义该方法或事件上的相关值。 如果方法或事件没有此类参数,则方法或事件可以使用 CorrelationAliasAttribute 来定义相关值的位置。 此属性在一个接口中可以出现多次。

CorrelationInitializerAttribute 

用于在方法或事件中指示相关参数的值是在调用该方法或引发该事件时初始化的。 对于给定的 CorrelationToken,必须在对话中的任何其他方法或事件执行之前调用或接收初始值设定项方法或事件。 任何可以初始化新对话(即新的相关令牌)的方法或事件都必须使用此属性进行标记。 对于每个相关令牌,方法或事件必须包含一个适当的命名参数或一个 CorrelationAliasAttribute。

CorrelationAliasAttribute 

在方法或事件定义中用来重写该成员的 CorrelationParameter 设置。 CorrelationAliasAttribute 属性指定可用参数中可以获得相关值的位置。 该字符串参数是针对形参集的以点分隔的路径。 该参数指示在何处可以找到匹配数据值。 如果定义了多个相关令牌,还必须指定令牌 Name 命名参数。

二:下面是个小例子,该示例中工作流将创建两个任务,然后在这些任务完成时等待(同一本地服务事件)通知。 在这种情况下,当外部代码将事件引发到工作流时,本地服务基础结构必须依赖于所引发事件中的数据(相关值)将事件路由到工作流实例中相应的 HandleExternalEventActivity 活动。

每创建一项任务,任务服务就会显示一个消息框,通知用户任务已创建。 单击了“确定”按钮后,将为对应的任务 ID 引发用以完成任务的事件。 这些属性与 CreateTask 活动上设置的属性相同,因此事件与正确的 TaskCompleted 活动关联。

1.事件参数类TaskEventArgs:

[Serializable]
    
public 
class TaskEventArgs : ExternalDataEventArgs
     {
        
string idValue;
        
string assigneeValue;
        
string textValue;
        
public TaskEventArgs(Guid instanceId, 
string id, 
string assignee, 
string text)
            :
base(instanceId)
        {
            
this.idValue = id;
            
this.assigneeValue = assignee;
            
this.textValue = text;
        }
        
public 
string Id
        {
            
get { 
return 
this.idValue; }
            
set { 
this.idValue = value; }
        }
        
public 
string Assignee
        {
            
get { 
return 
this.assigneeValue; }
            
set { 
this.assigneeValue = value; }
        }
        
public 
string Text
        {
            
get { 
return 
this.textValue; }
            
set { 
this.textValue = value; }
        }
    }

2.定义服务接口:   

[ExternalDataExchange]
    [CorrelationParameter(
"
taskId
")]
    
public 
interface ITaskService
     {         
        [CorrelationInitializer]
        
void CreateTask(
string taskId, 
string assignee, 
string text);
        [CorrelationAlias(
"
taskId
"
"
e.Id
")]
        
event EventHandler<TaskEventArgs> TaskCompleted;
    }

注意:2.1 [CorrelationParameter("taskId")] 中的"taskId"和CreateTask方法中的string taskId要一致。
           2.2 [CorrelationAlias("taskId", "e.Id")] 关联参数的别名绑定。 

 

3.实现服务类:
public 
class TaskService : ITaskService
     {
        
public 
void CreateTask(
string taskId, 
string assignee, 
string text)
        {
            Console.WriteLine(
"
task 
" + taskId + 
"
 created for 
" + assignee);
            ThreadPool.QueueUserWorkItem(ShowDialog, 
new TaskEventArgs(WorkflowEnvironment.WorkflowInstanceId, taskId, assignee, text));
        }
        
public 
void RaiseEvent(TaskEventArgs args)
        {
            EventHandler<TaskEventArgs> taskCompleted = 
this.TaskCompleted;
            
if (taskCompleted != 
null)
                taskCompleted(
null, args);
        }
        
public 
void ShowDialog(
object state)
        {
            TaskEventArgs taskEventArgs = state 
as TaskEventArgs;
            MessageBox.Show(
string.Format(
"
{0}, click OK when '{1}' completed.
", taskEventArgs.Assignee, taskEventArgs.Text), 
string.Format(
"
Task {0}
", taskEventArgs.Id), MessageBoxButtons.OK);
            
            RaiseEvent(taskEventArgs);
        }
        
public 
event EventHandler<TaskEventArgs> TaskCompleted;
    }

4.创建自定义通信活动

4.1 CreateTask活动继承自CallExternalMethodActivity,来调用本地服务中的方法,在构造函数中设定InterfaceType和MethodName属性。代码如下:

 
[ToolboxItemAttribute(
typeof(ActivityToolboxItem))]
    
public 
partial 
class CreateTask : System.Workflow.Activities.CallExternalMethodActivity
     {
        
//
 Properties on the task
        
public 
static DependencyProperty AssigneeProperty = DependencyProperty.Register(
"
Assignee
"
typeof(System.String), 
typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
        
public 
static DependencyProperty TaskIdProperty = DependencyProperty.Register(
"
TaskId
"
typeof(System.String), 
typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
        
public 
static DependencyProperty TextProperty = DependencyProperty.Register(
"
Text
"
typeof(System.String), 
typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask));
        
private 
void InitializeComponent()
        {
        }
    
        
public CreateTask()
        {
            
this.InterfaceType = 
typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.ITaskService);
            
this.MethodName = 
"
CreateTask
";
        }
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(
true)]
        
public 
string Assignee
        {
            
get
            {
                
return ((
string)(
base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty)));
            }
            
set
            {
                
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.AssigneeProperty, value);
            }
        }
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(
true)]
        
public 
string TaskId
        {
            
get
            {
                
return ((
string)(
base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty)));
            }
            
set
            {
                
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TaskIdProperty, value);
            }
        }
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(
true)]
        
public 
string Text
        {
            
get
            {
                
return ((
string)(
base.GetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty)));
            }
            
set
            {
                
base.SetValue(Microsoft.Samples.Workflow.CorrelatedLocalService.CreateTask.TextProperty, value);
            }
        }
        
protected 
override 
void OnMethodInvoking(EventArgs e)
        {
            
this.ParameterBindings[
"
taskId
"].Value = 
this.TaskId;
            
this.ParameterBindings[
"
assignee
"].Value = 
this.Assignee;
            
this.ParameterBindings[
"
text
"].Value = 
this.Text;
        }
       
    }
4.2 TaskCompleted活动继承自HandleExternalEventActivity,来处理本地服务中的事件,在构造函数中设定
InterfaceType和EventName属性。代码如下:
[ToolboxItemAttribute(
typeof(ActivityToolboxItem))]
    
public 
partial 
class TaskCompleted : System.Workflow.Activities.HandleExternalEventActivity
     {
        
//
 properties
        
public 
static DependencyProperty SenderProperty = System.Workflow.ComponentModel.DependencyProperty.Register(
"
Sender
"
typeof(Object), 
typeof(TaskCompleted));
        
public 
static DependencyProperty EProperty = System.Workflow.ComponentModel.DependencyProperty.Register(
"
E
"
typeof(TaskEventArgs), 
typeof(TaskCompleted));
        
public TaskCompleted()
        {
            
this.EventName = 
"
TaskCompleted
";
            
this.InterfaceType = 
typeof(Microsoft.Samples.Workflow.CorrelatedLocalService.ITaskService);
        }
        
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(
true)]
        
public 
object Sender
        {
            
get
            {
                
return ((Object)(
base.GetValue(TaskCompleted.SenderProperty)));
            }
            
set
            {
                
base.SetValue(TaskCompleted.SenderProperty, value);
            }
        }
        
public 
static DependencyProperty EventArgsProperty = System.Workflow.ComponentModel.DependencyProperty.Register(
"
EventArgs
"
typeof(TaskEventArgs), 
typeof(TaskCompleted));
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [BrowsableAttribute(
true)]
        
public Microsoft.Samples.Workflow.CorrelatedLocalService.TaskEventArgs EventArgs
              {
            
get
            {
                
return ((TaskEventArgs)(
base.GetValue(TaskCompleted.EventArgsProperty)));
            }
            
set
            {
                
base.SetValue(TaskCompleted.EventArgsProperty, value);
            }
        }
        
protected 
override 
void OnInvoked(EventArgs e)
        {
            EventArgs = e 
as TaskEventArgs;
        }
    }
5.实现工作流如下图:
 
完整代码如下:

 
public 
sealed 
partial 
class CorrelatedLocalServiceWorkflow : SequentialWorkflowActivity
     {
        
public CorrelatedLocalServiceWorkflow()
        {
            InitializeComponent();
        }        
        
private 
void OnTaskCompleted(
object sender, ExternalDataEventArgs e)
        {
            Console.WriteLine(
"
task 
" + ((TaskEventArgs)e).Id + 
"
 done
");
        }
    }

6.两个自定义活动关于关联的相关属性的设置,

 

CreateTask活动和TaskCompleted活动中多了如下属性,给这个关联提供一个唯一的名称.每个分支上的CorrelationToken设置要一致。

7.宿主程序:  

 
class WorkflowApplication
     {
        
static AutoResetEvent waitHandle = 
new AutoResetEvent(
false);
        
static TaskService taskService = 
new TaskService();
        
static WorkflowInstance instance;
        
static 
void Main()
        {
            
using (WorkflowRuntime workflowRuntime = 
new WorkflowRuntime())
            {
                ExternalDataExchangeService dataExchangeService = 
new ExternalDataExchangeService();
                workflowRuntime.AddService(dataExchangeService);
                dataExchangeService.AddService(taskService);
                workflowRuntime.StartRuntime();
                workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
                workflowRuntime.WorkflowTerminated += 
delegate(
object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };
                instance = workflowRuntime.CreateWorkflow(
typeof(CorrelatedLocalServiceWorkflow));
                instance.Start();
                waitHandle.WaitOne();
                workflowRuntime.StopRuntime();
            }
        }
        
static 
void OnWorkflowCompleted(
object sender, WorkflowCompletedEventArgs instance)
        {
            waitHandle.Set();
        }
    }

 

程序运行后结果如下:

本文转自生鱼片博客园博客,原文链接:http://www.cnblogs.com/carysun/archive/2008/06/01/WFCorrelation.html,如需转载请自行联系原作者

你可能感兴趣的文章
50. Spring Boot日志升级篇—log4j【从零开始学Spring Boot】
查看>>
测试学习方向
查看>>
linux下安装python3
查看>>
数据结构绪论
查看>>
将博客搬至CSDN
查看>>
C#判断本地系统的网络连接状态
查看>>
F# 入门(二):安装和使用
查看>>
渗透测试流程
查看>>
C++学习笔记 -- 虚析构函数与纯虚析构函数
查看>>
Oracle中的日期函数
查看>>
01_对象的创建方法
查看>>
one-shot 检测算法YOLO、SSD
查看>>
ansible 提示安装sshpass
查看>>
常用SQL语句
查看>>
Linux网络编程必看书籍推荐
查看>>
GitHub在windows上代码管理教程
查看>>
Android 异步处理
查看>>
Magento安装错误:PHP extension ‘mcrypt’ ‘curl’ must be loaded.
查看>>
转:linux/unix命令行终端的光标及字符控制快捷键
查看>>
Yahoo为啥赚不到钱
查看>>