windows workflow foundation在WebApplication中的应用,使用StateMechineWorkflow

现在的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交互的接口
     
ContractedBlock.gif ExpandedBlockStart.gif IDocumentService
 1None.gifusing System;
 2None.gifusing System.Collections.Generic;
 3None.gifusing System.Text;
 4None.gifusing System.Workflow.ComponentModel;
 5None.gifusing System.Workflow.Activities;
 6None.gif
 7None.gifnamespace StateWorkflowLib.App.DocumentWF
 8ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 9InBlock.gif    //Serializable for persis
10InBlock.gif    [Serializable]
11InBlock.gif    public class DocumentEventArgs : ExternalDataEventArgs
12ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
13InBlock.gif        private string _docId;
14InBlock.gif
15InBlock.gif        public DocumentEventArgs(Guid instanceId, string docId)
16InBlock.gif            : base(instanceId)
17ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
18InBlock.gif            _docId = docId;
19ExpandedSubBlockEnd.gif        }

20InBlock.gif
21InBlock.gif        public string DocId
22ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
23ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn _docId; }
24ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ _docId = value; }
25ExpandedSubBlockEnd.gif        }

26ExpandedSubBlockEnd.gif    }

27InBlock.gif
28InBlock.gif    [ExternalDataExchange]
29InBlock.gif    public interface IDocumentService
30ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
31InBlock.gif        event EventHandler<DocumentEventArgs> DocumentCreated;
32InBlock.gif        event EventHandler<DocumentEventArgs> DocumentSubmited;
33InBlock.gif        event EventHandler<DocumentEventArgs> DocumentApproved;
34InBlock.gif        event EventHandler<DocumentEventArgs> DocumentRejected;
35ExpandedSubBlockEnd.gif    }

36ExpandedBlockEnd.gif}
    注意 :DocumentEventArgs 要继承自ExternalDataEventArgs;还要可以Serializable。因为这类对象可能需要序列化,存到数据库;
             IDocumentService接口是要有ExternalDataExchange属性的,用来做数据交换。
     然后定义一个实现
ContractedBlock.gif ExpandedBlockStart.gif DocumentService
 1None.gif [Serializable]
 2None.gif    public class DocumentService:IDocumentService
 3ExpandedBlockStart.gifContractedBlock.gif    dot.gif{
 4InBlock.gif        public void RaiseDocumentCreatedEvent(DocumentObject doc, Guid instanceId)
 5ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 6InBlock.gif            //to do : ur business logic
 7InBlock.gif            // doc.Save();
 8InBlock.gif
 9InBlock.gif            //raise envent to invoke workflow run
10InBlock.gif            if (this.DocumentCreated != null)
11InBlock.gif                this.DocumentCreated(nullnew DocumentEventArgs(instanceId, doc.ID.ToString()));
12ExpandedSubBlockEnd.gif        }

13InBlock.gif
14InBlock.gif        public void RaiseDocumentCreatedEvent(string docId, Guid instanceId)
15ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
16InBlock.gif            //
17InBlock.gif            //to do: another logic here
18InBlock.gif            //
19InBlock.gif             if (this.DocumentCreated != null)
20InBlock.gif                 this.DocumentCreated(nullnew DocumentEventArgs(instanceId, docId));
21ExpandedSubBlockEnd.gif        }

22InBlock.gif
23InBlock.gif        public void RaiseDocumentSubmitedEvent(string docId, Guid instanceId)
24ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
25InBlock.gif             if (this.DocumentSubmited != null)
26InBlock.gif                this.DocumentSubmited(nullnew DocumentEventArgs(instanceId, docId));
27ExpandedSubBlockEnd.gif        }

28InBlock.gif        public void RaiseDocumentApprovedEvent(string docId, Guid instanceId)
29ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
30InBlock.gif            if (this.DocumentApproved != null)
31InBlock.gif                this.DocumentApproved(nullnew DocumentEventArgs(instanceId, docId));
32ExpandedSubBlockEnd.gif        }

33InBlock.gif        public void RaiseDocumentRejectedEvent(string docId, Guid instanceId)
34ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
35InBlock.gif            if (DocumentRejected != null)
36InBlock.gif                DocumentRejected(nullnew DocumentEventArgs(instanceId, docId));
37ExpandedSubBlockEnd.gif        }

38InBlock.gif 
39InBlock.gif        public event EventHandler<DocumentEventArgs> DocumentCreated;
40InBlock.gif        public event EventHandler<DocumentEventArgs> DocumentSubmited;
41InBlock.gif        public event EventHandler<DocumentEventArgs> DocumentApproved;
42InBlock.gif        public event EventHandler<DocumentEventArgs> DocumentRejected;

    在这个service里面可以写自己的普通的处理代码,然后引发事件,驱动workflow的运转。
    注意,需要继承自刚才定义的那个接口
2:配置workflow
      这里的配置选用的是xoml的statewrokflow。这样的wrokflow其实定义的是一个文件。
     定义的结果如下
    
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 " >
None.gif    
< StateActivity x:Name = " InitState " >
None.gif        
< EventDrivenActivity x:Name = " waitForCreate " >
None.gif            
< HandleExternalEventActivity x:Name = " handleCreateEvent "  EventName = " DocumentCreated "  InterfaceType = " {x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService} "   />
None.gif            
< SetStateActivity x:Name = " setToDraftState "  TargetStateName = " DraftState "   />
None.gif        
</ EventDrivenActivity >
None.gif    
</ StateActivity >
None.gif    
< StateActivity x:Name = " DraftState " >
None.gif        
< EventDrivenActivity x:Name = " waitForSubmit " >
None.gif            
< HandleExternalEventActivity x:Name = " handleSubmitEvent "  EventName = " DocumentSubmited "  InterfaceType = " {x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService} "   />
None.gif            
< SetStateActivity x:Name = " setToSubmit "  TargetStateName = " SubmitedState "   />
None.gif        
</ EventDrivenActivity >
None.gif    
</ StateActivity >
None.gif    
< StateActivity x:Name = " SubmitedState " >
None.gif        
< EventDrivenActivity x:Name = " waitForApprovedEvent " >
None.gif            
< HandleExternalEventActivity x:Name = " handleApprovedEvent "  EventName = " DocumentApproved "  InterfaceType = " {x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService} "   />
None.gif            
< SetStateActivity x:Name = " setToClosed "  TargetStateName = " ClosedState "   />
None.gif        
</ EventDrivenActivity >
None.gif        
< EventDrivenActivity x:Name = " waitForRejectedEvent " >
None.gif            
< HandleExternalEventActivity x:Name = " handleRejectedEvent "  EventName = " DocumentRejected "  InterfaceType = " {x:Type StateWorkflowLib.App.DocumentWF.IDocumentService,TypeName=StateWorkflowLib.App.DocumentWF.IDocumentService} "   />
None.gif            
< SetStateActivity x:Name = " setToDraft "  TargetStateName = " DraftState "   />
None.gif        
</ EventDrivenActivity >
None.gif    
</ StateActivity >
None.gif    
< StateActivity x:Name = " ClosedState "   />
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
None.gif     _workflowRuntime  =   new  System.Workflow.Runtime.WorkflowRuntime( " WorkflowRuntime " );
workflowRuntime.StartRuntime();
None.gif     
    注意,里面的参数是在webconfig中配置的节点的名字(NodeName,而不是name属性)
  
如果是第一次启动工作流
None.gif    DocumentService docService  =  WorkflowManager.GlobalDataExchangeService.GetService( typeof (DocumentService))  as  DocumentService;
None.gif        
if  (docService  ==   null )
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            docService 
= new DocumentService();
InBlock.gif            WorkflowManager.GlobalDataExchangeService.AddService(docService);
InBlock.gif
InBlock.gif            WorkflowInstance workflowInstance 
= WorkflowManager.WorkflowRuntime.CreateWorkflow(typeof(XmlWorkflowExample));
InBlock.gif            workflowInstance.Start();
InBlock.gif            page.Session[
"DocumentWorkflowId"= workflowInstance.InstanceId;
InBlock.gif
ExpandedBlockEnd.gif        }

WorkflowManager是我自己写的一个类,因为workflow现在的版本未定,总是在变,所以自己写一个接口。
基本意思就是,如果第一次运行,那么就要生成一个docService实例,交给工作流管理,然后生成一个工作流实例。记录下这个实例的Id。
 这是一个具体驱动workflow运行的代码
None.gif    Guid instanceId  =   new  Guid(page.Session[ " DocumentWorkflowId " ].ToString());
None.gif        
switch  (eventName)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            
case "CreateDocument":
InBlock.gif                
//to do logic here
InBlock.gif                
//DocumentObject docObj = new DocumentObject();
InBlock.gif                
//docService.RaiseDocumentCreatedEvent(docObj, instanceId);
InBlock.gif                
//
InBlock.gif
                docService.RaiseDocumentCreatedEvent(docId, instanceId);
InBlock.gif                WorkflowManager.GlobalManualWorkflowSchedulerService.RunWorkflow(instanceId);
    这一个可以写在哪一个Button的处理里面了。需要注意的是WorkflowSchedulerService,这里需要手工驱动工作流运转。因为在web环境下,不能使用DefaultWorkflowSchedulerService,不然的话,只要docService.RaiseDocumentCreatedEvent(docId, instanceId)一执行,工作流就直接驱动起来了,不要自己再去RunWorkflow的。


写了不少,但是有点太乱了。

workflow fundation的特点 / 如何将工作流保存到数据库(一个LongRun工作流的话)只能下次再说了。

转载于:https://www.cnblogs.com/wayne-ivan/archive/2007/09/06/883704.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值