[置顶]坚持学习WF文章索引
WF 提供的通信模型是构建于队列系统的基础之上,我们可以使用自定义活动来注册以接收关于队列的消息,而宿主应用程序中的服务则发送关于队列的消息。自定义活动可以使用此模型来处理外部事件,也可以传递异步活动执行的完成。这样,您的活动可以先执行到某一点,然后等待激发因素的到来以便继续执行。下图描述了宿主应用程序中的代码与工作流中的代码(或活动)之间的通信模型。
下面这张图是WF类库中和队列相关的三个类:
为了使自定义活动能够侦听消息是否到达某个队列,我们通常有以下步骤:
1.使用WorkflowQueuingService 创建工作流队列,该类还提供了创建、查找或删除工作流队列所需的方法。一般我们会在自定义活动的 Initialize 或 Execute 方法中来实现。
2.自定义活动必须注册才能接收到这些通知,方法是在工作流队列自身中注册 QueueItemAvailable 事件。您可以使用 RegisterForQueueItemAvailable 方法为 QueueItemAvailable 事件注册一个订户。QueueItemAvailable事件用于通知订户项已经传送(以异步方式)至此 WorkflowQueue。在确保队列存在并注册事件后,当队列中有可用项目时,您的活动会得到通知,之后,您可以从队列中取出该项目并对其进行处理。
3.我们自定义活动要能够充当事件接收器的活动(如 HandleExternalEvent 活动),您还需要实现 IEventActivity 接口。如果您的活动要侦听事件,则此接口用于定义该活动的主要职责:
public interface IEventActivity
{
void Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler);
void Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler);
IComparable QueueName { get; }
}
WF中所有的通信的活动都实现了这个接口。
QueueName 属性必须返回 IComparable 值,消息加入队列时,它可以唯一地标识您的活动。对于用于将消息加入队列以通知工作流运行时的代码,也需要使用这同一个队列名。
通过此接口,能够命令活动在其执行前订阅事件并让活动知道何时取消订阅。在订阅和取消订阅方法中,该活动负责确保使用 QueueName 来创建队列并在处理结束时删除队列。此外,这也为您的活动能够向任何本地服务注册信息提供了机会,这些本地服务将代表活动来执行逻辑并通过将消息加入队列予以响应。
本地服务是您定义并从主机添加到工作流运行时的一个类,它可以被您的宿主代码、工作流或您的活动所利用。只要宿主应用程序处于运行状态,本地服务就能够维护事件处理程序或其他侦听程序,从而可通过将消息加入队列来确保相应的数据到达工作流。您传递给本地服务的信息应包括队列名和工作流实例 ID 的相关信息,以及该服务发起工作或向您的活动返回结果时所需的任何信息。
1.下面我们先来实现一个这样的自定义活动,利用该活动得到对列中的信息,然后在将该信息发送给宿主程序代码如下:
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Collections.Generic;
namespace CaryQueue
{
[Designer(typeof(SequentialActivityDesigner),typeof(IDesigner))]
public partial class RequestResponseData: SequenceActivity,IActivityEventListener<QueueEventArgs>,IEventActivity
{
public RequestResponseData()
{
InitializeComponent();
}
Properties#region Properties
public static DependencyProperty OutputValuesProperty = System.Workflow.ComponentModel.DependencyProperty.Register("OutputValues", typeof(Dictionary<string, string>), typeof(RequestResponseData));
[Description("The values to be sent back to the host")]
[Category("Data")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Dictionary<string, string> OutputValues
{
get
{
return ((Dictionary<string, string>)(base.GetValue(RequestResponseData.OutputValuesProperty)));
}
set
{
base.SetValue(RequestResponseData.OutputValuesProperty, value);
}
}
public static DependencyProperty InputValuesProperty = System.Workflow.ComponentModel.DependencyProperty.Register("InputValues", typeof(Dictionary<string, string>), typeof(RequestResponseData));
[Description("The data sent to the activity")]
[Category("Data")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Dictionary<string, string> InputValues
{
get
{
return ((Dictionary<string, string>)(base.GetValue(RequestResponseData.InputValuesProperty)));
}
set
{
base.SetValue(RequestResponseData.InputValuesProperty, value);
}
}
#endregion
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (ProcessMessage(GetQueue(executionContext, QueueName)))
{
//let the base class run the children, and return status
return base.Execute(executionContext);
}
//if no items are there, then subscribe to get notified when they arrive
Subscribe(executionContext, this);
return ActivityExecutionStatus.Executing;
}
IEvent and IActivityListener#region IEvent and IActivityListener
[Browsable(false)]
public IComparable QueueName
{
get { return "CaryQueue"; }
}
public void Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
{
WorkflowQueue queue = parentContext.GetService<WorkflowQueuingService>().CreateWorkflowQueue(QueueName, false);
queue.RegisterForQueueItemAvailable(parentEventHandler);
}
public void Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
{
WorkflowQueue q = GetQueue(parentContext, QueueName);
if (q != null)
{
q.UnregisterForQueueItemAvailable(parentEventHandler);
parentContext.GetService<WorkflowQueuingService>().DeleteWorkflowQueue(QueueName);
}
}
public void OnEvent(object sender, QueueEventArgs e)
{
ActivityExecutionContext ctx = sender as ActivityExecutionContext;
if (ProcessMessage(GetQueue(ctx, e.QueueName)))
{
if (base.Execute(ctx) == ActivityExecutionStatus.Closed)
ctx.CloseActivity();
}
}
#endregion
private WorkflowQueue GetQueue(ActivityExecutionContext context, IComparable queueName)
{
WorkflowQueuingService qService = context.GetService<WorkflowQueuingService>();
if (qService != null && qService.Exists(queueName))
return qService.GetWorkflowQueue(queueName);
else
return null;
}
private bool ProcessMessage(WorkflowQueue queue)
{
if (queue == null || queue.Count == 0)
return false;
MessageHelper msg = queue.Peek() as MessageHelper;
if (msg != null && msg.InputValues != null)
{
InputValues = msg.InputValues;
Console.WriteLine("Request:"+msg.InputValues["inputvalueone"]);
Console.WriteLine("Request:" + msg.InputValues["inputvaluetwo"]);
return true;
}
return false;
}
/**//// <summary>
/// Called when the base class completes executing the
/// child activities. Here we know all the children are complete.
/// </summary>
/// <param name="executionContext"></param>
protected override void OnSequenceComplete(ActivityExecutionContext executionContext)
{
//pull the message from the queue and send the
//response back to the host, signalling we are done.
WorkflowQueue q = executionContext.GetService<WorkflowQueuingService>().GetWorkflowQueue(QueueName);
MessageHelper msg = q.Dequeue() as MessageHelper;
msg.SendResponse(OutputValues);
//clean up, we
发表评论
-
平淡的2007
2007-12-24 08:04 817早上起来,送女朋友去公交车站,然后回来赶紧打开电脑,先 ... -
DreamSpark发布,高校学生免费使用Visual Studio 2008 Professional Edition 等微软软件
2008-02-20 13:23 1415今天上网无意中搜索到学生可以免费使用VS2008专业版,后来又 ... -
坚持学习WF(1):从HelloWorld开始
2008-04-04 16:30 892[置顶]坚持学习WF文章索 ... -
坚持学习WF(2):WF创作模式和设计时工具
2008-04-05 17:19 639[置顶]坚持学习WF文章索 ... -
坚持学习WF(3):WF框架概览
2008-04-08 07:27 783[置顶]坚持学习WF文章索 ... -
坚持学习WF(4):活动(Activity)和依赖属性(DependencyProperty)
2008-04-12 00:01 1148[置顶]坚持学习WF文章索引 活动(Activity) 活动 ... -
坚持学习WF(5):自定义活动(CustomActivity)
2008-04-13 15:25 929当WF提供的标准活动不能满足我们的需求的时候,我们就需要定义自 ... -
MOSS点滴(1):如何开发和部署feature
2008-04-16 21:35 836Features 是MOSS 2007以开箱即用的一套新功能, ... -
MOSS点滴(2):自定义Application Page
2008-04-19 20:07 844在MOSS中后台管理的页面都是Application Pag ... -
坚持学习WF(6):开发可复用的宿主程序
2008-04-21 21:45 695我们之前写工作流宿主 ... -
MOSS点滴(3):说说MOSS中的母版页
2008-04-25 21:15 1188MOSS中有两种页面:Site P ... -
MOSS点滴(4):实现Form认证
2008-04-29 21:12 705本文主要参考了网上的一些文章,但有些文章有些地方说的不是很明确 ... -
坚持学习WF(7):流程控制(Flow Control)
2008-04-30 18:10 839本文主要说说WF中和流 ... -
坚持学习WF(8):本地服务之调用外部方法
2008-05-09 08:17 761WF提供了一组核心服务 ... -
MOSS中的WebPart开发
2008-05-10 13:53 1060由于在asp.net1.1的时候asp.net中还没有webp ... -
坚持学习WF(9):本地服务之事件处理
2008-05-28 07:49 800[置顶]坚持学习WF文章索引 一:先来介绍两个活动 Even ... -
坚持学习WF(10):在工作流中使用关联
2008-06-01 13:03 692[置顶]坚持学习WF文章索 ... -
MOSS中创建自定义内容类型
2008-06-12 20:23 1107一:简要介绍 某类内容 ... -
.NET中IDisposable接口的基本使用
2008-06-15 12:01 950首先来看MSDN中关于这个接口的说明: [ComVisible ... -
坚持学习WF(12):使用EventHandlingScopeActivity活动
2008-06-18 22:46 684[置顶]坚持学习WF文章索引 EventHandlingSco ...
相关推荐
坚持学习WF(11):工作流通信与队列 WF 提供的通信模型是构建于队列系统的基础之上,我们可以使用自定义活动来注册以接收关于队列的消息,而宿主应用程序中的服务则发送关于队列的消息。自定义活动可以使用此模型来...
坚持学习WF(11):工作流通信与队列 WF 提供的通信模型是构建于队列系统的基础之上,我们可以使用自定义活动来注册以接收关于队列的消息,而宿主应用程序中的服务则发送关于队列的消息。自定义活动可以使用此模型来...
"坚持学习WF(11)工作流通信与队列"关注WF如何与其他组件或服务进行通信,可能包括使用队列进行异步通信的场景。 "坚持学习WF(12)使用EventHandlingScopeActivity活动"更进一步,专门讲解EventHandlingScopeActivity...
将WCF工作流服务与服务总线队列集成,可以创建高效、可扩展的应用系统。下面将详细阐述这一集成过程中的主要知识点。 1. **WCF工作流服务**:WCF WorkFlow Service(WF)是.NET Framework的一部分,允许开发人员...
5. **工作流服务**:使用WF创建WCF服务,结合了流程管理和分布式通信的能力。 Windows Communication Foundation(WCF)是.NET Framework的另一重要组件,用于构建高度可配置的、安全的、可靠的、可扩展的分布式...
6. **工作流服务:** 将WF与WCF结合,创建基于工作流的服务。 **通过WCF_WF_Samples.exe这个压缩包,开发者可以下载并运行这些官方示例,逐步学习和实践WCF和WF的用法。每个示例通常会包含完整的代码、详细的文档和...
- **增强的工作流设计器**: .NET 3.5 中的 WF 引入了一个更加直观且功能强大的工作流设计器,使得开发者可以更轻松地构建复杂的流程图。 - **更好的性能优化**: 相较于之前的版本,.NET 3.5 中的 WF 在性能方面有了...
4. WF工作流:学习工作流的生命周期,包括设计、实例化、执行和跟踪。理解活动、工作流持久化以及如何将工作流集成到实际应用中。 5. Linq和linq-to-sql:学习如何使用Linq进行数据查询,以及如何利用linq-to-sql将...
Windows Workflow Foundation (WF)则是.NET Framework中的工作流引擎,它允许开发者以模型驱动的方式来实现业务流程。WF提供了一套强大的工具和技术,可以创建、执行和管理复杂的业务流程,包括顺序流程、状态机流程...
通常,这样的图会展示各个组件之间的关系,包括WCF服务、WF工作流逻辑以及Silverlight客户端如何相互作用。可能包括数据流、服务接口、工作流状态转换以及用户界面交互等方面的设计。 在学习和实践中,了解如何利用...
5. WF(Windows Workflow Foundation):WF为.NET Framework提供工作流支持,允许开发者在应用程序中实现复杂的业务流程。WF定义了工作流的生命周期,包括设计、执行、暂停、恢复和终止等状态。通过WF,开发者可以...
WF与.NET 4.5的集成使得工作流的创建和管理变得更加简单。 总的来说,这本书全面覆盖了.NET开发的关键技术,无论是对于初学者还是经验丰富的开发者,都能从中获益匪浅。通过学习书中的实例和代码,读者将能够熟练...
- 工作流设计与实现 - 活动与状态机 - 故障恢复与事务 **章节27:本地化** - **知识点**: - 多语言支持 - 资源文件与字符串资源 - 格式化与排序 - 文化敏感度 **章节28:COM 互操作** - **知识点**: -...
- **实现工作流**: 如何使用WF实现复杂的工作流逻辑。 - **本地化** (第27章): - **国际化与本地化**: 国际化(Internationalization)与本地化(Localization)的区别。 - **资源文件**: 如何使用资源文件进行本地...
- **AppFabric工作流管理服务**:工作流服务与WF集成,使得业务流程能够被定义、执行和监控,增强了业务逻辑的灵活性。 **数据存储**:AppFabric使用内存缓存来提高数据访问速度,同时也支持将数据持久化到数据库中...
- **集成优势:** 通过AppFabric,WCF服务可以轻松地与其他WF工作流或其他组件集成,从而构建出高度集成和灵活的分布式系统。 **4. 部署与托管策略** - **缓存服务:** AppFabric提供了一个高性能的分布式内存缓存...
- 深入研究高级主题,如消息队列、工作流服务(WF)和持久性会话。 在22155448295.pdf文档中,你可能会找到关于这些知识点的详细讲解,包括实例代码、配置示例和最佳实践。通过深入学习和实践,你将能够熟练掌握WCF...
2. **工作流与WCF**:讲解如何将WCF与Windows Workflow Foundation集成,实现流程驱动的应用。 3. **消息队列与WF集成**:探讨WCF如何与MSMQ结合,实现异步处理和解耦。 4. **服务性能优化**:分析WCF服务性能瓶颈,...