工作流学习过程-持久化服务

工作流系统中有很大一部分需要和人进行交互,有的时候需要很长的时间,所以我们不可能让工作流实例一直保存在内存当中,这就需要进行持久化操作。
工作流的持久化就是保存工作流的某些状态信息到持久化存储里,比如sql数据库,文件中,一旦被保存到持久化存储里了,工作流就可以从内存中移除掉,在需要的时候在进行装载。

持久化服务是WF中核心服务之一,WF框架提供一个标准的持久化服务SqlWorkflowPersistenceService,利用它可以将工作流状态信息存放在Sql Server数据库中,
你也可以自己实现持久化服务,你必须继承自WorkflowPersistenceService这个类,自定义的持久化服务可以把数据存储在二进制文件,xml,其他关系型数据库中等等,
但是一个工作流实例一次只能使用一个持久化服务。

一旦你将持久化服务加载到工作流引擎中,你就不需要手动去干涉了,他会自动的完成相应的操作。在以下状态的时候,工作流会被持久化。

1. idle的时候(如等待外部事件,使用DelayActivity)。

2. 工作流完成或终止。

3. 当TransactionScopeActivity完成的时候。

4. 当CompensatableSequenceActivity完成的时候。

5. 当一个装饰有PersistOnCloseAttribute的自定义活动完成的时候。

6. 当你手动的去调用Unload或TryUnload方法的时候。

如果你使用DelayActivity的时候,持久化服务也会存储DelayActivity的过期时间,并且持久化服务会定期检查是否过期,以准备从新恢复工作流状态,
SqlWorkflowPersistenceService有一个LoadingInterval属性可以设置获取加载间隔的长度。

有的时候当工作流变成idle的时候,你也可以选择不进行持久化存储,这种情况适合当你等待的外部事件比较频繁,而且事件很快就被接收的时候,
因为这个时候如果你在进行持久化存储,你花在卸载和装载上时间会更多,还不如不进行持久化存储呢。

下面我们完成一个例子来说如何使用SqlWorkflowPersistenceService:

1.首先我们需要建立我们的持久化数据库,WF已提供了响应sql脚本,位置如下:

[WindowsFolder]\Microsoft.Net\Framework\v3.0\Windows Workflow Foundation\SQL\[language].[windows]这里面有SqlPersistenceService_Schema.sql
和SqlPersistenceService_Logic.sql两个文件用来生成持久化数据库.

创建好的持久化数据库里包含两张表, InstanceState和 CompletedScope,InstanceState表中记录未完成事例的运行状态,CompletedScope表记录当工做流使用事务的支持。

public partial class Persistencecs : Form
{
private WorkflowRuntimeManager workflowManager;
private WorkflowPersistenceService persistence;
private PersistenceService persistenceService;
private Dictionary<Guid, Workflow> workflows = new Dictionary<Guid, Workflow>();
private Workflow selectedWorkflow;
public Persistencecs()
{
InitializeComponent();
}

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
workflowManager
= new WorkflowRuntimeManager(new WorkflowRuntime());
AddServices(workflowManager.WorkflowRuntime);

workflowManager.WorkflowRuntime.WorkflowCreated
+= new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowCreated);
workflowManager.WorkflowRuntime.WorkflowCompleted
+= new EventHandler<WorkflowCompletedEventArgs>(WorkflowRuntime_WorkflowCompleted);
workflowManager.WorkflowRuntime.WorkflowPersisted
+= new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowPersisted);
workflowManager.WorkflowRuntime.WorkflowUnloaded
+= new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowUnloaded);
workflowManager.WorkflowRuntime.WorkflowLoaded
+= new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowLoaded);
workflowManager.WorkflowRuntime.WorkflowIdled
+= new EventHandler<WorkflowEventArgs>(WorkflowRuntime_WorkflowIdled);

//initially disable these buttons until a workflow
//is selected in the data grid view
btnContinue.Enabled = false;
btnStop.Enabled
= false;

//start the runtime prior to checking for any
//existing workflows that have been persisted
workflowManager.WorkflowRuntime.StartRuntime();

//load information about any workflows that
//have been persisted
RetrieveExistingWorkflows();
}

protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
//cleanup the workflow runtime
if (workflowManager != null)
{
workflowManager.Dispose();
}
}

void WorkflowRuntime_WorkflowCreated(object sender,WorkflowEventArgs e)
{
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Created");
}

void WorkflowRuntime_WorkflowIdled(object sender,WorkflowEventArgs e)
{
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Idled");
}

void WorkflowRuntime_WorkflowLoaded(object sender,WorkflowEventArgs e)
{
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Loaded");
}

void WorkflowRuntime_WorkflowUnloaded(object sender,WorkflowEventArgs e)
{
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Unloaded");
}

void WorkflowRuntime_WorkflowPersisted(object sender,WorkflowEventArgs e)
{
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Persisted");
}

void WorkflowRuntime_WorkflowCompleted(object sender,WorkflowCompletedEventArgs e)
{
UpdateCompletedWorkflow(e.WorkflowInstance.InstanceId);
UpdateDisplay(e.WorkflowInstance.InstanceId,
"Completed");
}

private void RetrieveExistingWorkflows()
{
workflows.Clear();
//retrieve a list of workflows that have been persisted


foreach (SqlPersistenceWorkflowInstanceDescription workflowDesc in ((SqlWorkflowPersistenceService)persistence).GetAllWorkflows())
{
Workflow workflow
= new Workflow();
workflow.InstanceId
= workflowDesc.WorkflowInstanceId;
workflow.StatusMessage
= "Unloaded";
workflows.Add(workflow.InstanceId, workflow);
}
if (workflows.Count > 0)
{
RefreshData();
}
}

private void AddServices(WorkflowRuntime workflowRuntime)
{
String connStringPersistence
= String.Format("Initial Catalog={0};Data Source={1};Integrated Security={2};", "c6ps", @".", "SSPI");
persistence
= new SqlWorkflowPersistenceService(connStringPersistence, true, new TimeSpan(0, 2, 0), new TimeSpan(0, 0, 5));
workflowRuntime.AddService(persistence);

//add the external data exchange service to the runtime
ExternalDataExchangeService exchangeService = new ExternalDataExchangeService();
workflowRuntime.AddService(exchangeService);

//add our local service
persistenceService = new PersistenceService();
exchangeService.AddService(persistenceService);
}

private delegate void UpdateDelegate();

/// <summary>
/// Update the status message for a workflow
/// </summary>
/// <param name="instanceId"></param>
/// <param name="statusMessage"></param>
private void UpdateDisplay(Guid instanceId, String statusMessage)
{
UpdateDelegate theDelegate
= delegate()
{
Workflow workflow
= GetWorkflow(instanceId);
workflow.StatusMessage
= statusMessage;
RefreshData();
//slow things down so you can see the status changes
System.Threading.Thread.Sleep(1000);
};

//execute the anonymous delegate on the UI thread
this.Invoke(theDelegate);
}

private Workflow GetWorkflow(Guid instanceId)
{
Workflow result
= null;
if (workflows.ContainsKey(instanceId))
{
result
= workflows[instanceId];
}
else
{
//create a new instance
result = new Workflow();
result.InstanceId
= instanceId;
workflows.Add(result.InstanceId, result);
}
return result;
}

private void RefreshData()
{
//setup binding for DataGridView
BindingSource source = new BindingSource();
dataGridView1.DataSource
= source;
source.DataSource
= workflows.Values;

dataGridView1.Columns[
0].MinimumWidth = 220;
dataGridView1.Columns[
1].MinimumWidth = 80;
dataGridView1.Columns[
2].MinimumWidth = 30;

dataGridView1.Refresh();
}

private void UpdateCompletedWorkflow(Guid instanceId)
{
UpdateDelegate theDelegate
= delegate()
{
Workflow workflow
= GetWorkflow(instanceId);
workflow.IsCompleted
= true;
};

//execute the anonymous delegate on the UI thread
this.Invoke(theDelegate);
}

private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
//save the selected workflow instance
if (dataGridView1.SelectedRows.Count > 0)
{
DataGridViewRow selectedRow
= dataGridView1.SelectedRows[0];
selectedWorkflow
= selectedRow.DataBoundItem as Workflow;
SetButtonState();
}
}

private void SetButtonState()
{
if (selectedWorkflow != null)
{
btnContinue.Enabled
= !(selectedWorkflow.IsCompleted);
btnStop.Enabled
= !(selectedWorkflow.IsCompleted);
}
else
{
btnContinue.Enabled
= false;
btnStop.Enabled
= false;
}
}

#region 按钮事件处理
private void btnCreate_Click(object sender, EventArgs e)
{
workflowManager.StartWorkflow(
typeof(PersistenceWorkflow), null);
}


private void btnContinue_Click(object sender, EventArgs e)
{
if (selectedWorkflow != null)
{
persistenceService.OnContinueReceived(
new ExternalDataEventArgs(selectedWorkflow.InstanceId));
}
}

private void btnStop_Click(object sender, EventArgs e)
{
if (selectedWorkflow != null)
{
persistenceService.OnStopReceived(
new ExternalDataEventArgs(selectedWorkflow.InstanceId));
}
}
#endregion
}

public class Workflow
{
private Guid instanceId = Guid.Empty;
private String statusMessage = String.Empty;
private Boolean isCompleted;

public Guid InstanceId
{
get { return instanceId; }
set { instanceId = value; }
}

public String StatusMessage
{
get { return statusMessage; }
set { statusMessage = value; }
}

public Boolean IsCompleted
{
get { return isCompleted; }
set { isCompleted = value; }
}
}

 

posted on 2010-10-29 11:11  gotolovo  阅读(499)  评论(0编辑  收藏  举报