Windows Workflow Foundation (WF) 和 DotNetNuke™






4.88/5 (6投票s)
本文描述了一个使用 DotNetNuke 模块与托管在 Web 服务中的 Windows Workflow 服务进行通信的实现。
引言
Windows Workflow Foundation 是一个用于管理工作流的框架。本文描述了一个使用 DotNetNuke 模块与托管在 Web 服务中的 Windows Workflow 服务进行通信的实现。
Windows Workflow Foundation 是一个强大的企业级框架,允许您建模业务流程并执行和管理工作流。是的,您可以完全通过过程化代码实现相同的功能;然而,对于复杂的业务流程,您最终可能会得到一堆难以管理的混乱代码。Windows Workflow Foundation 允许您以图形方式建模工作流流程并轻松更改它们。
示例应用程序称为“休假申请”。该应用程序允许用户启动休假申请并获得批准(或不批准)。该应用程序并非真正实用,它只是一个示例,展示了使用 DotNetNuke 模块与 Windows Workflow 服务(托管为 Web 服务)进行通信所需的最小组件。
以下不是教程。它只是创建示例代码所用步骤的概述。它不包含您在实际工作流应用程序中需要添加的重要组件,例如 SqlWorkflowPersistenceService。它也不包含 Web 方法的安全性。有关 Web 方法安全性的示例,请参阅 实现“超级严格的安全”。
创建 Web 服务
ASP.NET 3.51 SP1(或更高版本)包含 用于使用 WCF 托管 Windows Workflow 的附加组件。然而,本示例使用的是普通的 .asmx Web 服务。
使用 Visual Studio 2008 创建一个名为 VacationRequest 的新项目。
创建一个接口类(IVacationRequest
),该类指示将使用的 Web 方法。
using System;
namespace VacationRequest
{
public interface IVacationRequest
{
/// Activate the workflow
void StartWorkflow();
/// Perform a division operation
bool RequestedDays(int RequestedDays);
/// Retrieve the last divide result
String VacationRequestStatus();
/// Allow the workflow to stop
void StopWorkflow();
}
}
向项目中添加一个顺序工作流(VacationRequestWorkflow
)类。
使用 Visual Studio 中的设计器来组装类中的活动(以实现流程)。
使用 WhileActivity
(ProcessRequest
)在 EventDrivenActivity
s 被反复调用时保持工作流实例的活动状态(**注意**,此示例不使用 持久化服务,因此当 ASP.NET 进程终止时,工作流实例最终也会终止)。
ProcessRequest
通常仅在(代码隐藏中的)CheckIsTimeToStop
变量为 true
时终止。请注意,CheckIsTimeToStop
被设置为 Condition
。
ProcessRequest
活动使用三个 EventDrivenActivity
s 来分组 RequestedDays
、VacationRequestStatus
和 StopWorkflow
Web 方法(StartWorkflow
方法映射到工作流图顶部的 StartVacationRequest
活动)。
例如,EventDrivenActivity1
用于分组 WebServiceInputActivity
(RequestedDaysInput
)、CodeActivity
(ApproveRequest
)和 WebServiceOutputActivity
(RequestedDaysOutput
)。
WebServiceInputActivity
(RequestedDaysInput
)用于将 RequestedDays
Web 服务方法及其传递给它的参数映射到工作流。
CodeActivity
(ApproveRequest
)执行代码(ApproveRequest_ExecuteCode
),该代码将更改休假申请的状态(代码隐藏中的 RequestStatus
变量)。
WebServiceOutputActivity
(RequestedDaysOutput
)完成 Web 服务调用。此活动可以从工作流返回值。在本例中,它仅返回一个正值。
以下代码是该类的完整代码隐藏。
using System;
using System.Workflow.Activities;
namespace VacationRequest
{
public sealed partial class VacationRequestWorkflow :
SequentialWorkflowActivity
{
public int RequestDays;
public string RequestStatus;
public Boolean isTimeToStop = false;
public VacationRequestWorkflow()
{
InitializeComponent();
}
// This method will return the value of isTimeToStop
// The value of isTimeToStop will be set by other
// methods in the workflow
private void CheckIsTimeToStop(object sender, ConditionalEventArgs e)
{
e.Result = !(isTimeToStop);
}
// Request will be approved if RequestDays is less than 3 days
private void ApproveRequest_ExecuteCode(object sender, EventArgs e)
{
RequestStatus = (RequestDays < 3) ? ''Approved'' : ''Not Approved'';}
// When this method is called isTimeToStop will be set to true
// This will cause the workflow to terminate
private void webServiceInputActivity1_InputReceived(object sender, EventArgs e)
{
//Stop the WhileActivity
isTimeToStop = true;
}
}
}
代码已完成。现在选择**发布为 Web 服务**。
创建一个 Web 服务项目,并在 Web 浏览器中查看 VacationRequest.VacationRequestWorkflow_WebService.asmx 页面时……
将显示 Web 方法。
**注意**:如果使用 IIS7 运行 Web 服务的示例代码,应用程序池必须设置为“经典 .NET AppPool”。
DotNetNuke 模块 Web 服务引用
然后创建一个 DotNetNuke 模块,该模块将能够与 Windows Workflow Foundation Web 服务通信。首先,创建一个 Web 代理。
在 Visual Studio 中打开 DotNetNuke 网站并添加一个新项目。
创建一个名为 VacationWebService 的简单类项目。
创建一个 Web 引用,指向先前步骤中创建的 Web 服务。请注意,我们将在后续步骤中以编程方式更改 Web 服务的地址。
DotNetNuke 模块
DotNetNuke 模块允许您输入 Web 服务的 URL,在单击 创建休假申请 按钮后,检索 WorkflowID
。WorkflowID
将在当前工作流实例的所有后续请求中传递。Web 服务期望 WorkflowID
在标头中传递。
以下是执行该任务的按钮的代码。
protected void btnCreateVacationRequest_Click(object sender, EventArgs e)
{
// Reference to the web service
VacationRequestWorkflow_WebService VacationRequest =
new VacationRequestWorkflow_WebService();
// Enable cookies
VacationRequest.CookieContainer = new System.Net.CookieContainer();
// Set the address to the web service
VacationRequest.Url = txtWebserviceURL.Text.Trim();
// Call the method to start the workflow
VacationRequest.StartWorkflow();
// Create a URI
Uri VacationRequestUri = new Uri(VacationRequest.Url);
// The web service will pass
// the WorkflowInstanceId back in the cookie collection
// Use the URI to obtain a collection of the cookies
CookieCollection mycollection =
VacationRequest.CookieContainer.GetCookies(VacationRequestUri);
// Loop through each cookie until the WF_WorkflowInstanceId cookie is found
foreach (Cookie Cookie in mycollection)
{
if (Cookie.Name == ''WF_WorkflowInstanceId'')
{
// Display the WF_WorkflowInstanceId value in the text box
txtCurrentWorkflowID.Text = Cookie.Value;
}
}
}
下一步是请求天数。
以下是执行此任务的代码。
protected void btnRequestDays_Click(object sender, EventArgs e)
{
// Reference to the web service
VacationRequestWorkflow_WebService VacationRequest =
new VacationRequestWorkflow_WebService();
// Set the address to the web service
VacationRequest.Url = txtWebserviceURL.Text.Trim();
// Create a URI
Uri VacationRequestUri = new Uri(VacationRequest.Url);
// Enable cookies
VacationRequest.CookieContainer = new System.Net.CookieContainer();
// Use the URI to obtain a collection of the cookies
CookieCollection mycollection =
VacationRequest.CookieContainer.GetCookies(VacationRequestUri);
// Add the current WorkflowInstanceId to the cookie collection
// that will be passed to the web service
VacationRequest.CookieContainer.SetCookies
(
VacationRequestUri,
String.Format(''{0}={1}'', ''WF_WorkflowInstanceId'',
txtCurrentWorkflowID.Text.Trim())
);
// Call the RequestedDays web method and pass the requested days
VacationRequest.RequestedDays(Convert.ToInt32(txtRequestedDays.Text));
}
现在可以检索休假申请的状态。如果请求未获批准,您可以使用同一工作流实例更改天数并重新提交。
以下是执行此任务的代码。
protected void btnGetStatus_Click(object sender, EventArgs e)
{
// Reference to the web service
VacationRequestWorkflow_WebService VacationRequest =
new VacationRequestWorkflow_WebService();
// Set the address to the web service
VacationRequest.Url = txtWebserviceURL.Text.Trim();
// Create a URI
Uri VacationRequestUri = new Uri(VacationRequest.Url);
// Enable cookies
VacationRequest.CookieContainer = new System.Net.CookieContainer();
// Use the URI to obtain a collection of the cookies
CookieCollection mycollection =
VacationRequest.CookieContainer.GetCookies(VacationRequestUri);
// Add the current WorkflowInstanceId to the cookie collection
// that will be passed to the web service
VacationRequest.CookieContainer.SetCookies
(
VacationRequestUri,
String.Format(''{0}={1}'', ''WF_WorkflowInstanceId'',
txtCurrentWorkflowID.Text.Trim())
);
// Call the VacationRequestStatus web method and retrieve the status
lblRequestStatus.Text = VacationRequest.VacationRequestStatus();
}
最后一步是停止工作流。
以下是执行此任务的代码。
protected void btnStopWorkflow_Click(object sender, EventArgs e)
{
// Reference to the web service
VacationRequestWorkflow_WebService VacationRequest =
new VacationRequestWorkflow_WebService();
// Set the address to the web service
VacationRequest.Url = txtWebserviceURL.Text.Trim();
// Create a URI
Uri VacationRequestUri = new Uri(VacationRequest.Url);
// Enable cookies
VacationRequest.CookieContainer = new System.Net.CookieContainer();
// Use the URI to obtain a collection of the cookies
CookieCollection mycollection =
VacationRequest.CookieContainer.GetCookies(VacationRequestUri);
// Add the current WorkflowInstanceId to the cookie collection
// that will be passed to the web service
VacationRequest.CookieContainer.SetCookies
(
VacationRequestUri,
String.Format(''{0}={1}'', ''WF_WorkflowInstanceId'',
txtCurrentWorkflowID.Text.Trim()));
// Stop the workflow and delete the workflow instance
VacationRequest.StopWorkflow();
}
如果您在工作流停止和删除后尝试请求 WorkflowInstanceID
的状态,您将收到一个错误,因为工作流实例已不存在。
一个简单的例子,拥有巨大的可能性
Windows Workflow Foundation 的真正强大之处在于它能够让您轻松地更改工作流。工作流可以发送电子邮件、与旧系统通信并记录所有事件。工作流还可以拥有事件,如果请求批准时间过长,会发送电子邮件。
此外,Silverlight 等客户端技术可以提供更深入、更丰富的界面来执行任务。