Share via


Serialize fluxos de trabalho e atividades de e para XAML

Além de serem construídas em tipos contidos nos assemblies, as definições de fluxo de trabalho também podem ser serializadas para XAML. Essas definições serializadas possam ser recarregadas para edição ou inspeção, podem ser passadas para um sistema de compilação ou carregadas e chamadas. Este tópico fornece uma visão geral de como serializar definições de fluxo de trabalho e trabalhar com definições de fluxo de trabalho XAML.

Trabalhar com definições de fluxo de trabalho XAML

Para criar uma definição de fluxo de trabalho para serialização, a classe ActivityBuilder é usada. Criar um ActivityBuilder é bem semelhante a criar um DynamicActivity. Todos os argumentos desejados são especificados, e as atividades que constituem o comportamento são configuradas. No exemplo a seguir, uma atividade Add é criada e usa dois argumentos de entrada, adiciona-os juntos e retorna o resultado. Como essa atividade retorna um resultado, a classe genérica ActivityBuilder<TResult> é usada.

ActivityBuilder<int> ab = new ActivityBuilder<int>();
ab.Name = "Add";
ab.Properties.Add(new DynamicActivityProperty { Name = "Operand1", Type = typeof(InArgument<int>) });
ab.Properties.Add(new DynamicActivityProperty { Name = "Operand2", Type = typeof(InArgument<int>) });
ab.Implementation = new Sequence
{
    Activities =
    {
        new WriteLine
        {
            Text = new VisualBasicValue<string>("Operand1.ToString() + \" + \" + Operand2.ToString()")
        },
        new Assign<int>
        {
            To = new ArgumentReference<int> { ArgumentName = "Result" },
            Value = new VisualBasicValue<int>("Operand1 + Operand2")
        }
    }
};

Cada uma das instâncias DynamicActivityProperty representa um dos argumentos de entrada para o fluxo de trabalho, e Implementation contém as atividades que compõem a lógica do fluxo de trabalho. Observe que as expressões de valor r neste exemplo são expressões do Visual Basic. As expressões lambda não são serializáveis para XAML a menos que Convert seja usado. Se os fluxos de trabalho serializados forem destinados para serem abertos ou editados no designer de fluxo de trabalho, as expressões do Visual Basic deverão ser usadas. Para obter mais informações, consulte Criação de fluxos de trabalho, atividades e expressões usando código imperativo.

Para serializar a definição de fluxo de trabalho representada pela instância ActivityBuilder para XAML, use ActivityXamlServices para criar um XamlWriter e, em seguida, use XamlServices para serializar a definição de fluxo de trabalho usando o XamlWriter. ActivityXamlServices tem métodos para mapear instâncias ActivityBuilder para e de XAML, e para carregar fluxos de trabalho XAML e retornar um DynamicActivity que pode ser chamado. No exemplo a seguir, a instância ActivityBuilder do exemplo anterior é serializada para uma cadeia de caracteres, e salva em um arquivo.

// Serialize the workflow to XAML and store it in a string.
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(tw, new XamlSchemaContext()));
XamlServices.Save(xw, ab);
string serializedAB = sb.ToString();

// Display the XAML to the console.
Console.WriteLine(serializedAB);

// Serialize the workflow to XAML and save it to a file.
StreamWriter sw = File.CreateText(@"C:\Workflows\add.xaml");
XamlWriter xw2 = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(sw, new XamlSchemaContext()));
XamlServices.Save(xw2, ab);
sw.Close();

O exemplo a seguir representa o fluxo de trabalho serializado.

<Activity
  x:TypeArguments="x:Int32"
  x:Class="Add"
  xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <x:Members>
    <x:Property Name="Operand1" Type="InArgument(x:Int32)" />
    <x:Property Name="Operand2" Type="InArgument(x:Int32)" />
  </x:Members>
  <Sequence>
    <WriteLine Text="[Operand1.ToString() + " + " + Operand2.ToString()]" />
    <Assign x:TypeArguments="x:Int32" Value="[Operand1 + Operand2]">
      <Assign.To>
        <OutArgument x:TypeArguments="x:Int32">
          <ArgumentReference x:TypeArguments="x:Int32" ArgumentName="Result" />
          </OutArgument>
      </Assign.To>
    </Assign>
  </Sequence>
</Activity>

Para carregar um fluxo de trabalho serializado, use o método ActivityXamlServicesLoad. Isso utiliza a definição de fluxo de trabalho serializado e retorna um DynamicActivity que representa a definição de fluxo de trabalho. Observe que o XAML não é desserializado até que CacheMetadata seja chamado no corpo do DynamicActivity durante o processo de validação. Se a validação não for chamada explicitamente, ela será executada quando o fluxo de trabalho for chamado. Se a definição de fluxo de trabalho XAML for inválida, uma exceção ArgumentException será gerada. Todas as exceções geradas de CacheMetadata escapam da chamada para Validate e devem ser tratadas pelo chamador. No exemplo a seguir, o fluxo de trabalho serializado do exemplo anterior é carregado e é chamado usando WorkflowInvoker.

// Load the workflow definition from XAML and invoke it.
DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB)) as DynamicActivity<int>;
Dictionary<string, object> wfParams = new Dictionary<string, object>
{
    { "Operand1", 25 },
    { "Operand2", 15 }
};

int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);

Quando esse fluxo de trabalho é chamado, a seguinte saída é exibida no console.

25 + 15
40

Observação

Para obter mais informações sobre como invocar fluxos de trabalho com argumentos de entrada e saída, consulte Usando WorkflowInvoker e WorkflowApplication e Invoke.

Se o fluxo de trabalho serializado contiver expressões C#, uma instância ActivityXamlServicesSettings com sua propriedade CompileExpressions definida como true deverá ser passada como parâmetro para ActivityXamlServices.Load, caso contrário, um NotSupportedException será gerado com uma mensagem semelhante à a seguir: O tipo de atividade de expressão 'CSharpValue`1' requer compilação para ser executado. Certifique-se de que o fluxo de trabalho foi compilado.

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB), settings) as DynamicActivity<int>;

Para obter mais informações, confira Expressões em C#.

Uma definição de fluxo de trabalho serializado também pode ser carregada em uma instância ActivityBuilder usando o método ActivityXamlServicesCreateBuilderReader. Depois de um fluxo de trabalho serializado ser carregado em uma instância ActivityBuilder, ele pode ser inspecionado e modificado. Isso é útil para autores do designer do fluxo de trabalho personalizado e fornece um mecanismo para salvar e recarregar definições de fluxo de trabalho durante o processo de design. No exemplo a seguir, a definição do fluxo de trabalho serializado do exemplo anterior é carregada e suas propriedades são inspecionadas.

// Create a new ActivityBuilder and initialize it using the serialized
// workflow definition.
ActivityBuilder<int> ab2 = XamlServices.Load(
    ActivityXamlServices.CreateBuilderReader(
    new XamlXmlReader(new StringReader(serializedAB)))) as ActivityBuilder<int>;

// Now you can continue working with the ActivityBuilder, inspect
// properties, etc...
Console.WriteLine("There are {0} arguments in the activity builder.", ab2.Properties.Count);
foreach (var prop in ab2.Properties)
{
    Console.WriteLine("Name: {0}, Type: {1}", prop.Name, prop.Type);
}