Последний шаг перед запуском рабочего процесса— создание обмена между хостом и выполняющимся рабочим процессом через модель событий. Вспомним, что мы уже описали интерфейс, который настроил контракт вызова из хоста в рабочий процесс. Мы сделали это при, настройке действий HandleExternalEvent. Контракт интерфейса был назван iApproval.
Выполните следующие шаги для реализации этого контракта обмена в приложении хоста:
1. Создайте в приложении новый класс и назовите его ManageApproval.
2. Реализуйте созданный ранее интерфейс IApproval. Это означает, что вам нужно описать дескриптор для события Approve. Кроме того, класс должен быть помечен как Serializable. Далее показан пример:
[Serializable]
*
class ManageApproval : IApproval {.
public event EventHandler<ApprovalEventArgs> Approval;
}
3. Затем создайте в классе метод, который будет запускать событие. Этот метод должен вызываться из клиента для утверждения поездки (или отклонения ее). Он должен записывать результаты в параметры ApprovalEventArgs, которые принимает событие Approval, а затем порождать событие, передавая самого себя в качестве посылающей стороны. Вот пример:
public void ApproveTravel(int travelld, bool isApproved, Guid wfInstanceld) {
// Проверить, есть ли подписчик на событие if (Approval != null) {
// Создать аргументы нового события и установить утверждение ApprovalEventArgs approvalArgs = new ApprovalEventArgs(wfInstanceld) ; approvalArgs.IsApproved = isApproved;
i
// Породить событие, передав самого себя Approval(this, approvalArgs);
}
i
4. Вам нужно зарегистрировать экземпляр этого нового класса в сервисе обмена данными рабочего процесса. Это позволит соединить события хоста и рабочего процесса. Добавьте в метод Main следующий код (после уже сделанных вами ранее вызовов
AddService):
// Настроить обмен HandleExternalEvent ManageApproval approvalMgr = new ManageApproval(); exchangeServ.AddService(approvalMgr);
5. Теперь вам нужно добавить клиентский код (также в метод Main файла Program.cs). Это позволит вам ввести условие утверждения.
Вспомните, что рабочий процесс должен уведомить соответствующего утверждающего менеджера. После этого утверждающий менеджер зайдет в клиентское приложение. Это приложение проверит, является ли данный утверждающий менеджер правильным утверждающим, а затем позволит ему произвести утверждение. Однако нашему простому консольному приложению придется все это имитировать при помощи некоего тестового кода. В настоящем решении клиентское приложение узнало бы об этом благодаря информации из рабочего процесса (возможно, сохраненной в базе данных).
Вы можете попросить пользователя ввести утверждение через консоль, а затем вызвать метод ApproveTravel класса ManageApproval. Все это будет передано в ожидающий рабочий процесс. В этот метод вы должны передать имитированный идентификатор запроса на поездку, состояние утверждения (true или false), а также идентификатор экземпляра рабочего процесса. Это показано в следующем коде:
approvalMgr .ApproveTravel (_request Id, true, instance. Instanceld) ;
Полный код хоста и клиента показан в листинге 20.1.
using System;
using System.Collections.Generic;
using System. Linq;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.Activities;
namespace TravelRequestWf { class Program {
private static AutoResetEvent _waitHandle private static string _userName; private static double _travleCost; private static int _requestld; private static void EnterTravelRequest() {
II Описать параметры рабочего процесса
Console.Write("Enter a user паше (>6 = manager): ");
_userName = Console.ReadLine();
Console.Write("Enter travel cost (double): "); string cost = Console.ReadLine();
_travleCost = double.Parse(cost);
Console.Write("Enter travel id (int): ") ; string id = Console.ReadLine();
_requestld = int.Parse(id);
}
static void Main(string[] args) {
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime()) {
// Создать объект обмена данными ExternalDataExchangeService exchangeServ =
new ExternalDataExchangeService();
\
workflowRuntime.AddService(exchangeServ);
// Настроить обмен CallExternalMethod exchangeServ.AddService(new UserProfile()); exchangeServ.AddService(new Notification());
// Настроить обмен HandleExternalEvent ManageApproval approvalMgr = new ManageApproval(); exchangeServ.AddService(approvalMgr);
// Подключить события рабочего процесса workflowRuntime.WorkflowCompleted += OnWorkflowComplete; workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;
// Получить ввод пользователя EnterTravelRequest();
// Настроить параметры
Dictionary<string, object> wfParams = new Dictionary<string, object>(); wfParams.Add("TravelRequestor", _userName); wfParams.Add("TravelCost", _travleCost); wfParams.Add("TravelRequestId", requestld);
11 Ждать указаний пользователя
Console.WriteLine("Hit enter to start the workflow.");
Console.ReadLine();
// Создать экземпляр рабочего процесса
Workflowlnstance instance = workflowRuntime.CreateWorkflow( typeof(TravelRequestWf.TravelRequestProcess), wfParams);
// Запустить рабочий процесс instance.Start() ;
Console.WriteLine("Workflow Started: " +
instance.Instanceld.ToString());
// Сделать паузу, чтобы подождать рабочий процесс Thread.Sleep(300);
// Если рабочий процесс ждет утверждения (тестовый код) if(IsWaitingOnApproval()) {
Console.Write("Enter 'approve1 to approve travel,
or anything else to reject: "); string approval = Console.ReadLine();
if(approval == "approve") {
approvalMgr.ApproveTravel(_requestId, true, instance.Instanceld);
} else {
approvalMgr.ApproveTravel(_requestld, false, instance.Instanceld);
}
}
_waitHandle.WaitOne();
Console.WriteLine("");
Console.WriteLine("Hit enter to exit.");
Console.ReadLine();
}
}
private static bool IsWaitingOnApproval() {
// Это тестовый код, а не реальный клиент.
// Определить, ждет ли рабочий процесс утверждения.
UserProfile userProfile = new UserProfile();
// Если пользователь - не менеджер, то требуется утверждение if (!userProfile.IsUserManager(_userName)) { return true;
} else if (_travleCost > 1500) { return true;
} else {
return false;
}
}
private static void OnWorkflowComplete(object sender, WorkflowCompletedEventArgs e) {
Console.WriteLine("Workflow Completed: " +
e.WorkflowInstance.Instanceld.ToString()); _waitHandle.Set();
}
private static void OnWorkflowTerminated(object sender, WorkflowTerminatedEventArgs e) {
Console.WriteLine("Workflow Completed: "
+ e.Workflowlnstance.Instanceld + ". Message: " +e.Exception.Message);
_waitHandle.Set();
}
}
}