Огляд робочого потоку Windows Workflow. Частина 3, Різне, Програмування, статті

Читати частина 2


Прикріплені властивості


При реєстрації властивостей залежно ви можете викликати метод RegisterAttached для створення прикріпленого властивості. Прикріплене властивість – це така властивість, яке визначено в одному класі, але відображається в іншому. В даному випадку ви визначаєте властивість в DaysOfWeekActivity, але насправді це властивість відображається в інтерфейсі як прикріплене до послідовного дії.





public static DependencyProperty
WeekdayProperty =
DependencyProperty.RegisterAttached(“Weekday”,
typeof(WeekdayEnum), typeof(DaysOfWeekActivity),
new PropertyMetadata(DependencyPropertyOptions.Metadata));

Останній рядок дозволяє специфікувати додаткову інформацію про властивість; в даному прикладі специфікована, що цією властивістю буде Metadata.


Властивості Metadata відрізняються від звичайних властивостей в тому відношенні, що вони ефективно читаються тільки під час виконання. Ви можете сприймати властивість Metadata як щось подібне оголошенню констант всередині C #. Ви не можете змінити константи під час виконання програми, і точно також ви не можете змінювати властивості Metadata під час виконання робочого потоку.


В даному прикладі ви хочете встановити дні активізації дії, тому ви можете встановити в Designer це поле в “Saturday, Sunday”. У коді, виданому для робочого потоку, ви можете побачити оголошення, подібні показаним нижче.





this.sequenceActivity1.SetValue
(DaysOfWeekActivity.WeekdayProperty,
((WeekdayEnum)((WeekdayEnum.Sunday / WeekdayEnum.Saturday))));

На додаток до визначення властивості залежності вам знадобляться методи для отримання і установки цього значення для довільного дії. Це зазвичай визначається як статичний метод складеного дії і показано в наступному коді:





public static void SetWeekday( Activity activity, object value )
{
if ( null == activity )
throw new ArgumentNullException( “activity” );
if ( null == value )
throw new ArgumentNullException( “value” );
activity.SetValue( DaysOfWeekActivity.WeekdayProperty, value );
}
public static object GetWeekday( Activity activity )
{
if ( null == activity )
throw new ArgumentNullException( “activity” );
return activity.GetValue( DaysOfWeekActivity.WeekdayProperty );
}

Є ще дві зміни, які ви повинні внести, щоб додаткове властивість могло відображатися як приєднане до SequenceActivity. Перше – це створити постачальника розширювачів, який повідомить Visual Studio про необхідність включення додаткового властивості в послідовне дію, і друге – зареєструвати цього постачальника, що робиться перевизначенням методу Initialize в Activity Designer і додаванням наступного коду до нього:





protected override void Initialize( Activity activity )
{
base.Initialize( activity );
IExtenderListService iels = base.GetService( typeof( IExtenderListService ) )
as IExtenderListService;
if ( null != iels )
{
bool extenderExists = false;
foreach ( IExtenderProvider provider in iels.GetExtenderProviders() )
{
if ( provider.GetType() == typeof( WeekdayExtenderProvider ) )
{
extenderExists = true;
break;
}
}
if ( !extenderExists )
{
IExtenderProviderService ieps =
base.GetService( typeof( IExtenderProviderService ) )
as IExtenderProviderService;
if ( null != ieps )
ieps.AddExtenderProvider( new WeekdayExtenderProvider() );
}
}
}

Виклики GetService в наведеному коді призначені для того, щоб дозволити користувача конструктору запросити служби, предоставляемиехостом (в даному випадку ним є Visual Studio ). Ви запитуєте у Visual Studio IextenderListService, який надає спосіб перерахувати всіх доступних постачальників розширювачів, і якщо не буде знайдено жодного примірника WeekdayExtenderProvider, тоді запитується IExtenderProviderService, і додається новий постачальник. Нижче показаний код постачальника розширювачів.





[ProvideProperty(“Weekday”, typeof(SequenceActivity))]
public class WeekdayExtenderProvider : IExtenderProvider
{
bool IExtenderProvider.CanExtend(object extendee)
{
bool canExtend = false;
if ((this != extendee) && (extendee is SequenceActivity))
{
Activity parent = ((Activity)extendee).Parent;
if (null != parent)
canExtend = parent is DaysOfWeekActivity;
}
return canExtend;
}
public WeekdayEnum GetWeekday(Activity activity)
{
WeekdayEnum weekday = WeekdayEnum.None;
Activity parent = activity.Parent;
if ((null != parent) && (parent is DaysOfWeekActivity))
weekday = (WeekdayEnum)DaysOfWeekActivity.GetWeekday(activity);
return weekday;
}
public void SetWeekday(Activity activity, WeekdayEnum weekday)
{
Activity parent = activity.Parent;
if ((null != parent) && (parent is DaysOfWeekActivity))
DaysOfWeekActivity.SetWeekday(activity, weekday);
}
}

Постачальник розширювачів забезпечений властивостями, які він надає, і для кожного з цих властивостей він повинен забезпечити загальнодоступні методи Get і Set . Імена цих методів повинні відповідати іменам властивості з відповідним префіксом Get або Set.


Після внесення показаних вище змін до Designer і додавання постачальника розширень, коли ви клацнете на послідовному дії у візуальному конструкторі, то в Visual Studio побачите властивості, показані на рис. 41.14.


Рис. 41.14. Прикріплені властивості


Постачальники розширювачів використовуються в. NET і для інших цілей. Одним з поширених застосувань є додавання спливаючих підказок (tooltips) до елементів управління в проекті Windows Forms. Коли ви додаєте в форму елемент-підказку, це реєструє розширювач і додає властивість Tooltip до кожного елементу управління у формі.


Робочі потоки


До цього моменту в цій главі увага концентрувалася на діях, але не говорилося про робочі потоках. Робочий потік – це просто список дій, і насправді робочий потік сам по собі є ще одним типом дій. Застосування такої моделі спрощує механізм виконує системи, оскільки йому достатньо знати, як слід виконувати тільки один тип об’єктів – будь-який, успадкований від класу Activity.


Кожен екземпляр робочого потоку унікально ідентифікований властивістю InstanceId, тобто Guid, який може бути призначено виконуючою системою, або ж цей Guid може бути представлений виконуючою системі вашим кодом – зазвичай це робиться для кореляції працюючого примірника робочого потоку з деяким зовнішнім джерелом даних, що знаходяться поза робочим потоку, таким як рядок бази даних. Ви можете звернутися до певного екземпляру робочого потоку за допомогою методу GetWorkflow (Guid) класу WorkflowRuntime.


Існують два типи робочих потоків, доступних в WF – послідовний і кінцевий автомат.


Послідовні робочі потоки


Кореневе дію послідовного робочого потоку – це SequentialWorkflowActivity. Цей клас успадковував від SequenceActivity, який ви вже бачили, і він визначає дві події, до яких при необхідності ви можете приєднати обробники. Ці події – Initialized і Completed.


Послідовний робочий потік починає роботу, виконуючи знаходиться в ньому перше дочірнє дію, і зазвичай триває до тих пір, поки не виконає всі інші дочірні дії. Є кілька ситуацій, коли робочий потік не виконує всіх своїх дій. Одна – це коли виникає виняток у процесі виконання робочого потоку, а інша – коли всередині потоку зустрічається TerminateActivity.


Робочий потік може і не виконуватися постійно; наприклад, коли зустрічається DelayActivity, то потік входить в стан очікування, і тоді він може бути видалений з пам’яті, якщо визначена служба сталості потоків. Сталість потоків зазначено в розділі “Служба сталості”.


Робочі потоки типу кінцевих автоматів


Потік типу кінцевого автомата використовується у випадку, коли у вас є процес, який може перебувати в одному з декількох станів, і переходи з одного стану в інший можуть виконуватися за допомогою передачі даних в робочий потік.


Прикладом може служити робочий потік, який використовується для керування будинком. В цьому випадку ви можете моделювати клас двері, яка може бути закрита або відкрита, і клас замка, який може бути замкнутий або незамкнуті. Спочатку, коли ви завантажуєте систему (або будівля!), Ви починаєте з відомого стану; для простоти припустимо, що всі двері закриті і замкнені на замок, так що стан даної двері – “закрита і замкнені“.


Коли співробітник вводить свій код доступу на зовнішніх дверей, він тим самим посилає подія робочого потоку, що включає такі подробиці, як введений код і, можливо, ідентифікатор користувача. Потім вам може знадобитися звернутися до бази даних для отримання подробиць, таких як, наприклад, чи має ця особа право відкривати обрану двері в цей час дня, і якщо має, то робочий потік повинен змінити стан двері з початкового на стан “відкрита і не замкнені“.


З цього стану є два потенційні шляхи – співробітник відкриває двері (ви знаєте це, оскільки двері забезпечена сенсором відкриття / закриття), або ж він вирішить не входити, оскільки забув щось у себе в машині, і тоді після невеликої паузи ви замикаєте двері. Таким чином, двері можуть перейти в свій стан “закрита і замкнена” або ж в стан “відкрита і не замкнені”.


Тепер припустимо, що співробітник увійшов в будівлю і зачинив за собою двері; знову ж ви повинні виконати перехід зі стану “відкрита і не замкнені” в стан “закрита і не замкнені”, і після паузи повинен відбутися перехід в стан “закрита і замкнені”. Ви також можете видати сигнал тривоги, якщо двері залишилася “відкритою і не замкненою” протягом тривалого періоду часу.


Змоделювати цю ситуацію в середовищі Windows Workflow надзвичайно просто. Вам потрібно визначити стану, які може приймати система, і потім визначити події, які можуть переводити її з одного стану в інший. У табл. 41.2 описані стану системи і подробиці переходів, які можливі з кожного стану, а також введення (як зовнішній, так і внутрішній), що змінює ці стани.


Одне з інших коштів, які ви можете вирішити додати в систему – це здатність реагувати на сигнал пожежної тривоги. Коли сигнал тривоги буде вимкнений, вам потрібно відімкнути всі двері, щоб усі могли покинути будівлю, а пожежна команда – проникнути в нього. Ви можете змоделювати це як фінальне стан робочого потоку керуючого дверима, оскільки з цього стану вся система повинна бути скинута, як тільки пожежна тривога буде скасована.



















Стан Перехід
Закрита і замкнені Це початковий стан системи.
У відповідь на вставку користувачем картки (і успішної перевірки права доступу) стан змінюється в “закрита і не замкнені”, тобто замок двері відмикається електронікою
Закрита і не замкнені Коли двері знаходиться в цьому стані, можетпроізойті одне з двох подій:
(1) користувач відкриває двері – виконується перехід в стан “відкрита і не замкнені”;
(2) закінчується час таймера і двері повертається в стан “закрита і замкнена”
Відкрита і не замкнені З цього стану робочий потік може перейти тільки в стан “закрита і не замкнені”
Пожежна тривога Цей стан – фінальне для робочого потоку, і в нього можна перейти з будь-якого іншого стану
Таблиця 41.2. Стани і переходи системи

Робочий потік на рис. 41.15 визначає кінцевий автомат і показує стани, які він може приймати, а лінії означають можливі переходи з одного стану в інший.


Рис. 41.15. Визначення кінцевого автомата


Початковий стан робочого потоку змодельоване дією ClosedLocked. Воно складається з деякого коду ініціалізації (замикаючого двері) і потім дії на основі події, яка очікує зовнішнього події – В даному випадку, введення співробітником власного коду доступу до будівлі. Кожне з показаних дій всередині фігури стану складається з послідовних робочих потоків – таким чином, було визначено робочий потік ініціалізації системи (CLInitialize) і робочий потік, який відповідає на зовнішні події, що виникають при воді співробітником його PIN-коду (RequestEntry). Погляньте на визначення робочого потоку RequestEntry, як він зображений на рис. 41.16.


Рис. 41.16. Визначення робочого потоку RequestEntry


Кожен стан складається з ряду підпотоків, кожен з яких має кероване подією дію на початку, а потім кілька інших дій, які формують обробляє код всередині стану. На рис. 41.16 є дія HandleExternalEventActivity на початку, яке очікує введення PIN. Потім виконується його перевірка, і якщо код дійсний, робочий потік переходить в стан ClosedUnlocked.


Стан ClosedUnlocked складається з двох робочих потоків – один реагує на подію відкриття дверей, яке переводить робочий потік в стан OpenUnlocked, а інший, який містить дію затримки, використовується для переходу в стан ClosedLocked. Дія, кероване станом, працює в манері, аналогічної дії ListenActivity, показаному раніше в цій главі – це стан складається з ряду керованих подіями робочих потоків, і будь що виникає подія обробляється тільки одним робочим потоком.


Для підтримки робочого потоку ви повинні бути готові ініціювати події в системі, щоб викликати зміни стану системи. Це робиться за рахунок використання інтерфейсу і реалізації цього інтерфейсу, і така пара об’єктів називається зовнішньої службою (External service). Нижче в цьому розділі буде описаний інтерфейс, використовуваний в даному кінцевому автоматі.


Передача параметрів робочого потоку


Типовий робочий потік для свого виконання Visual Studio вимагає деяких даних. Це може бути ідентифікатор замовлення для потоку обробки замовлень, ідентифікатор облікового запису покупця для робочого потоку обробки платежів або будь-які інші необхідні дані.


Механізм передачі параметрів для робочих потоків дещо відрізняється від того ж механізму в стандартних класах. NET, де зазвичай ви передаєте параметри при виклику методу. Для робочого потоку ви передаєте параметри, зберігаючи їх у словнику у вигляді пар “ім’я-значення”, і коли ви конструюєте робочий потік, то проходите з цього словника. Коли WF планує на виконання робочий потік, ці пари “ім’я-значення” використовуються для установки значень загальнодоступних властивостей екземпляра робочого потоку. Кожне ім’я параметра перевіряється по загальнодоступним властивостями робочого потоку і, якщо виявлено відповідність, викликається засіб доступу set цієї властивості і йому передається значення параметра. Якщо ви додаєте в словник пару “імязначеніе”, причому ім’я не відповідає властивості робочого потоку, то при спробі сконструювати такий робочий потік буде порушено виняток.


Як приклад розглянемо наступний робочий потік, що визначає цілочисельне властивість OrderID:





public class OrderProcessingWorkflow: SequentialWorkflowActivity
{
public int OrderID
{
get { return _orderID; }
set { _orderID = value; }
}
private int _orderID;
}

Наступний фрагмент показує, як можна передати параметр – ідентифікатор замовлення екземпляру цього робочого потоку:





WorkflowRuntime runtime = new WorkflowRuntime ();
Dictionary<string,object> parms = new Dictionary<string,object>();
parms.Add(“OrderID”, 12345) ;
WorkflowInstance instance =
runtime.CreateWorkflow(typeof(OrderProcessingWorkflow), parms);
instance.Start();
… / / Інший код

У наведеному прикладі конструюється словник Dictionary , що містить параметри, які ви хочете передати робочого потоку, і потім використовувати при його конструюванні. Наведений вище код включає класи WorkflowRuntime і WorkflowInstance, які ще не були описані, про них мова піде в розділі “Хостинг робочих потоків” далі у розділі.

Читати частина 4

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*