`

坚持学习WF(10):在工作流中使用关联

阅读更多

[置顶]坚持学习WF文章索引

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

correlation4

如何解决这个问题呢,我们就需要在工作流中使用关联,通过使用接口属性来定义关联,使用关联后通信活动会多出一个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));
align=
分享到:
评论

相关推荐

    坚持学习WF,WF学习教程

    坚持学习WF(10):在工作流中使用关联 当工作流实例在本地服务接口上侦听相同事件的不同实例时,就无法确定该响应哪个事件。如何解决这个问题呢,我们就需要在工作流中使用关联。 坚持学习WF(11):工作流通信与队列 ...

    坚持学习WF

    坚持学习WF(10):在工作流中使用关联 当工作流实例在本地服务接口上侦听相同事件的不同实例时,就无法确定该响应哪个事件。如何解决这个问题呢,我们就需要在工作流中使用关联。 坚持学习WF(11):工作流通信与队列 WF...

    WF教程_坚持学习WF

    坚持学习WF(1):从HelloWorld开始 本文主要通过实现了一个可以接受参数的HelloWorld程序来了解WF。 坚持学习WF(2):WF创作模式和设计时工具 坚持学习WF(3):WF框架概览 2.3两篇主要全面的阐述了WF框架和Visual ...

    WF工作流例子

    通过学习和分析这些例子,开发者可以了解到如何在实际项目中应用WF,如何设计和实现符合业务需求的工作流,以及如何与其他.NET组件和服务协同工作。WF工作流例子是提升开发者在流程自动化领域技能的重要资源,对于想...

    WF工作流学习资料

    WF通过工作流服务(Workflow Service)支持服务导向架构(SOA),使得工作流可以在Web服务中部署和执行。 2. **WF架构**:WF主要包括四个主要组件:设计时环境、运行时引擎、持久化服务和跟踪服务。设计时环境提供...

    WF工作流的一个完整例子

    在基于WF的工作流设计中,有几种基本的工作流类型:顺序工作流、状态机工作流、活动图工作流和业务规则工作流。顺序工作流按照预定义的顺序执行活动;状态机工作流根据事件触发状态变化;活动图工作流结合了顺序和...

    微软工作流WF资料

    在IT行业中,工作流(Workflow)是一个至关重要的概念,它涉及到业务...通过深入学习和实践"微软工作流WF资料"中的内容,开发者可以掌握如何利用WF创建高效、灵活的企业级工作流解决方案,提升业务流程的自动化水平。

    wf工作流资料<转自网上的笔记>

    "坚持学习WF(10)在工作流中使用关联"会涉及工作流中不同活动之间的数据传递和关联,包括如何定义变量、使用数据绑定等。 "坚持学习WF(11)工作流通信与队列"关注WF如何与其他组件或服务进行通信,可能包括使用队列...

    坚持学习WF(1):从HelloWorld开始 源码

    在本篇“坚持学习WF(1):从HelloWorld开始”的源码分析中,我们将深入理解WF的基础知识和创建第一个工作流的步骤。 首先,让我们了解WF的基本概念。WF提供了一种模型化业务流程的方式,通过活动(Activities)来表示...

    工作流学习代码(WF)

    工作流(Workflow)是信息化管理中的一个重要概念,它是...通过深入研究这些学习代码,开发者不仅可以掌握工作流的基本概念和技术,还能提升在实际项目中应用工作流的能力,从而为企业的业务流程自动化提供强大的支持。

    WF工作流的第二个完整例子.rar

    标签中的"C#"表明示例中使用了这种语言来实现工作流的逻辑。 WindowWorkflowFoundation(WF)提供了强大的工作流设计工具,允许开发者在Visual Studio中通过拖放活动来构建工作流。这些工作流可以通过图形化界面...

    简单的WF4.0工作流设计器

    6. **工作流持久化**:在VS2010RC环境中,开发者可能实现了工作流的保存和加载功能,这是通过WF4.0的内置持久化机制完成的,它可以将工作流状态存储到数据库或文件中。 7. **调试与运行时支持**:VS2010RC提供了...

    WF工作流笔记.rar

    综上所述,WF工作流笔记的内容涵盖了工作流的理论基础、实践方法、系统选择、自动化策略、监控与优化等多个方面,对于理解工作流以及在实际工作中应用工作流具有很高的参考价值。通过深入学习这些笔记,IT专业人士...

    在asp.net下用WF开发的工作流实例

    本实例将探讨如何在ASP.NET中使用WF进行工作流开发。 首先,Windows Workflow Foundation是.NET Framework的一部分,它提供了一个平台来设计、执行和管理工作流。WF支持四种主要的工作流模型:顺序流程、状态机流程...

    WF从入门到精通关于工作流的学习pdf格式的文档

    在“WF从入门到精通”教程中,读者将学习如何使用Visual Studio创建和设计工作流,以及如何在应用程序中集成和运行工作流。通过案例分析和实战演练,读者将掌握WF的核心技术,并能灵活应用于各种业务场景。 文档...

    WF工作流设计器(WPF版)

    9. **工作流运行时**:工作流设计器创建的工作流需要在WF运行时环境中执行。运行时负责调度活动,处理数据流,并确保工作流按照预期运行。 10. **自定义活动**:除了使用内置活动外,开发者还可以创建自定义活动,...

    非常好的工作流学习例子,Asp.net工作流(WF+LINQ)实现

    这个例子以一个报销流程为例,从员工(staff)发起报销流程开始,提交给经理...是学习微软WF工作流的一个好例子! 数据库在文件夹里,直接还原即可,不用附加。 ps:有同样喜欢研究工作流的朋友可以+10007354共同进步!

    WPF+WF+Linq 工作流的例子

    在"**WPF+WF+Linq 工作流的例子**"中,这三者被结合起来创建一个功能丰富的应用程序,可能涉及以下方面: 1. **工作流设计**:WF被用来设计和实现业务流程。开发者可以利用WF提供的活动库,通过组合不同的活动来...

    一个.net WF的纯Web工作流设计器,能生成xoml

    本项目提供的是一款基于Web的.NET WF工作流设计器,能够帮助用户在Web环境中设计工作流,并生成XOML文件。 XOML(eXtensible Object Markup Language)是.NET WF中用于存储工作流定义的XML格式。它描述了工作流中的...

    WF完整工作流实例(源码)

    在描述中提到的"ExternalDataExchangeService完整工作流实例(源码)",意味着我们有完整的代码示例,可以深入理解如何在实际项目中使用这个服务。这包括如何配置、启动和使用ExternalDataExchangeService,以及如何...

Global site tag (gtag.js) - Google Analytics