Sérialisation de workflows et d’activités vers et à partir de XAML

Outre le fait d'être compilées en types qui sont contenus dans des assemblys, les définitions de workflow peuvent également être sérialisées en XAML. Ces définitions sérialisées peuvent être rechargées pour la modification ou l'inspection, passées à un système de génération pour la compilation, ou bien chargées et appelées. Cette rubrique fournit une vue d'ensemble de la sérialisation de définitions de workflow et de l'utilisation de définitions de workflow XAML.

Utiliser des définitions de workflows XAML

Pour créer une définition de workflow pour la sérialisation, la classe ActivityBuilder est utilisée. La création d'un ActivityBuilder est très semblable à la création d'un DynamicActivity. Tous les arguments souhaités sont spécifiés, et les activités qui constituent le comportement sont configurées. Dans l’exemple suivant, une activité Add qui prend deux arguments d’entrée est créée, elle les ajoute, puis le résultat. Étant donné que cette activité retourne un résultat, la classe ActivityBuilder<TResult> générique est utilisée.

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")
        }
    }
};

Chacune des instances DynamicActivityProperty représente l'un des arguments d'entrée du workflow, et Implementation contient les activités qui composent la logique du workflow. Notez que les expressions r-value dans cet exemple sont des expressions Visual Basic. Les expressions lambda ne sont pas sérialisables en XAML à moins d’utiliser Convert. Si les workflows sérialisés sont destinés à être ouverts ou modifiés dans le concepteur de workflows, vous devez utiliser des expressions Visual Basic. Pour plus d’informations, consultez Création de workflows, d’activités et d’expressions à l’aide de code impératif.

Pour sérialiser la définition de workflow représentée par l'instance ActivityBuilder en XAML, utilisez ActivityXamlServices de créer XamlWriter, puis utilisez XamlServices pour sérialiser la définition de workflow à l'aide de XamlWriter. ActivityXamlServices comporte des méthodes pour mapper des instances ActivityBuilder vers et à partir du XAML, et pour charger des workflows XAML et retourner un DynamicActivity qui peut être appelé. Dans l’exemple suivant, l’instance ActivityBuilder de l’exemple précédent est sérialisée en chaîne et enregistrée dans un fichier.

// 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();

L'exemple suivant représente le workflow sérialisé.

<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>

Pour charger un workflow sérialisé, utilisez la méthode ActivityXamlServicesLoad. Elle prend la définition de workflow sérialisée et retourne un DynamicActivity qui représente la définition de workflow. Notez que le XAML n’est pas désérialisé tant que CacheMetadata n’est pas appelé sur le corps de DynamicActivity pendant le processus de validation. Si la validation n’est pas appelée explicitement, elle est effectuée lors de l’appel du workflow. Si la définition de workflow XAML n'est pas valide, une exception ArgumentException est levée. Toutes les exceptions levées à partir de CacheMetadata sont soustraites à l'appel à Validate et doivent être gérées par l'appelant. Dans l'exemple suivant, le workflow sérialisé de l'exemple précédent est chargé et appelé à l'aide de 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);

Lorsque ce workflow est appelé, la sortie suivante s'affiche sur la console.

25 + 15
40

Notes

Pour plus d’informations sur l’appel de workflows avec des arguments d’entrée et de sortie, consultez Utilisation de WorkflowInvoker et WorkflowApplication et Invoke.

Si le workflow sérialisé contient des expressions C#, une instance ActivityXamlServicesSettings avec sa propriété CompileExpressions définie sur true doit être passée en tant que paramètre à ActivityXamlServices.Load, sinon, une NotSupportedException sera levée avec un message similaire à ce qui suit : Le type d’activité d’expression 'CSharpValue'1' doit être compilé pour s’exécuter. Vérifiez que le workflow a été compilé.

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

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

Pour plus d’informations, consultez Expressions C#.

Une définition de workflow sérialisée peut également être chargée dans une instance ActivityBuilder à l’aide de la méthode ActivityXamlServicesCreateBuilderReader. Une fois qu’un workflow sérialisé est chargé dans une instance ActivityBuilder, il peut être inspecté et modifié. Cette possibilité, qui est utile pour les auteurs de concepteurs de workflow personnalisés, fournit un mécanisme permettant d'enregistrer et de recharger des définitions de workflow pendant le processus de conception. Dans l'exemple suivant, la définition de workflow sérialisée de l'exemple précédent est chargée et ses propriétés sont inspectées.

// 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);
}