4、添加自定义活动
现在我们的服务已经可以从智能客户端接受一个工作申请了。接下来,我们要做一些必要的修改来准备接收工作申请了。
现在我们的服务已经可以从智能客户端接受一个工作申请了。接下来,我们要做一些必要的修改来准备接收工作申请了。
- 将Source\Assets文件中的两个项目添加到解决方案: HRApplicationServices.Contracts和HRApplicationServices.Activities
- 在HRApplicationServices项目中添加对上面两个项目的引用。
- 由于我们的工作流是一个长时间运行的程序,可能做一些内部工作之后需要等待人工响应。这就意味我们需要配置持久化存储。打开HRApplicationServices中web.config文件,在connectionStrings中添加下面的内容:
在<behavior>配置节中的serviceMetadata节后添加 sqlWorkflowInstanceStore行为<connectionStrings> <add name="WF4Persistence" connectionString="Data Source=.\sqlexpress; Database=WF4Persistence; Integrated Security=True"/>
<serviceMetadata httpGetEnabled="true"/> <sqlWorkflowInstanceStore connectionStringName="WF4Persistence"/>
- 重新生成解决方案,以保证可以使用HRApplicationService.Activities中定制的活动。
5、接受工作申请
- 打开SubmitApplication.xamlx创建一个变量来存储申请请求和响应。先删除ApplicationService活动中的data变量,然后添加类型为SubmitJobApplicationRequest名为ApplicationRequest的变量和类型为SubmitJobApplicationResponse名为ApplicationResponse的两个变量。这两种类型都在HRApplicationServices.Contracts类库之中。
- 为ApplicationResponse变量赋初值,“New SubmitJobApplicationResponse()”
- 接下来修改DataContract以接收工作申请。首先展开“Receive Application”活动,选择其中的ReceiveRequest活动,按下【F4】功能键打开属性窗口,做如下修改:
==>
6、保存工作申请
我们需要将工作流申请保存到HR数据库中,在源文件中提供的SaveJobApplication定制活动会调用ADO.NET的Entity Framework框架来帮助我们实现这一功能。当一个工作申请保存到数据库中时,会自动创建一个申请ID,这个ID会作为记录的主键。
- 从工具栏的HRApplicationServices组拖拽一个SaveJobApplication活动到Save and Respond活动下的SendResponse活动前面。
将SaveJobApplication的属性设置值如下:
AppRequest : ApplicationRequest ;
Result : ApplicationResponse
下面是SaveJobApplication自定义活动的代码:
/// <summary> /// <SubmitJobApplicationResponse>表示活动返回结果的类型 /// </summary> public class SaveJobApplication : CodeActivity<SubmitJobApplicationResponse> { public InArgument<SubmitJobApplicationRequest> AppRequest { get; set; } //执行活动 protected override SubmitJobApplicationResponse Execute(CodeActivityContext context) { //HRApplicationDataEntities提供用于查询和使用对象形式的实体数据的功能。 using (HRApplicationDataEntities ctx = new HRApplicationDataEntities()) { //从工作流上下文中获取提交的申请信息 SubmitJobApplicationRequest request = AppRequest.Get(context); //创建申请对象 Applicant app = ctx.Applicants.CreateObject(); app.ApplicantName = request.Resume.Name; app.NumberOfReferences = request.Resume.NumReferences; app.Education = request.Resume.Education; app.RequestID = request.RequestID; //保存对象 ctx.Applicants.AddObject(app); ctx.SaveChanges(); ctx.Connection.Close(); return new SubmitJobApplicationResponse() { ApplicationID = app.ApplicationID, ApplicantName = request.Resume.Name, ResponseText = string.Format(ServiceResources.JobApplicationProcessing, request.Resume.Name, app.ApplicationID) }; } } }
ServiceResources资源文件:
运行完SaveJobApplication活动之后,ApplicationResponse变量里面将储存JobApplicationProcessing字符串中的内容,表示我们已经收到申请,并正在处理。
7、配置响应
尽管我们现在已经将工作申请保存到了数据库,但是仍然需要让客户端应用程序知道你已经收到了申请并正在处理中。并且还要初始化关联句柄(correlation handle),我们将使用它来识别绑定到工作流实例的信息,此工作流使用的内容是基于关联的。
- 首先,我们需要创建一个关联句柄,这个句柄将关联此工作流实例的信息。选中Application Service,点击变量按钮,添加一个新变量ApplicationIDHandle,类型为CorrelationHandle。
- 接下来设置响应数据。在SendResponse活动中,点击“查看消息”标签显示内容定义弹出框,将“Message data”修改为ApplicationResponse。
- 现在我们可以定义相关初始值设定项CorrelationInitializers了。这个初始值设定项将使用XPath表达式从输出信息ApplicationResponse中提取数据ApplicationID。提取的键值将被用于确定持久化工作流实例。选中SendResponse活动,打开属性窗口中CorrelationInitializers旁边的“...”按钮,弹出“Add Correlation Initializers”对话框。
- 点击“Add initializer”按钮并写入 ApplicationIDHandle。
- 选中新增的ApplicationIDHandle,在XPath查询窗口双击选中“ApplicationID:Int32”信息内容,自动生成XPath语句。
- 在我们创建的工作流服务中使用的默认命名空间是tempuri.org,我们可以对其进行修改。右键选中SubmitApplication.xamlx文件后查看代码
- 定位到“Name=”处,然后插入字母“p”。这一操作将使得服务使用操作契约的命名空间作为WSDL类型的默认命名空间。>
8、添加客户端程序
- 添加源代码Source\Assets中的HRClient项目。
- 在HRClient项目中添加对SubmitApplication.xamlx服务的引用。当然,你最好确认一下你引用的服务是否正确,方式如下:【选中HRApplicationService】---> 【展开】 ---> 【选中SubmitApplication.xamlx,右键】---> 【在浏览器中查看】,看看能够正常显示服务的wsdl说明。
9、测试
将HRClient设置为启动项目,运行
下面是客户端窗口程序的核心代码:
public partial class HRForm : Form
{
//服务在客户端的代理实例
HRClient.SubmitApp.ApplicationServiceClient proxy;
private void SubmitJobApplication()
{
ShowConfirmationPanel();
proxy = new HRClient.SubmitApp.ApplicationServiceClient();
// OnStartCompleted 是一个AsyncCallback,引用在异步操作完成时调用的回调方法
// BeginSubmitJobApplication异步调用SubmitJobApplication
proxy.BeginSubmitJobApplication(CreateApplicationRequest(), OnStartCompleted, null);
}
private void OnStartCompleted(IAsyncResult asr)
{
try
{
//接受服务器端响应结果
SubmitJobApplicationResponse result = (SubmitJobApplicationResponse)proxy.EndSubmitJobApplication(asr);
SetConfirmationText(result.ResponseText);
ShowStartAgainButton();
//关闭服务代理
proxy.Close();
}
catch (CommunicationException)
{
ShowExceptionText(Resources.CommException);
proxy.Abort();
}
catch (TimeoutException)
{
ShowExceptionText(Resources.TimeoutText);
proxy.Abort();
}
catch (Exception)
{
proxy.Abort();
throw;
}
}
private void SubmitButton_Click(object sender, EventArgs e)
{
SubmitJobApplication();
}
}