windows workflow foundation在WebApplication中的应用,使用StateMechineWorkflow
2007-06-18 12:16
501 查看
现在的workflow foundation是bate2.2版。比之上一个版本,改变也比较大。
现在的微软提供了很多activty,也有新的在发布,这里是他的老家:http://www.windowsworkflow.net/Default.aspx?tabindex=0&tabid=1
我的这个例子比较简单,和一个老外的代码差不多。
首先,需要做的有三部分
1:要处理的对象,和wrokflow的接口,事件。
2:设计wrokflow
3:作host,驱动workflow的运行。
我的这个例子是一个文档批准的流程:创建文档(草稿状态);确认提交(提交状态);批准(结束状态);拒绝(返回草稿状态)。
按照上边的步骤,开始做
1:添加对象,接口,事件
添加一个Document的对象
添加一个可以和workflow交互的接口
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
IDocumentService
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System;
2
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Collections.Generic;
3
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Text;
4
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Workflow.ComponentModel;
5
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Workflow.Activities;
6
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace StateWorkflowLib.App.DocumentWF
8
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//Serializable for persis
10
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[Serializable]
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public class DocumentEventArgs : ExternalDataEventArgs
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private string _docId;
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public DocumentEventArgs(Guid instanceId, string docId)
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
: base(instanceId)
17
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
_docId = docId;
19
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string DocId
22
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
23
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
get
![](http://www.cnblogs.com/Images/dot.gif)
{ return _docId; }
24
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
set
![](http://www.cnblogs.com/Images/dot.gif)
{ _docId = value; }
25
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
26
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
27
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[ExternalDataExchange]
29
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public interface IDocumentService
30
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
31
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentCreated;
32
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentSubmited;
33
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentApproved;
34
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentRejected;
35
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
36
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
注意 :DocumentEventArgs 要继承自ExternalDataEventArgs;还要可以Serializable。因为这类对象可能需要序列化,存到数据库;
IDocumentService接口是要有ExternalDataExchange属性的,用来做数据交换。
然后定义一个实现
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
DocumentService
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
[Serializable]
2
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class DocumentService:IDocumentService
3
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
4
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentCreatedEvent(DocumentObject doc, Guid instanceId)
5
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
6
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do : ur business logic
7
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// doc.Save();
8
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//raise envent to invoke workflow run
10
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentCreated != null)
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentCreated(null, new DocumentEventArgs(instanceId, doc.ID.ToString()));
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentCreatedEvent(string docId, Guid instanceId)
15
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
17
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do: another logic here
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
19
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentCreated != null)
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentCreated(null, new DocumentEventArgs(instanceId, docId));
21
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
22
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentSubmitedEvent(string docId, Guid instanceId)
24
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
25
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentSubmited != null)
26
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentSubmited(null, new DocumentEventArgs(instanceId, docId));
27
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
28
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentApprovedEvent(string docId, Guid instanceId)
29
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
30
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentApproved != null)
31
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentApproved(null, new DocumentEventArgs(instanceId, docId));
32
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
33
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentRejectedEvent(string docId, Guid instanceId)
34
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
35
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (DocumentRejected != null)
36
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
DocumentRejected(null, new DocumentEventArgs(instanceId, docId));
37
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
38
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentCreated;
40
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentSubmited;
41
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentApproved;
42
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentRejected;
在这个service里面可以写自己的普通的处理代码,然后引发事件,驱动workflow的运转。
注意,需要继承自刚才定义的那个接口
2:配置workflow
这里的配置选用的是xoml的statewrokflow。这样的wrokflow其实定义的是一个文件。
定义的结果如下
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateMachineWorkflowActivity x:Class="StateWorkflowLib.XmlWorkflowExample" InitialStateName="InitState" x:Name="XmlWorkflowExample" DynamicUpdateCondition="{x:Null}" CompletedStateName="ClosedState" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="InitState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForCreate">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleCreateEvent" EventName="DocumentCreated" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToDraftState" TargetStateName="DraftState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="DraftState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForSubmit">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleSubmitEvent" EventName="DocumentSubmited" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToSubmit" TargetStateName="SubmitedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="SubmitedState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForApprovedEvent">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleApprovedEvent" EventName="DocumentApproved" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToClosed" TargetStateName="ClosedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForRejectedEvent">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleRejectedEvent" EventName="DocumentRejected" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToDraft" TargetStateName="DraftState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="ClosedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateMachineWorkflowActivity>
每一个workflow必须要有一个开始,一个结束状态;
这里定义了4个状态:WaitForCreate,Draft,Sumbmited,Closed。
拿其中一个作为例子,WaitForCreate状态有一个EventDrivenActivity,等待事件驱动的一个功能。然后这个里面有一个订阅外部事件的处理HandleExternalEventActivity,订阅的是“DocumentCreated”事件;接收到这个事件之后(可以做很多处理)接着就直接改变了当前工作流的状态到Darft状态。
3:写aspx驱动之
首先,配置webconfig。注意在web里面要使用 <add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
不要使用DefaultWorkflowSchedulerService。需要的话,还要定义SqlWorkflowPersistenceService,用来把工作流保存到数据库中。
然后,启动一个WorkflowRuntime
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
_workflowRuntime = new System.Workflow.Runtime.WorkflowRuntime("WorkflowRuntime");
workflowRuntime.StartRuntime();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
注意,里面的参数是在webconfig中配置的节点的名字(NodeName,而不是name属性)
如果是第一次启动工作流
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
DocumentService docService = WorkflowManager.GlobalDataExchangeService.GetService(typeof(DocumentService)) as DocumentService;
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (docService == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
docService = new DocumentService();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowManager.GlobalDataExchangeService.AddService(docService);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowInstance workflowInstance = WorkflowManager.WorkflowRuntime.CreateWorkflow(typeof(XmlWorkflowExample));
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
workflowInstance.Start();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
page.Session["DocumentWorkflowId"] = workflowInstance.InstanceId;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
WorkflowManager是我自己写的一个类,因为workflow现在的版本未定,总是在变,所以自己写一个接口。
基本意思就是,如果第一次运行,那么就要生成一个docService实例,交给工作流管理,然后生成一个工作流实例。记录下这个实例的Id。
这是一个具体驱动workflow运行的代码
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
Guid instanceId = new Guid(page.Session["DocumentWorkflowId"].ToString());
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
switch (eventName)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "CreateDocument":
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do logic here
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//DocumentObject docObj = new DocumentObject();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//docService.RaiseDocumentCreatedEvent(docObj, instanceId);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
docService.RaiseDocumentCreatedEvent(docId, instanceId);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowManager.GlobalManualWorkflowSchedulerService.RunWorkflow(instanceId); 这一个可以写在哪一个Button的处理里面了。需要注意的是WorkflowSchedulerService,这里需要手工驱动工作流运转。因为在web环境下,不能使用DefaultWorkflowSchedulerService,不然的话,只要docService.RaiseDocumentCreatedEvent(docId, instanceId)一执行,工作流就直接驱动起来了,不要自己再去RunWorkflow的。
写了不少,但是有点太乱了。
workflow fundation的特点 / 如何将工作流保存到数据库(一个LongRun工作流的话)只能下次再说了。
现在的微软提供了很多activty,也有新的在发布,这里是他的老家:http://www.windowsworkflow.net/Default.aspx?tabindex=0&tabid=1
我的这个例子比较简单,和一个老外的代码差不多。
首先,需要做的有三部分
1:要处理的对象,和wrokflow的接口,事件。
2:设计wrokflow
3:作host,驱动workflow的运行。
我的这个例子是一个文档批准的流程:创建文档(草稿状态);确认提交(提交状态);批准(结束状态);拒绝(返回草稿状态)。
按照上边的步骤,开始做
1:添加对象,接口,事件
添加一个Document的对象
添加一个可以和workflow交互的接口
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
IDocumentService
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System;
2
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Collections.Generic;
3
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Text;
4
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Workflow.ComponentModel;
5
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System.Workflow.Activities;
6
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace StateWorkflowLib.App.DocumentWF
8
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//Serializable for persis
10
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[Serializable]
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public class DocumentEventArgs : ExternalDataEventArgs
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private string _docId;
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public DocumentEventArgs(Guid instanceId, string docId)
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
: base(instanceId)
17
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
_docId = docId;
19
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string DocId
22
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
23
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
get
![](http://www.cnblogs.com/Images/dot.gif)
{ return _docId; }
24
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
set
![](http://www.cnblogs.com/Images/dot.gif)
{ _docId = value; }
25
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
26
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
27
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[ExternalDataExchange]
29
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public interface IDocumentService
30
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
31
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentCreated;
32
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentSubmited;
33
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentApproved;
34
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
event EventHandler<DocumentEventArgs> DocumentRejected;
35
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
36
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
注意 :DocumentEventArgs 要继承自ExternalDataEventArgs;还要可以Serializable。因为这类对象可能需要序列化,存到数据库;
IDocumentService接口是要有ExternalDataExchange属性的,用来做数据交换。
然后定义一个实现
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
DocumentService
1
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
[Serializable]
2
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class DocumentService:IDocumentService
3
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
4
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentCreatedEvent(DocumentObject doc, Guid instanceId)
5
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
6
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do : ur business logic
7
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// doc.Save();
8
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//raise envent to invoke workflow run
10
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentCreated != null)
11
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentCreated(null, new DocumentEventArgs(instanceId, doc.ID.ToString()));
12
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
13
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentCreatedEvent(string docId, Guid instanceId)
15
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
16
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
17
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do: another logic here
18
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
19
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentCreated != null)
20
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentCreated(null, new DocumentEventArgs(instanceId, docId));
21
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
22
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentSubmitedEvent(string docId, Guid instanceId)
24
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
25
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentSubmited != null)
26
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentSubmited(null, new DocumentEventArgs(instanceId, docId));
27
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
28
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentApprovedEvent(string docId, Guid instanceId)
29
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
30
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this.DocumentApproved != null)
31
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.DocumentApproved(null, new DocumentEventArgs(instanceId, docId));
32
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
33
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void RaiseDocumentRejectedEvent(string docId, Guid instanceId)
34
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
35
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (DocumentRejected != null)
36
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
DocumentRejected(null, new DocumentEventArgs(instanceId, docId));
37
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
38
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentCreated;
40
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentSubmited;
41
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentApproved;
42
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public event EventHandler<DocumentEventArgs> DocumentRejected;
在这个service里面可以写自己的普通的处理代码,然后引发事件,驱动workflow的运转。
注意,需要继承自刚才定义的那个接口
2:配置workflow
这里的配置选用的是xoml的statewrokflow。这样的wrokflow其实定义的是一个文件。
定义的结果如下
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateMachineWorkflowActivity x:Class="StateWorkflowLib.XmlWorkflowExample" InitialStateName="InitState" x:Name="XmlWorkflowExample" DynamicUpdateCondition="{x:Null}" CompletedStateName="ClosedState" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="InitState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForCreate">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleCreateEvent" EventName="DocumentCreated" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToDraftState" TargetStateName="DraftState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="DraftState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForSubmit">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleSubmitEvent" EventName="DocumentSubmited" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToSubmit" TargetStateName="SubmitedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="SubmitedState">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForApprovedEvent">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleApprovedEvent" EventName="DocumentApproved" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToClosed" TargetStateName="ClosedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<EventDrivenActivity x:Name="waitForRejectedEvent">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<HandleExternalEventActivity x:Name="handleRejectedEvent" EventName="DocumentRejected" InterfaceType="{x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService}" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<SetStateActivity x:Name="setToDraft" TargetStateName="DraftState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</EventDrivenActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateActivity>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<StateActivity x:Name="ClosedState" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</StateMachineWorkflowActivity>
每一个workflow必须要有一个开始,一个结束状态;
这里定义了4个状态:WaitForCreate,Draft,Sumbmited,Closed。
拿其中一个作为例子,WaitForCreate状态有一个EventDrivenActivity,等待事件驱动的一个功能。然后这个里面有一个订阅外部事件的处理HandleExternalEventActivity,订阅的是“DocumentCreated”事件;接收到这个事件之后(可以做很多处理)接着就直接改变了当前工作流的状态到Darft状态。
3:写aspx驱动之
首先,配置webconfig。注意在web里面要使用 <add type="System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService, System.Workflow.Runtime, Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
不要使用DefaultWorkflowSchedulerService。需要的话,还要定义SqlWorkflowPersistenceService,用来把工作流保存到数据库中。
然后,启动一个WorkflowRuntime
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
_workflowRuntime = new System.Workflow.Runtime.WorkflowRuntime("WorkflowRuntime");
workflowRuntime.StartRuntime();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
注意,里面的参数是在webconfig中配置的节点的名字(NodeName,而不是name属性)
如果是第一次启动工作流
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
DocumentService docService = WorkflowManager.GlobalDataExchangeService.GetService(typeof(DocumentService)) as DocumentService;
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (docService == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
docService = new DocumentService();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowManager.GlobalDataExchangeService.AddService(docService);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowInstance workflowInstance = WorkflowManager.WorkflowRuntime.CreateWorkflow(typeof(XmlWorkflowExample));
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
workflowInstance.Start();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
page.Session["DocumentWorkflowId"] = workflowInstance.InstanceId;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
WorkflowManager是我自己写的一个类,因为workflow现在的版本未定,总是在变,所以自己写一个接口。
基本意思就是,如果第一次运行,那么就要生成一个docService实例,交给工作流管理,然后生成一个工作流实例。记录下这个实例的Id。
这是一个具体驱动workflow运行的代码
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
Guid instanceId = new Guid(page.Session["DocumentWorkflowId"].ToString());
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
switch (eventName)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
case "CreateDocument":
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//to do logic here
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//DocumentObject docObj = new DocumentObject();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//docService.RaiseDocumentCreatedEvent(docObj, instanceId);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
docService.RaiseDocumentCreatedEvent(docId, instanceId);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
WorkflowManager.GlobalManualWorkflowSchedulerService.RunWorkflow(instanceId); 这一个可以写在哪一个Button的处理里面了。需要注意的是WorkflowSchedulerService,这里需要手工驱动工作流运转。因为在web环境下,不能使用DefaultWorkflowSchedulerService,不然的话,只要docService.RaiseDocumentCreatedEvent(docId, instanceId)一执行,工作流就直接驱动起来了,不要自己再去RunWorkflow的。
写了不少,但是有点太乱了。
workflow fundation的特点 / 如何将工作流保存到数据库(一个LongRun工作流的话)只能下次再说了。
相关文章推荐
- windows workflow foundation在WebApplication中的应用,使用StateMechineWorkflow
- Windows Workflow Foundation之旅(八)——使用活动控制流程、在工作流中使用条件
- 跟我一起学Windows Workflow Foundation(5)-----使用activity设计器创建一个整合的定制activity
- Windows Workflow Foundation Web Workflow Approvals Starter Kit
- 跟我一起学Windows Workflow Foundation(3)-----使用If/Else活动,定制活动处理工作流,使用事件传递数据
- 使用Windows WorkFlow Foundation
- Windows Workflow Foundation Web Workflow Approvals Starter Kit
- Windows Workflow Foundation (wwf) 在宿主中使用参数与实例通信 --学习笔记(二)
- Windows WorkFlow Foundation 入门之二(使用WF开发介绍)
- windows下使用批处理发布Web应用到Tomcat并启动Tomcat
- Windows Workflow Foundation Web Workflow Approvals Starter Kit
- Create a Java Web Application using Embedded Tomcat (如何使用Embedded 创建一个基于Tomcat的Web 应用))
- 面向最终用户的Web应用的兼容性设计:为在Windows(XP 2000 98)下屏幕分辨率为1024*768或800*600使用IE浏览器(IE6, IE5)的中国用户设计
- State Machine Workflows in Windows Workflow Foundation
- Windows Workflow Foundation Web Workflow Approvals Starter Kit
- Windows Workflow Foundation Web Workflow Approvals Starter Kit(转)
- Windows Workflow Foundation之旅(八)——使用活动控制流程、在工作流中使用条件
- 跟我一起学Windows Workflow Foundation(3)-----使用If/Else活动,定制活动处理工作流,使用事件传递数据
- Windows Workflow Foundation Web Workflow Approvals Starter Kit
- Windows WorkFlow Foundation 入门之三(在工作流中使用事务)