Динамическое обновление

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

Динамическое обновление

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

  1. Подготовка определения рабочего процесса для динамического обновления

  2. Обновите определение рабочего процесса, чтобы отразить необходимые изменения

  3. Создание карты обновления

  4. Применение карты обновления к требуемым экземплярам рабочих процессов

Примечание.

Обратите внимание, что шаги 1–3, которые охватывают создание схемы обновления, могут быть выполнены независимо от применения обновления. Распространенный сценарий, который разработчик рабочего процесса создаст карту обновления в автономном режиме, а затем администратор будет применять обновление позже.

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

Подготовка определения рабочего процесса для динамического обновления

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

Чтобы подготовить рабочий процесс языка XAML для динамического обновления, его можно загрузить в ActivityBuilder, а затем передать ActivityBuilder в DynamicUpdateServices.PrepareForUpdate.

Примечание.

Дополнительные сведения о работе с сериализованными рабочими процессами и ActivityBuilderсм. в разделе Сериализация рабочих процессов и действий в XAML и из нее.

В следующем примере определение MortgageWorkflow (состоящее из Sequence с несколькими дочерними действиями) загружается в ActivityBuilder, а затем подготавливается для динамического обновления. После возврата из метода ActivityBuilder содержит исходное определение рабочего процесса и копию.

// Load the MortgageWorkflow definition from Xaml into
// an ActivityBuilder.
XamlXmlReaderSettings readerSettings = new XamlXmlReaderSettings()
{
    LocalAssembly = Assembly.GetExecutingAssembly()
};

XamlXmlReader xamlReader = new XamlXmlReader(@"C:\WorkflowDefinitions\MortgageWorkflow.xaml",
    readerSettings);

ActivityBuilder ab = XamlServices.Load(
    ActivityXamlServices.CreateBuilderReader(xamlReader)) as ActivityBuilder;

// Prepare the workflow definition for dynamic update.
DynamicUpdateServices.PrepareForUpdate(ab);

Обновите определение рабочего процесса, чтобы отразить необходимые изменения

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

// Make desired changes to the definition. In this example, we are
// inserting a new VerifyAppraisal activity as the 3rd child of the root Sequence.
VerifyAppraisal va = new VerifyAppraisal
{
    Result = new VisualBasicReference<bool>("LoanCriteria")
};

// Get the Sequence that makes up the body of the workflow.
Sequence s = ab.Implementation as Sequence;

// Insert the new activity into the Sequence.
s.Activities.Insert(2, va);

Создание карты обновления

После изменения подготовленного к обновлению определения рабочего процесса можно создать схему обновления. Для создания схемы динамического обновления вызывается метод DynamicUpdateServices.CreateUpdateMap. Этот метод возвращает DynamicUpdateMap - объект, содержащий сведения, необходимые среде выполнения для изменения сохраненного экземпляра рабочего процесса, чтобы тот можно было загрузить и возобновить вместе с новым определением рабочего процесса. В следующем примере создается динамическая схема для измененного определения MortgageWorkflow из предыдущего примера.

// Create the update map.
DynamicUpdateMap map = DynamicUpdateServices.CreateUpdateMap(ab);

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

// Serialize the update map to a file.
DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
using (FileStream fs = System.IO.File.Open(@"C:\WorkflowDefinitions\MortgageWorkflow.map", FileMode.Create))
{
    serializer.WriteObject(fs, map);
}

Когда DynamicUpdateServices.CreateUpdateMap возвращает управление, скопированное определение рабочего процесса и другая информация о динамическом обновлении, добавленная при вызове DynamicUpdateServices.PrepareForUpdate, удаляются, а измененное определение рабочего процесса готово к сохранению, после чего его можно будет использовать при восстановлении обновленных экземпляров рабочего процесса. В следующем примере определение измененного рабочего процесса сохраняется в MortgageWorkflow_v1.1.xaml.

// Save the modified workflow definition.
StreamWriter sw = File.CreateText(@"C:\WorkflowDefinitions\MortgageWorkflow_v1.1.xaml");
XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(sw, new XamlSchemaContext()));
XamlServices.Save(xw, ab);
sw.Close();

Применение карты обновления к требуемым экземплярам рабочих процессов

Применение схемы обновления можно выполнить в любое время после ее создания. Это можно сделать немедленно с помощью экземпляра DynamicUpdateMap, который был возвращен методом DynamicUpdateServices.CreateUpdateMap, или позднее с помощью сохраненной копии схемы обновления. Для обновления экземпляра рабочего процесса загрузите его в объект WorkflowApplicationInstance с помощью метода WorkflowApplication.GetInstance. Далее создайте WorkflowApplication с помощью обновленного определения рабочего процесса и нужного метода WorkflowIdentity. Этот идентификатор WorkflowIdentity может отличаться от того, что был использован для сохранения исходного рабочего процесса, и, как правило, это делается для отражения того, что сохраненный экземпляр был изменен. Сразу после создания WorkflowApplication загружается с помощью перегрузки WorkflowApplication.Load, принимающей DynamicUpdateMap, затем выгружается посредством вызова WorkflowApplication.Unload. При этом будет произведено динамическое обновление и обновленный экземпляр рабочего процесса будет сохранен.

// Load the serialized update map.
DynamicUpdateMap map;
using (FileStream fs = File.Open(@"C:\WorkflowDefinitions\MortgageWorkflow.map", FileMode.Open))
{
    DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
    object updateMap = serializer.ReadObject(fs);
    if (updateMap == null)
    {
        throw new ApplicationException("DynamicUpdateMap is null.");
    }

    map = (DynamicUpdateMap)updateMap;
}

// Retrieve a list of workflow instance ids that corresponds to the
// workflow instances to update. This step is the responsibility of
// the application developer.
List<Guid> ids = GetPersistedWorkflowIds();
foreach (Guid id in ids)
{
    // Get a proxy to the persisted workflow instance.
    SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(connectionString);
    WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(id, store);

    // If desired, you can inspect the WorkflowIdentity of the instance
    // using the DefinitionIdentity property to determine whether to apply
    // the update.
    Console.WriteLine(instance.DefinitionIdentity);

    // Create a workflow application. You must specify the updated workflow definition, and
    // you may provide an updated WorkflowIdentity if desired to reflect the update.
    WorkflowIdentity identity = new WorkflowIdentity
    {
        Name = "MortgageWorkflow v1.1",
        Version = new Version(1, 1, 0, 0)
    };

    // Load the persisted workflow instance using the updated workflow definition
    // and with an updated WorkflowIdentity. In this example the MortgageWorkflow class
    // contains the updated definition.
    WorkflowApplication wfApp = new WorkflowApplication(new MortgageWorkflow(), identity);

    // Apply the dynamic update on the loaded instance.
    wfApp.Load(instance, map);

    // Unload the updated instance.
    wfApp.Unload();
}

Возобновление работы обновленного экземпляра рабочего процесса

Сразу после применения динамического обновления можно возобновлять работу экземпляра рабочего процесса. Обратите внимание, что следует использовать новое обновленное определение и WorkflowIdentity.

Примечание.

Дополнительные сведения о работе с WorkflowApplication ими см. в разделе "Использование WorkflowIdentity и WorkflowIdentityуправление версиями".

В следующем примере рабочий процесс MortgageWorkflow_v1.1.xaml из предыдущего примера был скомпилирован, и он загружается и возобновляется с помощью обновленного определения рабочего процесса.

// Load the persisted workflow instance using the updated workflow definition
// and updated WorkflowIdentity.
WorkflowIdentity identity = new WorkflowIdentity
{
    Name = "MortgageWorkflow v1.1",
    Version = new Version(1, 1, 0, 0)
};

WorkflowApplication wfApp = new WorkflowApplication(new MortgageWorkflow(), identity);

// Configure persistence and desired workflow event handlers.
// (Omitted for brevity.)
ConfigureWorkflowApplication(wfApp);

// Load the persisted workflow instance.
wfApp.Load(InstanceId);

// Resume the workflow.
// wfApp.ResumeBookmark(...);