Как разместить параллельно несколько версий рабочего процесса

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

В этом разделе

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

Примечание.

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

Создание копии проекта NumberGuessWorkflowActivities

  1. Откройте решение WF45GettingStartedTutorial в Visual Studio 2012, если оно не открыто.

  2. Чтобы построить решение, нажмите CTRL+SHIFT+B.

  3. Закройте решение WF45GettingStartedTutorial.

  4. Откройте проводник Windows и перейдите в папку, где находятся файл решения и папки проекта.

  5. Создайте папку с именем PreviousVersions в той же папке, что и NumberGuessWorkflowHost и NumberGuessWorkflowActivities. Эта папка служит для хранения сборок, содержащих различные версии рабочих процессов, которые используются на последующих шагах учебника.

  6. Перейдите в папку NumberGuessWorkflowActivities\bin\debug (или bin\release в зависимости от параметров проекта). Скопируйте NumberGuessWorkflowActivities.dll и вставьте его в папку PreviousVersions .

  7. Переименуйте NumberGuessWorkflowActivities.dll в папке PreviousVersions в NumberGuessWorkflowActivities_v1.dll.

    Примечание.

    Шаги в этом разделе демонстрируют один способ управления сборками, которые используются для хранения нескольких версий рабочих процессов. Также можно использовать другие методы, такие как строгое наименование сборок и их регистрация в глобальном кэше сборок (GAC).

  8. Создайте новую папку с именем NumberGuessWorkflowActivities_du в той же папке, что и NumberGuessWorkflowActivities, а также только что добавленную папку PreviousVersions, а также скопируйте все файлы и вложенные папки из папки NumberGuessWorkflowActivities в новую папку NumberGuessWorkflowActivities_du. Эта резервная копия проекта для начальной версии действий используется в разделе "Практическое руководство. Обновление определения выполняющегося экземпляра рабочего процесса".

  9. Повторно откройте решение WF45GettingStartedTutorial в Visual Studio 2012.

Обновление рабочих процессов

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

Обновление рабочего процесса StateMachine

  1. В Обозреватель решений в проекте NumberGuessWorkflowActivities дважды щелкните StateMachineNumberGuesSWorkflow.xaml.

  2. Дважды щелкните неправильный переход на компьютере состояния.

  3. Обновите Text крайнего левого WriteLine в действии If.

    Guess & " is too low."
    
    Guess + " is too low."
    
  4. Обновите Text крайнего правого WriteLine в действии If.

    Guess & " is too high."
    
    Guess + " is too high."
    
  5. Вернитесь к общему представлению компьютера состояния в конструкторе рабочих процессов, щелкнув StateMachine в области навигации в верхней части конструктора рабочих процессов.

  6. Дважды щелкните переход "Угадывание правильно" на компьютере состояния.

  7. Перетащите действие WriteLine из раздела "Примитивы" панели элементов и удалите его в действие drop Action здесь метка перехода.

  8. В поле свойств Text введите следующее выражение.

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

Обновление рабочего процесса блок-схемы

  1. В Обозреватель решений в проекте NumberGuessWorkflowActivities дважды щелкните FlowchartNumberGuessWorkflow.xaml.

  2. Обновите Text крайнего левого действия WriteLine.

    Guess & " is too low."
    
    Guess + " is too low."
    
  3. Обновите Text крайнего правого действия WriteLine.

    Guess & " is too high."
    
    Guess + " is too high."
    
  4. Перетащите действие WriteLine из раздела "Примитивы" панели элементов и удалите его в точку True падения действия самого верхнего FlowDecisionуровня. Действие WriteLine добавляется к блок-схеме и связывается с действием TrueFlowDecision.

  5. В поле свойств Text введите следующее выражение.

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

Обновление последовательного рабочего процесса

  1. В Обозреватель решений в проекте NumberGuessWorkflowActivities дважды щелкните sequentialNumberGuessWorkflow.xaml.

  2. Обновите Text крайнего левого WriteLine в действии If.

    Guess & " is too low."
    
    Guess + " is too low."
    
  3. Обновите Text крайнего правого действия WriteLine в действии If.

    Guess & " is too high."
    
    Guess + " is too high."
    
  4. Перетащите действие WriteLine из раздела "Примитивы" панели элементов и удалите его после действия DoTime, чтобы строка записи была окончательной в корневом Sequence действии.

  5. В поле свойств Text введите следующее выражение.

    Guess & " is correct. You guessed it in " & Turns & " turns."
    
    Guess + " is correct. You guessed it in " + Turns + " turns."
    

Обновление WorkflowVersionMap для включения предыдущих версий рабочих процессов

  1. Дважды щелкните WorkflowVersionMap.cs (или WorkflowVersionMap.vb) в проекте NumberGuessWorkflowHost , чтобы открыть его.

  2. Добавьте следующие инструкции using (или Imports) в начало файла с другими инструкциями using (или Imports).

    Imports System.Reflection
    Imports System.IO
    
    using System.Reflection;
    using System.IO;
    
  3. Добавьте три новых идентификатора рабочих процессов непосредственно под тремя существующими объявлениями идентификаторов рабочих процессов. Эти новые идентификаторы рабочих процессов v1 будут использоваться для получения правильных определений рабочих процессов перед выполнением обновлений.

    'Current version identities.
    Public StateMachineNumberGuessIdentity As WorkflowIdentity
    Public FlowchartNumberGuessIdentity As WorkflowIdentity
    Public SequentialNumberGuessIdentity As WorkflowIdentity
    
    'v1 Identities.
    Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity
    Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity
    Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity
    
    // Current version identities.
    static public WorkflowIdentity StateMachineNumberGuessIdentity;
    static public WorkflowIdentity FlowchartNumberGuessIdentity;
    static public WorkflowIdentity SequentialNumberGuessIdentity;
    
    // v1 identities.
    static public WorkflowIdentity StateMachineNumberGuessIdentity_v1;
    static public WorkflowIdentity FlowchartNumberGuessIdentity_v1;
    static public WorkflowIdentity SequentialNumberGuessIdentity_v1;
    
  4. В конструкторе WorkflowVersionMap обновите свойство Version трех текущих идентификаторов рабочих процессов до 2.0.0.0.

    'Add the current workflow version identities.
    StateMachineNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "StateMachineNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    FlowchartNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "FlowchartNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    SequentialNumberGuessIdentity = New WorkflowIdentity With
    {
        .Name = "SequentialNumberGuessWorkflow",
        .Version = New Version(2, 0, 0, 0)
    }
    
    map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow())
    map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow())
    map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow())
    
    // Add the current workflow version identities.
    StateMachineNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "StateMachineNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    FlowchartNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "FlowchartNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    SequentialNumberGuessIdentity = new WorkflowIdentity
    {
        Name = "SequentialNumberGuessWorkflow",
        // Version = new Version(1, 0, 0, 0),
        Version = new Version(2, 0, 0, 0)
    };
    
    map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow());
    map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow());
    map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow());
    

    Код, который добавляет текущие версии рабочих процессов в словарь, использует текущие версии, которые указаны в проекте, чтобы код, который инициализирует определения рабочего процесса, не нужно было обновлять.

  5. Добавьте следующий код в конструктор сразу после кода, добавляющего текущие версии в словарь.

    'Initialize the previous workflow version identities.
    StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "StateMachineNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "FlowchartNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With
    {
        .Name = "SequentialNumberGuessWorkflow",
        .Version = New Version(1, 0, 0, 0)
    }
    
    // Initialize the previous workflow version identities.
    StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "StateMachineNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    
    FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "FlowchartNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    
    SequentialNumberGuessIdentity_v1 = new WorkflowIdentity
    {
        Name = "SequentialNumberGuessWorkflow",
        Version = new Version(1, 0, 0, 0)
    };
    

    Эти удостоверения рабочих процессов связаны с первоначальными версиями соответствующих определений рабочих процессов.

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

    'Add the previous version workflow identities to the dictionary along with
    'the corresponding workflow definitions loaded from the v1 assembly.
    'Assembly.LoadFile requires an absolute path so convert this relative path
    'to an absolute path.
    Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"
    v1AssemblyPath = Path.GetFullPath(v1AssemblyPath)
    Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath)
    
    map.Add(StateMachineNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
    map.Add(SequentialNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
    map.Add(FlowchartNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
    
    // Add the previous version workflow identities to the dictionary along with
    // the corresponding workflow definitions loaded from the v1 assembly.
    // Assembly.LoadFile requires an absolute path so convert this relative path
    // to an absolute path.
    string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll";
    v1AssemblyPath = Path.GetFullPath(v1AssemblyPath);
    Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath);
    
    map.Add(StateMachineNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
    map.Add(SequentialNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
    map.Add(FlowchartNumberGuessIdentity_v1,
        v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
    

    Ниже приведен полный список для обновленного класса WorkflowVersionMap.

    Public Module WorkflowVersionMap
        Dim map As Dictionary(Of WorkflowIdentity, Activity)
    
        'Current version identities.
        Public StateMachineNumberGuessIdentity As WorkflowIdentity
        Public FlowchartNumberGuessIdentity As WorkflowIdentity
        Public SequentialNumberGuessIdentity As WorkflowIdentity
    
        'v1 Identities.
        Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity
        Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity
        Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity
    
        Sub New()
            map = New Dictionary(Of WorkflowIdentity, Activity)
    
            'Add the current workflow version identities.
            StateMachineNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "StateMachineNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            FlowchartNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "FlowchartNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            SequentialNumberGuessIdentity = New WorkflowIdentity With
            {
                .Name = "SequentialNumberGuessWorkflow",
                .Version = New Version(2, 0, 0, 0)
            }
    
            map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow())
            map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow())
            map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow())
    
            'Initialize the previous workflow version identities.
            StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "StateMachineNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "FlowchartNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With
            {
                .Name = "SequentialNumberGuessWorkflow",
                .Version = New Version(1, 0, 0, 0)
            }
    
            'Add the previous version workflow identities to the dictionary along with
            'the corresponding workflow definitions loaded from the v1 assembly.
            'Assembly.LoadFile requires an absolute path so convert this relative path
            'to an absolute path.
            Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"
            v1AssemblyPath = Path.GetFullPath(v1AssemblyPath)
            Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath)
    
            map.Add(StateMachineNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow"))
    
            map.Add(SequentialNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow"))
    
            map.Add(FlowchartNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
        End Sub
    
        Public Function GetWorkflowDefinition(identity As WorkflowIdentity) As Activity
            Return map(identity)
        End Function
    
        Public Function GetIdentityDescription(identity As WorkflowIdentity) As String
            Return identity.ToString()
        End Function
    End Module
    
    public static class WorkflowVersionMap
    {
        static Dictionary<WorkflowIdentity, Activity> map;
    
        // Current version identities.
        static public WorkflowIdentity StateMachineNumberGuessIdentity;
        static public WorkflowIdentity FlowchartNumberGuessIdentity;
        static public WorkflowIdentity SequentialNumberGuessIdentity;
    
        // v1 identities.
        static public WorkflowIdentity StateMachineNumberGuessIdentity_v1;
        static public WorkflowIdentity FlowchartNumberGuessIdentity_v1;
        static public WorkflowIdentity SequentialNumberGuessIdentity_v1;
    
        static WorkflowVersionMap()
        {
            map = new Dictionary<WorkflowIdentity, Activity>();
    
            // Add the current workflow version identities.
            StateMachineNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "StateMachineNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            FlowchartNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "FlowchartNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            SequentialNumberGuessIdentity = new WorkflowIdentity
            {
                Name = "SequentialNumberGuessWorkflow",
                // Version = new Version(1, 0, 0, 0),
                Version = new Version(2, 0, 0, 0)
            };
    
            map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow());
            map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow());
            map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow());
    
            // Initialize the previous workflow version identities.
            StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "StateMachineNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "FlowchartNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            SequentialNumberGuessIdentity_v1 = new WorkflowIdentity
            {
                Name = "SequentialNumberGuessWorkflow",
                Version = new Version(1, 0, 0, 0)
            };
    
            // Add the previous version workflow identities to the dictionary along with
            // the corresponding workflow definitions loaded from the v1 assembly.
            // Assembly.LoadFile requires an absolute path so convert this relative path
            // to an absolute path.
            string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll";
            v1AssemblyPath = Path.GetFullPath(v1AssemblyPath);
            Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath);
    
            map.Add(StateMachineNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity);
    
            map.Add(SequentialNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity);
    
            map.Add(FlowchartNumberGuessIdentity_v1,
                v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
        }
    
        public static Activity GetWorkflowDefinition(WorkflowIdentity identity)
        {
            return map[identity];
        }
    
        public static string GetIdentityDescription(WorkflowIdentity identity)
        {
            return identity.ToString();
        }
    }
    

Построение и запуск приложения

  1. Нажмите сочетание клавиш CTRL+SHIFT+B, чтобы построить приложение, а затем сочетание клавиш CTRL+F5 для его запуска.

  2. Запустите новый рабочий процесс, нажав кнопку "Создать игру". Версия рабочего процесса отображается под окном состояния и отображает обновленную версию из связанного WorkflowIdentity. Запишите InstanceId, чтобы просмотреть файл отслеживания для рабочего процесса после его завершения, а затем вводите предположения, пока игра не завершится. Обратите внимание на то, что догадка пользователя отображается в окне состояния в зависимости от обновлений действий WriteLine.

    Please enter a number between 1 and 10
    5 is too high.
    Please enter a number between 1 and 10
    3 is too high.
    Please enter a number between 1 and 10
    1 is too low.
    Please enter a number between 1 and 10
    Congratulations, you guessed the number in 4 turns.
    

    Примечание.

    Отображается обновленный текст из действий WriteLine, но выходные данные последнего действия WriteLine, которое было добавлено в этом разделе, отсутствуют. Это происходит потому, что окно состояния обновляется обработчиком PersistableIdle. Поскольку рабочий процесс завершается, а не переходит в состояние бездействия после окончательного действия, обработчик PersistableIdle не вызывается. Однако похожее сообщение отображается обработчиком Completed в окне состояния. Если необходимо, код можно добавить в обработчик Completed, чтобы извлечь текст из StringWriter и показать его в окне состояния.

  3. Откройте Windows Обозреватель и перейдите в папку NumberGuessWorkflowHost\bin\debug (или bin\release в зависимости от параметров проекта) и откройте файл отслеживания с помощью Блокнот, соответствующего завершенным рабочим процессам. Если вы не заметитеInstanceId, можно определить правильный файл отслеживания с помощью сведений об изменении даты в Windows Обозреватель.

    Please enter a number between 1 and 10
    5 is too high.
    Please enter a number between 1 and 10
    3 is too high.
    Please enter a number between 1 and 10
    1 is too low.
    Please enter a number between 1 and 10
    2 is correct. You guessed it in 4 turns.
    

    Обновленные выходные данные WriteLine содержатся в файле отслеживания, в том числе выходные данные трассировки действия WriteLine, добавленного в этом разделе.

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

    На следующем шаге: обновление определения выполняющегося экземпляра рабочего процесса обновляется, v1 чтобы они содержали новые функциональные возможности в качестве v2 экземпляров.