Pull to refresh

Windows Workflow Foundation – для чего и в каких случаях применять

Reading time8 min
Views22K

Базовое понимание
 
Помню, еще в университете перед реализацией любого алгоритма мы описывали его в виде блок схемы, и только после этого переходили непосредственно к кодированию. Workflow, как одна из парадигм программирования, на ряду с процедурным и объектно ориентированным подходами, как раз и позволяет нам визуально реализовать любой процесс, используя набор предопределенных функциональных блоков (Activity), при этом, избавляя от его последующего кодирования.

Библиотека WF, являясь одной из реализаций парадигмы Workflow, предоставляет следующие основные возможности:

— богатый набор функциональных блоков;
— расширение набора стандартных функциональных блоков пользовательскими;
— сохранение и возобновление экземпляров Workflow в процессе их исполнения;
— использование Workflow дизайнера в вашем приложении;
— интеграция с WCF;
— пошаговая диагностика непосредственно в Workflow дизайнере;
— и многое другое.

Критерии применения

Как известно, каждой технологии своя область применения. Для определения необходимости использования WF при реализации конкретного алгоритма/процесса я применяю 3 критерия:

1. Реализация алгоритма/процесса постоянно меняется.

В нашей компании мы разработали подсистему Workflow, которая является ядром всех продуктов. Имея, к примеру, десятки клиентов наших продуктов, у которых десятки процессов, получаем сотни разных изменяющихся процессов.

2. Процесс/алгоритм имеет длительный срок выполнения.

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

3. Нужно предоставить возможность изменения алгоритма/процесса конечному пользователю без вмешательства программиста.

Мы разработали свой собственный дизайнер, чтобы максимально упростить и облегчить редактирование процессов конечному пользователю (бизнес-аналитику). Это позволяет снять нагрузку с разработчиков. А возможность видеть и самим с легкостью менять свои процессы очень привлекательна для клиентов.

Таким образом, если актуально хотя бы одно из выше перечисленных требований, следует рассмотреть WF как возможный вариант реализации алгоритма/процесса.

Ознакомительный пример

В качестве ознакомительного примера использования WF я как раз и реализую Workflow процесс, который ответит на вопрос о целесообразности использования WF.
1. Создаю новый проект IsWWFUsefullSample используя шаблон Blank Solution:



2. Добавляю новый проект IsWWFUsefullSample.Activities используя шаблон Activity Designer Library:



3.  Удаляю сущеcтвующий файл ActivityDesigner1.xaml и добавляю новый элемент  используя шаблон Activity:



4. Открываю Activity в дизайнере и добавляю необходимые параметры типа Boolean:

— три входящих параметра соответствующих нашим критериям: IsLongRunning, IsChangeable, IsDesignerNecessary;

— один исходящий параметр для возврата результата: Result.

Стоит упомянуть, что на данный момент для описания выражений и типов внутри Workflow Activity можно использовать только синтаксис VB.Net. Обещают добавить поддержку С#.



5. Для анализа входящих праметров использую три вложенных If Activities (Toolbox -> Control Flow -> If), хотя конечно можно обойтись и одним. Для присвоения результата использую Assign Activity (Toolbox -> Primitives -> Assign). В итоге получается следующий алгоритм:



6. Workflow процесс готов. Для его использования добавляю новое приложение IsWWFUsefullSample.TestClient  на основании шаблона Workflow Console Application:




7. Удаляю файл Workflow1.xaml.

8. Добавляю ссылку на проект IsWWFUsefullSample.Activities.



9. Реализую Main метод. Он предлагает пользователю ответить на три вопроса, запускает процесс Workflow с полученными исходными данными и выводит результат вычисления.

// ==============================================================
// <copyright file="Program.cs" company="The World as a Workflow">
//     Copyright (c) The World as a Workflow. All rights reserved.
// </copyright>
// <author>Alexander Nechyporenko</author>
// <date>2011-07-12</date>
// ==============================================================

namespace IsWWFUsefullSample.TestClient
{
    using System;
    using System.Activities;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using IsWWFUsefullSample.Activities;

    /// <summary>
    /// Console program class.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Program starting point.
        /// </summary>
        /// <param name="args">Program parameters.</param>
        public static void Main(string[] args)
        {
            // Question answers
            const string Yes = "yes";
            const string No = "no";
            var answers = new List<string> { Yes, No };

            // Create new activity instance
            var activity = new IsWWFUsefull();
            var parameters = new Dictionary<string, object>();

            do
            {
                Console.WriteLine("Please, answer following questions to determine necessity of using WWF.");
                Console.WriteLine();

                // Read activity input parameters
                parameters["IsLongRunning"] = ReadAnswer("Is process/algorithm long running?", answers) == Yes;
                parameters["IsChangeable"] = ReadAnswer("Is process/algorithm frequently changed?", answers) == Yes;
                parameters["IsDesignerNecessary"] =
                    ReadAnswer("Do you need a visual designer for your process/algorithm?", answers) == Yes;

                // Execute activity
                var result = WorkflowInvoker.Invoke(activity, parameters);

                // Show result
                Console.WriteLine();
                if ((bool)result["Result"])
                {
                    Console.WriteLine("Use WWF!");
                }
                else
                {
                    Console.WriteLine("You don't need WWF but still can use it if you like it :).");
                }
            Console.WriteLine("---------------------------------------------------------------------");
                Console.WriteLine();
            }
            while (ReadAnswer("Do you want to proceed?", answers) == Yes);

            return;
        }

        /// <summary>
        /// Read answer from console.
        /// </summary>
        /// <param name="question">Question text.</param>
        /// <param name="answers">A list of posible</param>
        /// <returns>Answer text.</returns>
        private static string ReadAnswer(string question, IList<string> answers)
        {
            // Prepare answers prompting string
            var answersString = new StringBuilder();
            for (var i = 0; i < answers.Count; i++)
            {
                answersString.AppendFormat(i == 0 ? "{0}" : "/{0}", answers[i]);
            }

            // Read and validate the answer
            var text = string.Empty;
            var answer = string.Empty;
            do
            {
                if (!string.IsNullOrEmpty(text))
                {
                    Console.WriteLine(
                        string.Format("'{0}' doesn't belong to list of posible answers: '{1}'.", text, answersString));
                }

                Console.Write(string.Format("{0} ({1}): ", question, answersString));

                text = Console.ReadLine();
                answer = answers.Where(a => a == text.ToLower()).FirstOrDefault();
            }
            while (answer == null);

            return answer;
        }
    }
}


10. Запускаю и тестирую приложение:



Исходники проекта можно загрузить здесь.

Всем удачных архитектурных решений и приятного кодирования!

Tags:
Hubs:
+26
Comments36

Articles