C# の式

.NET Framework 4.5 以降では、Windows Workflow Foundation (WF) で C# 式がサポートされています。 Visual Studio 2012 で作成された、.NET Framework 4.5 を対象とする新しい C# ワークフロー プロジェクトでは C# 式が使用され、Visual Basic ワークフロー プロジェクトでは Visual Basic 式が使用されます。 Visual Basic 式を使用する既存の .NET Framework 4 ワークフロー プロジェクトは、プロジェクトの言語に関係なく .NET Framework 4.6.1 に移行することができ、サポートされています。 ここでは、WF での C# 式の概要について説明します。

ワークフローでの C# 式の使用

ワークフロー デザイナーでの C# 式の使用

.NET Framework 4.5 以降では、Windows Workflow Foundation (WF) で C# 式がサポートされています。 Visual Studio 2012 で作成された、.NET Framework 4.5 を対象とする C# ワークフロー プロジェクトでは C# 式が使用され、Visual Basic ワークフロー プロジェクトでは Visual Basic 式が使用されます。 必要な C# 式を指定するには、 [C# の式を入力してください] というラベルの付いたボックスにそれを入力します。 このラベルは、プロパティ ウィンドウ (デザイナーでアクティビティを選択した場合) またはワークフロー デザイナーのアクティビティに表示されます。 次の例では、2 つの WriteLine アクティビティが Sequence の中で NoPersistScope 内に含まれています。

Screenshot that shows an automatically created sequence activity.

Note

C# 式は、Visual Studio でのみサポートされており、再ホストされたワークフロー デザイナーではサポートされていません。 再ホストされたデザイナーでサポートされている WF45 の新機能の詳細については、「再ホストされたワークフロー デザイナーにおける Workflow Foundation 4.5 の新機能のサポート」を参照してください。

下位互換性

.NET Framework 4.6.1 に移行した .NET Framework 4 の既存の C# ワークフロー プロジェクトに含まれる Visual Basic 式はサポートされています。 Visual Basic 式をワークフロー デザイナーで表示すると、既存の Visual Basic 式のテキストは、その Visual Basic 式が有効な C# 構文である場合を除き、"値が XAML で設定されました" に置き換えられます。 Visual Basic 式が有効な C# 構文である場合は、式が表示されます。 Visual Basic 式を C# に更新するには、ワークフロー デザイナーでその式を編集して、対応する C# 式を指定します。 Visual Basic 式を C# に更新する必要はありませんが、ワークフロー デザイナーで式を更新すると、式は C# に変換され、Visual Basic に戻すことができなくなる場合があります。

コード ワークフローでの C# 式の使用

C# 式は、.NET Framework 4.6.1 コード ベースのワークフローでサポートされていますが、ワークフローを呼び出す前に、TextExpressionCompiler.Compile を使用して C# 式をコンパイルする必要があります。 ワークフローの作成者は、CSharpValue を使用して式の右辺値を表し、CSharpReference を使用して式の左辺値を表すことができます。 次の例では、Assign アクティビティに含まれる WriteLine アクティビティと Sequence アクティビティを使用してワークフローを作成します。 CSharpReferenceAssignTo 引数として指定され、式の左辺値を表します。 CSharpValueAssignValue 引数、および WriteLineText 引数として指定され、2 つの式の右辺値を表します。

Variable<int> n = new Variable<int>
{
    Name = "n"
};

Activity wf = new Sequence
{
    Variables = { n },
    Activities =
    {
        new Assign<int>
        {
            To = new CSharpReference<int>("n"),
            Value = new CSharpValue<int>("new Random().Next(1, 101)")
        },
        new WriteLine
        {
            Text = new CSharpValue<string>("\"The number is \" + n")
        }
    }
};

CompileExpressions(wf);

WorkflowInvoker.Invoke(wf);

ワークフローが作成されると、CompileExpressions ヘルパー メソッドを呼び出して C# 式がコンパイルされ、ワークフローが呼び出されます。 次の例は、CompileExpressions メソッドです。

static void CompileExpressions(Activity activity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions.
    string activityName = activity.GetType().ToString();

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = activity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = false
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { activity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRoot(
        activity, compiledExpressionRoot);
}

注意

C# 式がコンパイルされていない場合は、ワークフローが呼び出されたときに NotSupportedException がスローされ、以下のようなメッセージが表示されます。"Expression Activity type 'CSharpValue1' を実行するにはコンパイルが必要です。 ワークフローがコンパイルされていることを確認してください。"

カスタムのコードベースのワークフローで DynamicActivity を使用する場合は、次のコード例に示すように、CompileExpressions メソッドに変更を加える必要があります。

static void CompileExpressions(DynamicActivity dynamicActivity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions. For Dynamic Activities this can be retrieved using the
    // name property , which must be in the form Namespace.Type.
    string activityName = dynamicActivity.Name;

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = dynamicActivity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = true
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { dynamicActivity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
        dynamicActivity, compiledExpressionRoot);
}

動的アクティビティで C# 式をコンパイルする CompileExpressions オーバーロードには、いくつかの相違点があります。

  • CompileExpressions のパラメーターが DynamicActivity です。

  • 型名および名前空間の取得に DynamicActivity.Name プロパティが使用されます。

  • TextExpressionCompilerSettings.ForImplementationtrue に設定されます。

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation の代わりに CompiledExpressionInvoker.SetCompiledExpressionRoot が呼び出されます。

コード内で式を使用する方法の詳細については、「命令型コードを使用してワークフロー、アクティビティ、および式を作成する方法」を参照してください。

XAML ワークフローでの C# 式の使用

C# 式は XAML ワークフローでサポートされています。 コンパイルされた XAML ワークフローは型にコンパイルされ、Loose XAML ワークフローはランタイムによって読み込まれ、ワークフローの実行時にアクティビティ ツリーにコンパイルされます。

コンパイルされた Xaml

C# 式は、コンパイルされた XAML ワークフローでサポートされており、.NET Framework 4.6.1 を対象とする C# ワークフロー プロジェクトの一部として型にコンパイルされます。 コンパイルされた XAML は Visual Studio でワークフローを作成する場合の既定の種類であり、Visual Studio で作成された、.NET Framework 4.6.1 を対象とする C# ワークフロー プロジェクトでは C# 式が使用されます。

Loose Xaml

C# 式は Loose XAML ワークフローでがサポートされています。 Loose XAML ワークフローを読み込んで呼び出すワークフロー ホスト プログラムは、.NET Framework 4.6.1 を対象としている必要があります。また、CompileExpressionstrue (既定値は false) に設定する必要があります。 CompileExpressionstrue に設定するには、ActivityXamlServicesSettings プロパティが CompileExpressions に設定されている true インスタンスを作成し、そのインスタンスを ActivityXamlServices.Load へパラメーターとして渡します。 CompileExpressionstrue に設定されていない場合は、NotSupportedException がスローされ、以下のようなメッセージが表示されます。"Expression Activity type 'CSharpValue1' を実行するには、コンパイルが必要です。 ワークフローがコンパイルされていることを確認してください。"

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

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

XAML ワークフローの操作の詳細については、XAML との間のワークフローとアクティビティのシリアル化に関するページを参照してください。

XAMLX ワークフロー サービスでの C# 式の使用

C# 式は XAMLX ワークフロー サービスでがサポートされています。 ワークフロー サービスが IIS または WAS でホストされている場合、追加の手順は必要ありません。ただし、XAML ワークフロー サービスが自己ホスト型サービスの場合は、C# 式をコンパイルする必要があります。 C# 式を自己ホスト型の XAMLX ワークフロー サービスでコンパイルするには、最初に XAMLX ファイルを WorkflowService に読み込んでから、前の「コード ワークフローでの C# 式の使用」で説明した CompileExpressions メソッドに WorkflowServiceBody を渡します。 次の例では、XAMLX ワークフロー サービスが読み込まれ、C# 式がコンパイルされた後、ワークフロー サービスが開かれて要求を待機します。

// Load the XAMLX workflow service.
WorkflowService workflow1 =
    (WorkflowService)XamlServices.Load(xamlxPath);

// Compile the C# expressions in the workflow by passing the Body to CompileExpressions.
CompileExpressions(workflow1.Body);

// Initialize the WorkflowServiceHost.
var host = new WorkflowServiceHost(workflow1, new Uri("http://localhost:8293/Service1.xamlx"));

// Enable Metadata publishing/
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);

// Open the WorkflowServiceHost and wait for requests.
host.Open();
Console.WriteLine("Press enter to quit");
Console.ReadLine();

C# 式がコンパイルされないと、Open の処理は成功しますが、ワークフローは呼び出し時に失敗します。 次の CompileExpressions メソッドは、前の「コード ワークフローでの C# 式の使用」にあるメソッドと同じです。

static void CompileExpressions(Activity activity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions.
    string activityName = activity.GetType().ToString();

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = activity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = false
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { activity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRoot(
        activity, compiledExpressionRoot);
}