net的工作流 设计(WF)大家用的多吗,这个有什么

¥详询¥详询
上课(咨询)地址:北京市海淀区学院南路55号中软大厦
课程编号 DEV_DotNet_002&难度级别 中
课程介绍&&&&WF作为Visual Studio 2008的组成部分, 为开发人员进行基于商业流程的开发提供了一组工具与运行时引擎。在本课程中,你将学习使用WF进行Web应用和Windows应用的开发。你也将学习如何在工作流运行时与其宿主程序之间进行数据的交互,构建自定义WF活动,为WF提供持久化和跟踪服务。适合对象
NET开发人员,准备应用.NET WF设计、开发商业流程应用的人员
对网络有基本的了解和基本的操作经验
*好参加过MCSE的培训和学习
3天(18学时)课程大纲
熟悉.NET 工作流引擎
在Web应用和Windows应用中结合运用WF
运用WF构建业务流程
客服时间:早上9点~下午6点,其他时间请在线预约报名或留言,谢谢!
上一个课程:
下一个课程:
联系电话:
所在区域:
学习内容:
我们将对您的信息严格保密!
他们都在学
人气学校推荐温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
//创建活动实例
StateMachineWorkFlow context =
new StateMachineWorkFlow();
//创建单实例工作流宿主
WorkflowApplication application =
new WorkflowApplication(context);
application.Run();
Console.ReadLine();
得到如下结果:
阅读(4063)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'WF4.5 状态机使用WorkflowApplication 创建简单的工作流(一)',
blogAbstract:'研究了WF4 看了微软的很多官方列子,发现只有状态机能最方便的实现公司业务。\r\n其他工作流的列子里面在业务数据库里,还需要建立很多工作流的信息,如状态等。以下是使用笔记:\r\n创建简单的状态机工作流:\r\n\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n&\r\n在活动里新建状态机\r\n\r\n在init里添加WriteLine输出',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:3,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}WF4.0实战(十四):ASP.NET结合WF4.0完整示例
WF4.0实战(十四):ASP.NET结合WF4.0完整示例
有网友问如何在web中使用WF。今天我将实现一个完整的示例。这个示例将包括WF4.0的大部分知识点。包括:
1、持久化服务
2、跟踪服务
3、自定义扩展
4、WCF Workflow Service
5、WorkflowServiceHost
6、使用Interop活动去调用WF3.0工作流程
我先描述一下这个示例的功能,然后演示一下这个示例的功能,然后进一步的说明如何去实现。
有网友问如何在web中使用WF。今天我将实现一个完整的示例。这个示例将包括WF4.0的大部分知识点。包括:
1、持久化服务
2、跟踪服务
3、自定义扩展
4、WCF Workflow Service
5、WorkflowServiceHost
6、使用Interop活动去调用WF3.0工作流程
我先描述一下这个示例的功能,然后演示一下这个示例的功能,然后进一步的说明如何去实现。
这个示例是一个任务队列,这个示例在客户端有两个aspx页面。一个是用于用户输入请求的页面,这个请求会根据你选择的分类将这个任务分入到不同的任务队列。第二个页面用于处理这些请求。这些不同分类的队列有两种处理方式,没一个队列对应一种处理方式,一种是大家熟知的先进先出的方式。每次都是处理最先提交的请求,程序自动迁出最老的任务给你处理,第二种是,你选择这个任务队列,程序就会显示这个队列所有的任务,然后你选择一个任务进行处理。
这个示例中一定有四个任务队列:Product,Service,Marketing,General。这些任务队列的处理方式,你可以自己设置。当你提交一个请求之后,程序会根据的你在第一个页面上选择的分类将这个请求归入不同的队列。在再第二个页面进行处理。第二个页面的处理方式有三种:
第一种:将这个任务指定到另外一个任务队列中
第二种:不指定给另外一个处理队列,直接处理,流程结束
第三种:取消处理,将从任务队列中取出的任务归还回去
当你采用第一种方式处理的时候。就将这个任务规划到另外一个队列当中。此时,你需要在另外的这个队列中将任务迁出然后进行处理,处理方式也是以上三种。如果你选择第二种,流程完成。
这个例子有点类似工作流中的加签流程。你可以无限的加签。
以上是简单的描述示例的功能,下面我将用截图的方式展示一下这个示例:
登录界面:
点击导航条上的Submit,在Category下拉框中选择一项,填写Comments,点击提交,如下图:
流程启动成功,显示Guid,如下图:
在任务处理页面上,将多出一笔任务;
上面已经有三个任务队列存在任务了。任务队列General有2笔任务待处理。QC的意思是是否要进行质检。这三个队列中,Marketing队列处理的方式是列出所有的任务供你选择,其他两个队列的处理方式是先进先出。
点击Marketing的select,将这个队列的三个任务出现在下面的列表中,供你选择其中的一个进行处理:
而点击General的select,直接将最老的任务迁出:
我们将General的任务分配给队列Seivice,如下图:
你会发现Service多出一任务:
演示到此结束。下面我将叙述如何去实现以及用到的WF4.0中的所有的知识点。
设计数据库:
数据库操作使用的是Linq,看下上面这张截图。上面说的4中队列数据存储在SubQueue中,Queue是SubQueue的父表。就存了一条数据。QueueInstance是业务逻辑的主表。QueueTrack用于存储跟踪信息,包括:start、Assign、Route、UnAssign。OperateConfig表用于存放WF3.0活动的配置信息。
你用VS2010打开附件的代码,你会发现:
代码分了五个项目,为了增加代码的重用性。
1、RequestWeb用于是一个Asp.net应用程序,用于提交任务和处理任务。
2、QCPolicy是一个WF3.0的项目,这里我讲解一下。
这个流程用于判断是否需要进行QC,它将用到下面三张数据表进行判断:
WF3.0这个工作流用到了ReviewPolicy活动,如果你对WF3.0也熟悉的话,应该就知道这个用这个活动设置判断的业务规则。WF4.0现在已经不采用这种方式了,设置如下图。
3、TestQC是一个测试项目,测试QCPolicy。
4、UserTasks定义了一些工作流活动。
5、ServiceLayer是一个webservice项目。
持久化服务
持久化服务能将运行的工作流程保存到数据库中。这个例子的持久化服务是在WorkflowServiceHost中配置的。用了微软持久化服务,在数据库中运行SqlWorkflowInstanceStoreSchema.sql和SqlWorkflowInstanceStoreLogic.sql两个脚本,创建持久化数据表。
web.config配置:
&behavior&
&!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --&
&serviceMetadata httpGetEnabled="True"/&
&!-- To receive exception details in faults for debugging purposes, set the value below to true.
Set to false before deployment to avoid disclosing exception information --&
&serviceDebug includeExceptionDetailInFaults="True"/&
&!-- This line configures the persistence service --&
&sqlWorkflowInstanceStore
connectionStringName="Request"
instanceCompletionAction="DeleteAll"
instanceLockedExceptionAction="NoRetry"
instanceEncodingOption="GZip"
hostLockRenewalPeriod="00:00:30" /&
&workflowIdle
timeToUnload="00:00:10"
timeToPersist="00:00:05" /&
&!-- Configure the connection string for the persistence extensions--&
&dbConnection connectionStringName="Request"/&
&persistRequest connectionStringName="Request"/&
&persistQueueInstance connectionStringName="Request"/&
&tracking connectionStringName="Request"/&
&/behavior&
看上面的代码,connectionStringName="Request"指定持久化的连接字符串。
instanceCompletionAction="DeleteAll"指定工作流完成之后删除持久化数据。
自定义扩展。
使用自定义扩展,需要先定义扩展,然后在将这个扩展服务添加到运行时中。这个例子中一共定义了四个自定义扩展。
以最简单的为例:DBConnection。这个用于在工作流内能取到连接字符串。
定义扩展,分三个类:
/*****************************************************/
// The extension class is used to define the behavior
/*****************************************************/
public class DBConnectionExtension : BehaviorExtensionElement
public DBConnectionExtension()
Console.WriteLine("Behavior extension started");
[ConfigurationProperty("connectionStringName", DefaultValue = "",
IsKey = false, IsRequired = true)]
public string ConnectionStringName
get { return (string)this["connectionStringName"]; }
set { this["connectionStringName"] = value; }
public string ConnectionString
ConnectionStringSettingsCollection connectionStrings =
WebConfigurationManager.ConnectionS
if (connectionStrings == null) return null;
string connectionString = null;
if (connectionStrings[ConnectionStringName] != null)
connectionString =
connectionStrings[ConnectionStringName].ConnectionS
if (connectionString == null)
throw new ConfigurationErrorsException
("Connection string is required");
return connectionS
public override Type BehaviorType
get { return typeof(DBConnectionBehavior); }
protected override object CreateBehavior()
return new DBConnectionBehavior(ConnectionString);
/*****************************************************/
// The behavior class is used to create an extension
// for each new instance
/*****************************************************/
public class DBConnectionBehavior : IServiceBehavior
string _connectionS
public DBConnectionBehavior(string connectionString)
this._connectionString = connectionS
public virtual void ApplyDispatchBehavior
(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
WorkflowServiceHost workflowServiceHost
= serviceHostBase as WorkflowServiceH
if (null != workflowServiceHost)
string workflowDisplayName
= workflowServiceHost.Activity.DisplayN
workflowServiceHost.WorkflowExtensions.Add(()
=& new DBConnection(_connectionString));
public virtual void AddBindingParameters
(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection&ServiceEndpoint& endpoints,
BindingParameterCollection bindingParameters)
public virtual void Validate
(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
/*****************************************************/
// This is the actual extension class
/*****************************************************/
public class DBConnection
private string _connectionString = "";
public DBConnection(string connectionString)
_connectionString = connectionS
public string ConnectionString { get { return _connectionS } }
在web.config中进行配置来添加扩展:
&extensions&
&behaviorExtensions&
&add name="dbConnection" type="UserTasks.Extensions.DBConnectionExtension, UserTasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /&
&/behaviorExtensions&
&/extensions&
如何使用这个扩展,看下面的例子:
DBConnection ext = context.GetExtension&DBConnection&();
if (ext == null)
throw new InvalidProgramException("No connection string available");
RequestDataContext dc = new RequestDataContext(ext.ConnectionString);
跟踪服务:
跟踪服务其实就是一个自定义的扩展,先看定义也分三个类:
/*****************************************************/
// The extension class is used to define the behavior
/*****************************************************/
public class QueueTrackingExtension : BehaviorExtensionElement
public QueueTrackingExtension()
Console.WriteLine("Behavior extension started");
[ConfigurationProperty("connectionStringName", DefaultValue = "", IsKey = false, IsRequired = true)]
public string ConnectionStringName
get { return (string)this["connectionStringName"]; }
set { this["connectionStringName"] = value; }
public string ConnectionString
ConnectionStringSettingsCollection connectionStrings = WebConfigurationManager.ConnectionS
if (connectionStrings == null) return null;
string connectionString = null;
if (connectionStrings[ConnectionStringName] != null)
connectionString = connectionStrings[ConnectionStringName].ConnectionS
if (connectionString == null)
throw new ConfigurationErrorsException("Connection string is required");
return connectionS
public override Type BehaviorType { get { return typeof(QueueTrackingBehavior); } }
protected override object CreateBehavior() { return new QueueTrackingBehavior(ConnectionString); }
/*****************************************************/
// The behavior class is used to create an exention for
// each new instance
/*****************************************************/
public class QueueTrackingBehavior : IServiceBehavior
string _connectionS
public QueueTrackingBehavior(string connectionString)
this._connectionString = connectionS
public virtual void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceH
if (null != workflowServiceHost)
string workflowDisplayName = workflowServiceHost.Activity.DisplayN
workflowServiceHost.WorkflowExtensions.Add(()
=& new QueueTracking(_connectionString));
public virtual void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection&ServiceEndpoint& endpoints, BindingParameterCollection bindingParameters) { }
public virtual void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
/*****************************************************/
// This is the actual extension class
/*****************************************************/
public class QueueTracking : TrackingParticipant
private string _connectionString = "";
public QueueTracking(string connectionString)
_connectionString = connectionS
protected override void Track(TrackingRecord record, TimeSpan timeout)
CustomTrackingRecord customTrackingRecord =
record as CustomTrackingR
if (customTrackingRecord != null)
if (customTrackingRecord.Name == "Start"
customTrackingRecord.Name == "Route"
customTrackingRecord.Name == "Assign"
customTrackingRecord.Name == "UnAssign" ||
customTrackingRecord.Name == "QC")
QueueTrack t = new QueueTrack();
// Extract all the user data
if ((customTrackingRecord != null) &&
(customTrackingRecord.Data.Count & 0))
foreach (string key in customTrackingRecord.Data.Keys)
switch (key)
case "QueueInstanceKey":
if (customTrackingRecord.Data[key] != null)
t.QueueInstanceKey = (Guid)customTrackingRecord.Data[key];
case "SubQueueID":
if (customTrackingRecord.Data[key] != null)
t.SubQueueID = (int)customTrackingRecord.Data[key];
case "QC":
if (customTrackingRecord.Data[key] != null)
t.QC = (bool)customTrackingRecord.Data[key];
case "OperatorKey":
if (customTrackingRecord.Data[key] != null)
t.OperatorKey = (Guid)customTrackingRecord.Data[key];
if (t.SubQueueID != null && t.QC == null)
t.QC = false;
t.EventType = customTrackingRecord.N
t.EventDate = DateTime.UtcN
// Insert a record into the TrackUser table
UserTasksDataContext dc =
new UserTasksDataContext(_connectionString);
dc.QueueTracks.InsertOnSubmit(t);
dc.SubmitChanges();
web.config中配置:
&add name="tracking" type="UserTasks.Extensions.QueueTrackingExtension, UserTasks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /&
// Add a custom track record
CustomTrackingRecord userRecord = new CustomTrackingRecord("Assign")
{"QueueInstanceKey", qi.QueueInstanceKey},
{"OperatorKey", OperatorKey.Get(context)},
{"SubQueueID", qi.CurrentSubQueueID},
{"QC", qi.QC}
// Emit the custom tracking record
context.Track(userRecord);
看上图,用了一个Pick 与4个PickBranch,每一个PickBranch里面是一个或者多个ReceiveAndSendReply。QuseuStats用于返回每个任务队列的任务数量。
GetRequest用于返回任务列表。LoadRequest用于返回具体的某项任务数据。
主要的逻辑是在Submit中。双击进入Submit,看Submit的第一部分:
上图这部分用于将客户端请求的数据保存到数据库中,并创建一个Queus实例。
这是一个while循环。这样就能无限制的将任务划分到其他任务队列下面。
上图是第三部分。它也在while循环之中。Complete Request对应asp.net应用程序中的处理请求页面的Complete按钮。Unassign Request对应Cancel按钮。Timeout时间设置为5分钟,如果5分钟不处理,就持久化到数据库中。
以上的定义的工作流用到了UserTasks和ServiceLayer中的自定义活动,这些自定义活动都是CodeAcitivity类型的。
以一个自定义活动CreateRequest为例,代码如下:
public sealed class CreateRequest : CodeActivity
public InArgument&string& RequestType { get; set; }
public InArgument&string& UserName { get; set; }
public InArgument&string& UserEmail { get; set; }
public InArgument&string& Comment { get; set; }
public InArgument&Guid& QueueInstanceKey { get; set; }
public InArgument&Guid& RequestKey { get; set; }
protected override void Execute(CodeActivityContext context)
// Get the connection string
DBConnection ext = context.GetExtension&DBConnection&();
if (ext == null)
throw new InvalidProgramException("No connection string available");
RequestDataContext dc = new RequestDataContext(ext.ConnectionString);
// Create and initialize a Request object
Request r = new Request();
r.UserName = UserName.Get(context);
r.UserEmail = UserEmail.Get(context);
r.RequestType = RequestType.Get(context);
r.Comment = Comment.Get(context);
r.CreateDate = DateTime.UtcN
r.RequestKey = RequestKey.Get(context);
r.QueueInstanceKey = QueueInstanceKey.Get(context);
// Insert the Request record
PersistRequest persist = context.GetExtension&PersistRequest&();
persist.AddRequest(r);
总结:这是一个完整的工作流的例子,用到了WF4.0的大部分功能。其他的具体看代码吧,写得很累,有任何问题可以给我留言。
本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive//WFQueueList.html,如需转载请自行联系原作者
用云栖社区APP,舒服~
【云栖快讯】Apache旗下顶级开源盛会 HBasecon Asia 2018将于8月17日在京举行,现场仅600席,免费赠票领取入口&&
文章3106篇
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效...
RDS是一种稳定可靠、可弹性伸缩的在线数据库服务。支持MySQL、SQL Server、Po...
数据库云大使发布你的需求,坐收培训方案
需求发布后3小时内收到供应商响应
每个需求平均有3-5个供应商参与
95%以上的需求得到了圆满解决
所有需求不向客户收取任何费用
立即发布需求
你的位置:
> 课程详情
.NET工作流引擎(WF)开发实践
暂无评价&&&
开课时间:日 09:00 周三 已结束
结束时间:日 17:00 周五
课程时长:18小时
招生进展:
开课地点:北京市
授课讲师:
课程编号:65409
课程分类:
你实际购买的价格
付款时最多可用0淘币抵扣0元现金
购买成功后,系统会给用户帐号返回的现金券
.NET开发人员,准备应用.NET WF设计、开发商业流程应用的人员
WF作为Visual Studio 2008的组成部分, 为开发人员进行基于商业流程的开发提供了一组工具与运行时引擎。在本课程中,你将学习使用WF进行Web应用和Windows应用的开发。你也将学习如何在工作流运行时与其宿主程序之间进行数据的交互,构建自定义WF活动,为WF提供持久化和跟踪服务。
WF作为Visual Studio 2008的组成部分, 为开发人员进行基于商业流程的开发提供了一组工具与运行时引擎。课程大纲:在Web应用和Windows应用中结合运用WF 运用WF构建业务流程
培训师介绍:
资深讲师,Microsoft认证讲师(MCT),微软认证解决方案开发专家(MCSD), 微软认证应用程序开发专家(MCAD)。 丰富的项目开发经验和多年培训经验,主讲SQL Server数据库、Oracle数据库、.Net技术、架构设计、项目管理等课程。在长期的工作和教学中,积累了丰富的实践经验和扎实的理论知识。讲课生动活泼,语言幽默,感染力强,注重理论与实践的结合,善于把自己的实际经验融入到课堂教学中去,受到学员广泛好评。曾为多家企、事业单位提供培训和支持。
本课程名称: .NET工作流引擎(WF)开发实践
查看更多:
热门相关资料
更多相关搜索
讲师动态评分
与同行相比
授课内容与课纲相符0低0%
讲师授课水平0低0%
服务态度0低0%WF工作流_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
你可能喜欢

我要回帖

更多关于 审批工作流 的文章

 

随机推荐