XAML との間のワークフローおよびアクティビティのシリアル化

ワークフロー定義は、アセンブリに含まれる型にコンパイルされるほか、XAML にシリアル化することもできます。 これらのシリアル化された定義は、編集や検査のために再度読み込んだり、コンパイルのためにビルド システムに渡したり、読み込んで呼び出したりすることができます。 このトピックでは、ワークフロー定義のシリアル化と XAML ワークフロー定義の使用に関する概要について説明します。

XAML ワークフロー定義の使用

シリアル化するワークフロー定義を作成するには、ActivityBuilder クラスを使用します。 ActivityBuilder の作成は、DynamicActivity の作成とほとんど同じです。 目的の引数を指定し、動作を構成するアクティビティを構成します。 次の例では、2 つの入力引数を受け取り、それらを加算して結果を返す Add アクティビティを作成しています。 このアクティビティは結果を返すため、ジェネリック ActivityBuilder<TResult> クラスが使用されています。

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

それぞれの DynamicActivityProperty インスタンスでワークフローへの入力引数を 1 つずつ表し、Implementation にワークフローのロジックを構成するアクティビティが格納されています。 この例では、右辺値の式が Visual Basic 式であることに注意してください。 Convert を使用しないと、ラムダ式は XAML 形式にシリアル化できません。 シリアル化されたワークフローをワークフロー デザイナーで開くか編集することを目的としている場合は、Visual Basic 式を使用する必要があります。 詳細については、「命令型コードを使用してワークフロー、アクティビティ、および式を作成する方法」を参照してください。

XAML への ActivityBuilder インスタンスで表されるワークフロー定義を XAML 形式にシリアル化するには、ActivityXamlServices を使用して XamlWriter を作成した後、その XamlServices を使用することで、XamlWriter を使用してワークフロー定義をシリアル化します。 ActivityXamlServices には、ActivityBuilder インスタンスを XAML との間でマッピングしたり、XAML ワークフローを読み込んで、呼び出し可能な DynamicActivity を返したりするメソッドがあります。 次の例では、前の例の ActivityBuilder インスタンスを文字列にシリアル化し、ファイルに保存しています。

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

シリアル化されたワークフローの例を次に示します。

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

シリアル化されたワークフローを読み込むには、ActivityXamlServicesLoad メソッドを使用します。 このメソッドは、シリアル化されたワークフロー定義を受け取り、ワークフロー定義を表す DynamicActivity を返します。 検証プロセス中に CacheMetadata の本体で DynamicActivity が呼び出されるまでは、XAML は逆シリアル化されないことに注意してください。 検証が明示的に呼び出されない場合は、ワークフローが呼び出されたときに実行されます。 XAML ワークフロー定義が無効な場合、ArgumentException 例外がスローされます。 CacheMetadata からスローされる例外は、Validate への呼び出しからエスケープされ、呼び出し元によって処理される必要があります。 次の例では、前の例のシリアル化されたワークフローを読み込み、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);

このワークフローが呼び出されると、次の出力がコンソールに表示されます。

25 + 15
40

注意

入力と出力の引数を使用してワークフローを呼び出す方法の詳細については、「WorkflowInvoker と WorkflowApplication の使用」と「Invoke」を参照してください。

シリアル化されたワークフローに C# 式が含まれている場合、CompileExpressions プロパティが true に設定されている ActivityXamlServicesSettings インスタンスは、パラメーターとして ActivityXamlServices.Load に渡す必要があります。そうしないと、NotSupportedException がスローされ、次のようなメッセージが表示されます。"Expression Activity 型 'CSharpValue`1' は、実行するためにコンパイルが必要です。ワークフローがコンパイルされていることを確認してください。"

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

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

詳細については、「C# の式」を参照してください。

シリアル化されたワークフロー定義は、ActivityXamlServicesCreateBuilderReader メソッドを使用して ActivityBuilder インスタンスに読み込むこともできます。 シリアル化されたワークフローを ActivityBuilder インスタンスに読み込むと、検査や変更を行えるようになります。 これにより、デザイン プロセス中にワークフロー定義を保存したり再度読み込んだりするためのメカニズムが提供され、カスタム ワークフロー デザイナーを作成するときに役立ちます。 次の例では、前の例のシリアル化されたワークフロー定義を読み込み、そのプロパティを検査しています。

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