最近的一个项目里,使用了CSLA框架。CSLA有一个基本的设计原理,就是充分利用数据代理(同时规定BussinessObject is serializable),这个代理保证了csla的5层构架对各种物理部署构架的适应性。从它的框架可以看见,它的数据操作都是在DataPotol中定义,所以我们如果要在csla中使用工作流,切不可违反它的这一规定。
DataPortalClient.IDataPortalProxy proxy;
proxy = GetDataPortalProxy(method.RunLocal);
普通的WebApplication的做法是在globel文件里加载工作流,如下所示:
protected void Application_Start(object sender, EventArgs e)
{
WorkflowRuntime workflowRuntime = new WorkflowRuntime(ConfigurationParameters.WorkflowName);
workflowRuntime.AddService(new SqlWorkflowPersistenceService(ConfigurationParameters.WorkflowDBConn));
workflowRuntime.AddService(new SqlTrackingService(ConfigurationParameters.WorkflowDBConn));
ExternalDataExchangeService dataService = new ExternalDataExchangeService();
workflowRuntime.AddService(dataService);
WorkflowServices service = new WorkflowServices();
dataService.AddService(service);
workflowRuntime.StartRuntime();
Application[ConfigurationParameters.WorkflowName] = workflowRuntime;
}
在CSLA框架里,我们这样做:建立一个Command对象:
![]()
Code [Serializable]
public class WorkflowCommand : CommandBase
{
private static WorkflowRuntime m_workflowRuntime;
private static ExternalDataExchangeService m_exchangeService;
private static bool m_unloadFlag = false;
public static WorkflowService WorkflowServiceInstance { get; private set; }
public WorkflowInstance WorkflowInstance { get; private set; }
public static WorkflowRuntime WorkflowRuntime
{
get { return WorkflowCommand.m_workflowRuntime; }
}
#region Factory Methods
public static void InitializeWorkflowRuntime()
{
m_unloadFlag = false;
WorkflowCommand cmd = new WorkflowCommand();
DataPortal.Execute<WorkflowCommand>(cmd);
}
public static void UnloadWorkflowRuntime()
{
m_unloadFlag = true;
WorkflowCommand cmd = new WorkflowCommand();
DataPortal.Execute<WorkflowCommand>(cmd);
}
#endregion
#region Server-side Code
protected override void DataPortal_Execute()
{
if (!m_unloadFlag)
{
m_workflowRuntime = new WorkflowRuntime();
m_exchangeService = new ExternalDataExchangeService();
m_workflowRuntime.AddService(new ManualWorkflowSchedulerService());
m_workflowRuntime.AddService(m_exchangeService);
m_workflowRuntime.AddService(new SqlWorkflowPersistenceService(ConfigrationParameters.WorkflowConn));
m_workflowRuntime.AddService(new SqlTrackingService(ConfigrationParameters.WorkflowConn));
WorkflowServiceInstance = new WorkflowServiceInstance();
m_exchangeService.AddService(WorkflowServiceInstance);
m_workflowRuntime.StartRuntime();
}
else if (m_workflowRuntime != null)
{
m_workflowRuntime.StopRuntime();
}
}
#endregion
然后在globel里加载:
protected void Application_Start(object sender, EventArgs e)
{
WorkflowCommand.InitializeWorkflowRuntime();
}
这样的方式,保证了工作流的初始化在服务端完成,充分体现CSLA的思想。
那么如何在Bussiness object里使用这个Command对象呢,我们需要在Bussiness Object的DataPotal里控制工作流的流动和可持续化的操作,比如:
![]()
Code protected override void DataPortal_Update()
{
WorkflowInstance wfInstance = null;
ManualWorkflowSchedulerService schec = null;
WorkflowServiceInstance service = null;
Guid workflowID = Guid.Empty;
if (isrunWorkflow)
{
workflowID = ReadProperty(WorkflowIdProperty);
wfInstance = WorkflowCommand.WorkflowRuntime.GetWorkflow(workflowID);
wfInstance.Load();
schec = WorkflowCommand.WorkflowRuntime.GetService<ManualWorkflowSchedulerService>();
service = WorkflowCommand.WorkflowRuntime.WorkflowServiceInstance;
service.Start(Id, workflowID);
schec.RunWorkflow(workflowID);
}
//TODO:其他数据操作
wfInstance.Unload();
}
}
Ok,如上所示,把BussinessObject的数据操作和工作流数据操作都封装进DataPortal方法里,这样保证了工作流可持续化及跟踪服务在服务端运行。
这样,工作流就嵌入到CSLA框架中。
在界面,我们需要进入2层的innerException来捕捉工作流的异常:
![]()
Codecatch (Exception ex)
{
if (ex.InnerException.InnerException is System.Workflow.Activities.EventDeliveryFailedException)
{
//alert("not allowed!")
return;
}
else { }
}
整个过程结束。