次の方法で共有


Microsoft Windows Workflow Foundation 入門: 開発者向けの手引き

Dino Esposito

Solid Quality Learning

Updated February 2006

適用対象:

   Microsoft Windows Workflow Foundation
   Microsoft Windows Vista

要約 : Microsoft Windows Workflow Foundation のテクノロジおよび機能について説明します。Microsoft .NET プラットフォームでワークフロー駆動型アプリケーションを作成する必要がある開発者にとって役に立つ情報です。

**:   **この記事は、Windows Workflow Foundation Beta 2 を対象として作成されました。 テクノロジの最終リリースの前に、変更が加えられる可能性があることに注意してください。

目次

Windows プラットフォームへのワークフロー サポートの追加で一歩先を行く Windows プラットフォームへのワークフロー サポートの追加で一歩先を行く
最初のワークフローを作成する 最初のワークフローを作成する
データを受信して使用する データを受信して使用する
ワークフロー ランタイム ワークフロー ランタイム
ワークフローとアクティビティ ワークフローとアクティビティ
カスタム アクティビティを開発する カスタム アクティビティを開発する
より現実的なワークフローを計画する より現実的なワークフローを計画する
まとめ まとめ

Windows プラットフォームへのワークフロー サポートの追加で一歩先を行く

Microsoft Windows Workflow Foundation (WF) は、Windows プラットフォームでワークフロー ソリューションを開発するための拡張フレームワークです。 近々リリースされる Microsoft WinFX の一部である Windows Workflow Foundation は、ワークフロー ベースのアプリケーションの開発および実行のための API およびツールを提供します。 Windows Workflow Foundation は、ヒューマン ワークフローとシステム ワークフローを含む、さまざまなカテゴリのアプリケーションのエンドツーエンド ソリューションを作成するための単一の統合モデルを提供します。

Windows Workflow Foundation は、幅広い汎用のワークフロー フレームワークであり、徹底的にすべてのレベルで拡張性を提供するように設計されています。 Windows Workflow Foundation ベースのソリューションは、相互に接続されたコンポーネントによって構成され、これらのコンポーネントは Microsoft .NET ベースのコードによって作成され、ホスト アプリケーションで実行されます。 必要に応じた環境で Web ページを視覚的に作成する場合と同様に、特定のワークフローのステップを視覚的なデザイナで作成し、ワークフロー コンポーネントの分離コードを追加して、ルールの実装およびビジネス プロセスの定義を行います。

Windows Workflow Foundation は、ワークフロー エンジン、.NET 管理の API、ランタイム サービス、および Microsoft Visual Studio 2005 と統合された視覚的なデザイナとデバッガを提供します。 Windows Workflow Foundation では、クライアントおよびサーバーの両方に及ぶワークフローの構築および実行が可能であり、すべてのタイプの .NET アプリケーション内で実行可能なワークフローを作成できます。

この記事では、Windows Workflow Foundation について簡単に説明し、いくつかの例を挙げて動作のしくみを説明します。

ワークフローは、アクティビティのマップとして定義されたヒューマン プロセスまたはシステム プロセスのモデルです。 アクティビティは、ワークフローのステップであり、ワークフローの実行、再利用、および構成の単位です。 アクティビティのマップは、ルール、アクション、状態、およびそれらの関係を表します。 アクティビティを配置してデザインされた Windows Workflow Foundation ワークフローは、.NET アセンブリにコンパイルされ、ワークフロー ランタイムおよび共通言語ランタイム (CLR) で実行されます。

最初のワークフローを作成する

Windows Workflow Foundation は、主として、Visual Studio デザイナ内でデザインおよび実装された特殊なオブジェクトを処理する .NET のランタイム環境で構成されます。 Windows Workflow Foundation をサポートするには、Microsoft .NET Framework 2.0 が必要です。 専用のインストーラ パッケージによって、Visual Studio 2005 の Windows Workflow Foundation デザイナとプロジェクト テンプレートのサポートが追加されます。 インストールが完了すると、図 1 に示すように、Visual Studio 2005 の標準プロジェクトの一覧に、新しいノードが追加されます。

wwfgetstart01.gif

1. Visual Studio 2005 のワークフロー   プロジェクト   テンプレート

特定のタイプのワークフロー アプリケーションを識別するさまざまなオプションを選択できます。 表 1 に、ワークフロー プロジェクト テンプレートの一覧を示します。

1. Visual Studio 2005 のワークフロー   プロジェクト   タイプ

タイプ 説明

Sequential Workflow Console Application

既定の シーケンシャル ワークフローとコンソール テスト ホスト アプリケーションを含むワークフローを構築するプロジェクトを作成します。

Sequential Workflow Library

シーケンシャル ワークフローをライブラリとして構築するプロジェクトを作成します。

Workflow Activity Library

ワークフロー アプリケーションの構成単位として後から再利用可能なアクティビティのライブラリを作成するプロジェクトを作成します。

State Machine Console Application

ステートマシン ワークフローとコンソール ホスト アプリケーションを構築するプロジェクトを作成します。

State Machine Workflow Library

ステートマシン ワークフローをライブラリとして構築するプロジェクトを作成します。

Empty Workflow

ワークフローおよびアクティビティを含めることが可能な空のプロジェクトを作成します。

Windows Workflow Foundation は、シーケンシャル ワークフローと ステートマシン ワークフローという 2 つのすぐに使用できる基本ワークフロー スタイルをサポートします。

シーケンシャル * * ワークフローは、最後のアクティビティが完了するまで次々に実行されるステップのパイプラインによって表現される処理に最適です。 ただし、シーケンシャル ワークフローの実行は、単なる順次実行ではありません。 外部イベントの受信や、同時に複数のタスクを起動することも可能であるため、正確な実行の順序はいくらか異なる可能性があります。

ステートマシン * * ワークフローは、一連の状態、遷移、およびアクションで構成されます。 1 つの状態を開始状態として示し、その後は、イベントに基づいて、別の状態への遷移が可能になります。 ステートマシン ワークフローには、ワークフローの終わりを特定する最終状態を指定できます。

それでは、Sequential Workflow Console Application プロジェクトを選択し、新規に作成しましょう。 Visual Studio 2005 ソリューション エクスプローラには、2 つのファイル、workflow1.cs と workflow1.designer.cs (最初は非表示) が含まれます。 これら 2 つのファイルは、作成するワークフローを表します。 Windows Workflow Foundation ワークフローは、ワークフロー モデル ファイルとコード ファイル クラスで構成されます。 workflow1.cs クラスは、独自のワークフロー ビジネス ロジックを記述できるコード ファイル クラスです。 workflow1.designer.cs クラスは、アクティビティ マップの記述を表します。 このファイルは、Microsoft Windows フォーム プロジェクトのフォームとほぼ同じ方法で、Visual Studio 2005 によって自動的に管理されます。 ワークフローにアクティビティを追加すると、Visual Studio 2005 では、アクティビティ マップをプログラムで構築する Microsoft C# コードによってデザイナ クラスが更新されます。 Windows フォームにたとえると、ワークフローはフォームに類似し、アクティビティはコントロールに類似しています。

アクティビティのレイアウトに、XML ワークフロー マークアップ形式など、別の保存形式を選択することもできます。 このアプローチを試すには、プロジェクトから workflow1.cs ファイルを削除し、図 2 に示すように、新しいワークフロー アイテムを追加します。

wwfgetstart02.gif

2. コード分離を伴った Sequential ワークフロー   アイテムを追加する  

現在、このプロジェクトは、workflow1.xoml と workflow1.xoml.cs の 2 つのファイルで構成されています。 workflow1.xoml には、ワークフロー モデルを表す XML ワークフロー マークアップが含まれます。workflow1.xoml.cs はコード ファイル クラスであり、ワークフローのソース コードとイベント ハンドラが含まれます。 .xoml ファイルをダブルクリックすると、視覚的なワークフロー デザイナが実行されます (図 3 参照)。

マークアップまたはコードの選択によるワークフロー モデルのシリアル化は、実行時に影響を与えません。ワークフローがアセンブリにコンパイルされると、マークアップとコードは同等になります。

ワークフロー アプリケーションには、データの送受信などの作業を実行するアクティビティと、一連の子アクティビティの実行を管理する IfElseWhile などの複合アクティビティが混在します。 ワークフローは、ドキュメント レビュー、PO の承認、IT ユーザーの管理、パートナーとの情報交換、任意の種類のウィザード、基幹業務アプリケーションなど、高度なエンドツーエンド シナリオを実装できます。

図 3 に、1 つのアクティビティ (codeActivity1 ブロック) だけを含む非常に単純なワークフローのサンプルを示します。

wwfgetstart03.gif

3. Visual Studio 2005 ワークフロー   デザイナ

Code ブロックは、CodeActivity クラスのインスタンスに対応し、ユーザー定義コードで記述された動作を持つワークフロー内のアクティビティを表します。 バックエンド コードは、デザイナで選択された要素をダブルクリックして、Visual Studio 2005 から入力します。これは ASP.NET アプリケーションおよびその他の Visual Studio 2005 プロジェクトの一般的なプログラミング方法です。

アクティビティをダブルクリックすると、コード ファイルが開き、コード ハンドラのスタブが表示されます。

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    // コードを入力します。
}

コード ハンドラに入力したステートメントは、ワークフロー ランタイムがワークフロー内の指定されたアクティビティ ブロックの処理を開始すると同時に実行されます。 この例では、ウェルカム メッセージだけを出力します。

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    CodeActivity c = (CodeActivity)sender;
    Console.WriteLine("Hello, from '{0}'.\nI'm an instance of the {1} class.",
       c.Name, c.ToString());
}

ワークフローには、視覚的なレイアウトのほかに、workflow1.xoml.cs ファイルに保存された以下のコードが含まれます。

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace HelloWorldWorkflow
{
    public partial class Workflow1 : SequentialWorkflowActivity
    {
        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            CodeActivity c = (CodeActivity)sender;
            Console.WriteLine("Hello, from '{0}'.\nI'm an instance of the {1} class.",
               c.Name, c.ToString());
        }
    }
}

partial 属性は、.NET Framework 2.0 の新しい概念であるパーシャル クラスを表します。 パーシャル * * クラスでは、複数の異なるソース ファイルにクラス定義を分割できます。 各ソース ファイルに、通常のクラス定義が最初から最後まで記述されているように見えますが、その定義は部分的であり、クラスに必要なすべてのロジックが含まれているわけではありません。 コンパイラによって部分的なクラス定義がマージされて、コンパイル可能な完全なクラス定義になります。 パーシャル クラスは、オブジェクト指向とは関係ありません。これはプロジェクト内のクラスの動作を拡張するためのソース レベルおよびアセンブリに限定された方法です。 .NET Framework 2.0 では、パーシャル クラスを使用して、Visual Studio 2005 でコード ファイル内に自動生成コードが挿入されるのを防止します。 元のクラスで不足しているバインド コードは、パーシャル クラスを追加することで、ランタイムによって追加されます。

ワークフローは、Windows Workflow Foundation のワークフロー ランタイムによってのみ実行可能で、ワークフロー ランタイムには、いくつかのルールに従って、ホストとなる外部アプリケーションが必要です。 Visual Studio 2005 では、テストのための program.cs ファイルがプロジェクトに追加されます。 次に示すように、このファイルは簡単なコンソール アプリケーションです。

    class Program
    {
        static void Main(string[] args)
        {
            WorkflowRuntime workflowRuntime = new WorkflowRuntime();
            AutoResetEvent waitHandle = new AutoResetEvent(false);
            workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) {waitHandle.Set();};
            workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
            {
                Console.WriteLine(e.Exception.Message);
                waitHandle.Set();
            };
            WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(HelloWorldWorkflow.Workflow1));
            instance.Start();
            waitHandle.WaitOne();
            // ユーザーへのフィードバックです。
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("==========================");
            Console.WriteLine("Press any key to exit.");
            Console.WriteLine("==========================");
            Console.ReadLine();
        }
    }

簡易化のため、Visual Studio 2005 では、コンソール アプリケーション内にワークフロー クラスの名前がハードコーディングされます。上記のコードの太字で示された行を参照してください。 実行後すぐにコンソール アプリケーションが終了するのを防ぐため、Main メソッドの終わりに Console.ReadLine 呼び出しを追加します。 これで、ワークフローの構築およびテストのための準備ができました。F5 キーを押して実行してみましょう。 すべてが順調にいけば、図 4 に示された結果が出力されます。

wwfgetstart04.gif

4. コンソール   ホスト   アプリケーションで実行されたサンプル   ワークフロー  

ワークフロー アプリケーションのデバッグも簡単に行うことができます。 実際には、ブレークポイントを設定するだけです。 通常の C# コードと同様に、ワークフローのコード ファイル クラスの任意の場所にブレークポイントを挿入できます。または、興味深い方法として、デザイナのビューに直接挿入することも可能です。 図 5 に示すように、デバッガを起動するアクティビティを選択し、F9 キーを押してブレークポイントを設定します。

wwfgetstart05.gif

5. ワークフローのデザイナ   ビューにブレークポイントを設定する  

コードの流れがブレークポイントを設定したアクティビティに到達すると、Visual Studio 2005 からワークフロー デバッガに制御が渡されます (図 6 参照)。 それ以降は、通常どおりに F11 キーを押して、視覚的なデザイナのコードおよびアクティビティの中にステップインできます。

wwfgetstart06.gif

6. デバッグ   セッションを実行中のワークフロー   アプリケーション  

データを受信して使用する

ここではワークフローに変更を加えて、ワークフローがインスタンス化されたときにデータを受信および使用できるようにします。 ワークフローがインスタンス化されたときにワークフロー内にデータを受信するには、パラメータおよびイベントの 2 とおりの一般的なアプローチがあります。 パラメータはコードで作成したプロパティで表され、アクティビティおよびワークフロー ホスト アプリケーションによって使用が可能です。 イベントを選択した場合は、ワークフロー モデルのある時点で起動してデータを渡す外部ソースとして動作するカスタム アクティビティを作成し、追加する必要があります。 イベント ベースのアプローチについては、この記事の後半で説明します。ここでは、パラメータについて説明します。

次に示すように、ワークフローに対する 2 つのパラメータの追加は、ワークフローの分離コード ファイルで対応する 2 つのプロパティを作成することと同様に簡単です。

public partial class Workflow1 : SequentialWorkflowActivity
{
    private string firstName;
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    private string lastName;
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

パブリック プロパティの使用は、コードを整えるためのプログラミング習慣にすぎません。 これはパラメータ データを使用するための必要条件ではありません。 パブリック プロパティを使用してパラメータをラップする場合は、任意のプロパティ名を選択できます。 ただし、C# のパラメータ名は、大文字と小文字が区別される点に注意してください。

これらのパラメータを通じて実際にデータを入力するのは誰でしょうか。 この作業を担当するのは、ホスト アプリケーションです。 ただし、実行するワークフローがランタイム コンテナに読み込まれるとき、初期化時にホストによってすべてのパラメータが設定されることに注意してください。 この点をさらに詳しく説明するため、Windows フォームをベースにしたサンプル ホスト アプリケーションを作成しましょう。 サンプル アプリケーションでは、ユーザーが姓名を入力するためのテキスト ボックスを提供し (図 7 参照)、入力されたデータをワークフローのコード ハンドラに渡します。 パラメータを使用するために、次のようにコード ハンドラを書き直します。

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    MessageBox.Show("Welcome, " + FirstName + " " + LastName);
}

Windows フォームのサンプル ホスト アプリケーションでは、重要な処理として、[Start Workflow] ボタンにクリック ハンドラが追加されます。

wwfgetstart07.gif

7. ワークフローのホスト Windows フォーム   アプリケーション  

フォームの分離コード クラスの完全なソース コードを次に示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
namespace WinFormTestHost
{
    public partial class Form1 : Form
    {
        private WorkflowRuntime wr;
        public Form1()
        {
            InitializeComponent();
        }
        private void btnStartWorkflow_Click(object sender, EventArgs e)
        {
            if (wr == null)
            {
                wr = new WorkflowRuntime();
                wr.StartRuntime();
            }
            Dictionary<string, object> parameters =
                new Dictionary<string, object>();
            parameters.Add("FirstName", txtFirstName.Text);
            parameters.Add("LastName", txtLastName.Text);
            WorkflowInstance instance = 
wr.CreateWorkflow(typeof(HelloWorldWorkflow.Workflow1), parameters);
            instance.Start();
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (wr != null)
            {
                if (wr.IsStarted)
                {
                    wr.StopRuntime();
                }
            }
        }
    }
}

Parameters コレクションにデータを挿入するには、文字列とオブジェクトで構成された Dictionary ジェネリッククラスを使用する必要があります。 アイテムの名前は文字列ですが、含まれる値はオブジェクトとして構成されます。 ワークフロー モデルに存在する静的パラメータと同じ数だけのアイテムを Dictionary に追加します。このケースでは、FirstNameLastName です。 2 つのパラメータは、UI テキスト ボックスに入力された内容を受け取ります。

最後に、指定されたモデルのインスタンスが作成されると、ワークフローが実行されます。 ランタイム オブジェクト上の StartWorkflow メソッドには、いくつかのオーバーロードがあります。 コードで使用するバージョンでは、ワークフローの型、入力パラメータのコレクション、およびシステム生成のグローバル一意識別子 (GUID) を受け取ります。

ワークフロー ランタイムのインスタンスは、1 つのプロセスにつき 1 つだけ必要です。また、1 つの AppDomain に複数のインスタンスを持つことは許可されません。 一番良い方法は、必要なインスタンスをフォームのコンストラクタで直接作成することです。 同じランタイム オブジェクトによって、さまざまなワークフロー インスタンスを処理できます。 ランタイムは、GUID によってインスタンスを識別し、特定のインスタンスごとにプライベート データを受信します。

wwfgetstart08.gif

8. Windows フォーム   アプリケーションがホストする実行中のパラメータ化ワークフロー

学習のため、開発のこの段階でデザイナとワークフロー マークアップの両方のコードに簡単に目を通してみましょう。 次は workflow1.designer.cs ソース ファイルです。

public sealed partial class Workflow1
{
   #region Designer generated code
   /// <summary>
   /// デザイナのサポートに必須のメソッドです。コード エディタを使用して
   /// このメソッドの内容を修正しないでください。
   /// </summary>
   private void InitializeComponent()
   {
        this.CanModifyActivities = true;
        this.codeActivity1 = new System.Workflow.Activities.CodeActivity();
        //
        // codeActivity1
        //
        this.codeActivity1.Name = "codeActivity1";
        this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
        //
        // Workflow1
        //
        this.Activities.Add(this.codeActivity1);
        this.Name = "Workflow1";
        this.CanModifyActivities = false;
   }
   #endregion
    private CodeActivity codeActivity1;
}

対応するワークフロー マークアップの内容は次のとおりです。

<SequentialWorkflowActivity x:Class="HelloWorldWorkflow.Workflow1" x:Name="Workflow1" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
    <CodeActivity x:Name="codeActivity1" ExecuteCode="codeActivity1_ExecuteCode" />
</SequentialWorkflowActivity>

プロパティをパラメータとして使用できるだけではなく、依存関係のプロパティも使用できます。 これらについては、カスタム アクティビティの作成の段階で検討します。

ワークフロー ランタイム

ホストは、WorkflowRuntime クラスを通じて Windows Workflow Foundation との対話を行います。 上記のサンプル ホストは簡潔に見えますが、この重要なポイントを見逃さないでください。 ホストは、さらに多くの重要な処理に関与する可能性があります。たとえば、1 つ以上のプロセスおよび AppDomain の作成、必要に応じた AppDomain 間での呼び出しのマーシャリング、分離メカニズムのセットアップなどを行う場合があります。 スケーラビリティの理由で、1 台のマシンに搭載された複数の CPU を活用するために複数のプロセスを作成する場合もあれば、コンピュータ ファーム上で多数のワークフロー インスタンスを実行する場合もあります。

ホストには、その他にも実行するタスクがあります。 たとえば、ワークフローで長い待ち時間が発生した場合に適用するポリシーの管理、特定のイベントをリッスンしてユーザーや管理者にイベントを通知する、各ワークフローのタイムアウトおよび再試行の設定、パフォーマンス カウンタの公開、デバッグと診断のためのログ情報の書き込みなどがあります。

追加のタスクの大部分は、起動時にコンテナに登録された定義済みのサービスやカスタム サービスを通じて実行されます。 サンプル ホストは、追加タスクを 1 つも実行せず、ワークフロー インスタンスの起動だけを行います。 これは多くの一般的な状況にも該当します。

ワークフローとアクティビティ

話を元に戻して、ここではワークフロー プロジェクトがアクティブなときの Visual Studio 2005 のツールボックスを調べてみましょう。 ツールボックスは、図 9 に示すように、ステップの順序や相互関係をデザインしてワークフロー モデルを形成するために使用できるアクティビティを示します。

wwfgetstart09.gif

9. Windows Workflow Foundation Sequential ワークフロー構成単位

表 2 に、大部分の基本アクティビティの簡単な説明と、それらのアクティビティが役立ついくつかのシナリオを示します。

2. Windows Workflow Foundation の構成単位  

アクティビティ 説明

Code

ワークフローに Microsoft Visual Basic .NET または C# のコードを追加して、カスタム アクションを実行できます。 ただし、Web サービスなどの外部リソースへの依存によって、コードがワークフローの妨げにならないようにする必要があります。

Compensate

エラーが発生した場合、コードを呼び出して、ワークフローによって既に実行済みの操作を無効化、または補正することができます。 以前に成功の通知を送ったが、今では操作が中止されている場合は、その通知を受け取ったユーザーに電子メール メッセージを送信するのが一般的です。

ConditionedActivityGroup (CAG)

CAG 全体の終了条件が満たされるまで、各アクティビティの特定の条件に基づいて、一連の子アクティビティを条件付きで実行できます。 子アクティビティは、互いに独立したアクティビティであり、並列に実行できます。

Delay

ワークフローのタイミングを制御し、遅延を組み込むことができます。 Delay アクティビティにタイムアウトを設定して、ワークフローが一時停止した後、実行を再開するように指定できます。

EventDriven

イベントによって実行がトリガされる一連のアクティビティを表します。 最初の子アクティビティには、外部イベントに備えて待機できるアクティビティが必要です。 実行可能な最初の子アクティビティは、EventSink と Delay です。 Delay は、この場合はタイムアウトとして使用されます。

HandleExternalEvent

サービスが指定されたイベントを発行すると、WorkflowRuntime に登録されたデータ交換サービスからデータを受信できます。

FaultHandler

指定するタイプの例外を扱うことができます。 FaultHandler アクティビティは、指定された例外が発生した場合に必要な作業を実際に実行する他のアクティビティのラッパーです。 例外を格納し、分離コードで利用可能にするために、オプションとしてローカルの変数を指定できます。

IfElse

複数の代替分岐のうち、1 つを条件付きで実行できます。 各分岐に条件を設定し、条件を満たした最初の分岐が実行されます。 最後の分岐は "else (その他の)" 分岐として扱われるため、条件を設定する必要はありません。

CallExternalMethod

ワークフローから WorkflowRuntime に登録されたデータ交換サービスにメッセージを送信するために、インターフェイス上でメソッドを呼び出すことができます。

InvokeWebService

Web サービス メソッドを呼び出すことができます。 使用するプロキシ クラス (WSDL を利用) および呼び出すメソッドの名前を指定します。 同期および非同期の呼び出しがサポートされます。

InvokeWorkflow

任意の深さまで、ワークフローから別のワークフローを呼び出したり起動したりできます。 たとえば、呼び出されたワークフローが 3 番目のワークフローを呼び出し、3 番目のワークフローが 4 番目のワークフローを呼び出し、以下同様に続きます。 再帰呼び出しはサポートされません。 サポートされた呼び出しモデルは Fire-and-Forget です。

Listen

発生の可能性がある複数のイベントの 1 つを待機するか、指定されたタイムアウト間隔が経過してから停止し、結果に基づいて分岐できます。 各分岐に対し 1 つ以上のイベント駆動型アクティビティを追加できます。 条件を満たした最初の分岐だけが実行され、その他の分岐は実行されません。

Parallel

2 つ以上の処理を別々に実行できます。 アクティビティは両方の処理が終了するまで待機してから処理を続行します。

Policy

ルールのコレクションを表示および評価できます。 各ルールが条件を満たしていれば、アクションを実行することができます。

Replicator

指定されたアクティビティのインスタンスを任意の数だけ作成し、それらを順次または同時に実行できます。

Sequence

一連の子アクティビティを連続的に実行する処理を調整できます。 Sequence は最後の子アクティビティが終了したときに終了します。

SetState

State Machine ワークフローの新しい状態への遷移を指定できます。

State

State Machine ワークフローの状態を示します。

StateInitialization

State アクティビティ内で、状態が遷移したときに実行される子アクティビティのコンテナとして使用されます。

StateFinalization

State アクティビティ内で、状態から脱けるときに実行される子アクティビティのコンテナとして使用されます。

Suspend

ワークフローの処理を一時停止して、エラー条件が発生した場合に中断できます。 ワークフロー インスタンスを一時停止すると、エラーがログに記録されます。 管理者のエラー診断に役立つメッセージ文字列を指定できます。 現在のインスタンスに関連するすべての状態情報が保存され、管理者が実行を再開したときに復旧されます。

Terminate

異常な状況が発生した場合、ワークフローの処理を直ちに終了できます。 Parallel アクティビティ内で呼び出した場合は、現在の状態にかかわらず、すべての分岐が即座に終了します。 ワークフローが終了すると、エラーがログに記録され、管理者はメッセージによりエラーの内容を把握できます。

Throw

指定した型の例外をスローできます。 このアクティビティの使用は、ユーザー コード内でコード ハンドラが例外をスローすることと同等です。 このアクティビティは、宣言によって .NET 例外をスローします。

TransactionalScope

transactional scope はアクティビティをグループ化するために使用されるブロックです。 このアクティビティは、主にトランザクションの実行、補正、および例外処理に使用されます。

SynchronizationScope

このアクティビティの使用により、アクティビティ内での共有データへのアクセスが適切にシリアル化されます。

WebServiceInput

Web サービスとして公開されたワークフローで、Web サービス要求を受信できます。

WebServiceOutput

Web サービスとして公開されたワークフローで、Web サービス要求に応答できます。

WebServiceFault

これは、Web サービス障害の発生モデルを提供するもので、ASMX Web サービス フレームワーク メソッドで例外をスローすることと同等です。

While

条件が満たされたとき、1 つ以上のアクティビティを実行できます。 各繰り返しの前に、条件が評価されます。 条件が満たされた場合すべての子アクティビティが実行され、満たされない場合アクティビティは終了します。 宣言条件またはコード条件のいずれかを指定できます。

アクティビティは Windows Workflow Foundation を使用したワークフロー プログラミングの宣言アプローチを示します。 アクティビティを使用して、デザイン時にワークフロー モデルを作成し、各アクティビティのプロパティに値を割り当てます。 コード分離を伴ったワークフロー アイテムを選択した場合、最終結果は .xoml 拡張子を持つワークフロー マークアップ ファイルに XML マークアップとして保存されます。 それ以外の場合は、作成したモデルはワークフロー オブジェクト モデルへの一連の呼び出しとして、デザイナ生成の C# または Visual Basic .NET クラス ファイルに保存されます。 前者のアプローチは ASP.NET ページと類似していますが、後者は Windows フォーム アプリケーションの場合と類似しています。

Visual Studio 2005 では、この 2 つのアプローチの違いはほとんど現れません。 Visual Studio 2005 では、ワークフローを常に視覚的にデザインし、作業内容は、異なる 2 つの形式のいずれかに透過的に保存されます。 コードのみのソリューション (XOML およびコード分離なし) を選択した場合、デザイナ コードを微調整して柔軟性を高めることができます。 たとえば、構成ファイルまたはデータベースからパラメータの既定値を読み取るようにコードを作成できます。 ワークフロー マークアップとコード分離を選択した場合は、ワークフローのコードとそのモデルが整然と分離されます。

ワークフロー モデルをプログラムで変更することは可能でしょうか。 デザイン時には、Visual Studio で実行できるすべてのことをワークフローに対してプログラムで実行することができます。 実行時には、アクティビティのコレクションも動的に更新でき、実行中のワークフロー インスタンスに変更を加えることができます。 デザイン時には予想されていなかった業務上の変更があった場合や、ビジネス プロセスを修正および完了するビジネス ロジックが必要な場合に、ワークフローの変更が実行されます。 どのような場合でも、再デザインするのではなく、完成を目指した変更のみを行うべきです。

ワークフローの変更は、アプリケーションのコンテキスト内で 1 つのワークフロー インスタンスに適用されます。 これ以降の同種のワークフロー インスタンスは、変更の影響を受けません。 ワークフロー インスタンスへの変更は、そのワークフロー インスタンス内から実行でき、またアプリケーション コードで外部からも実行できます。

ワークフローを Web サービスとして APS.NET クライアントおよびその他のワークフローに公開する機能を含め、Windows Workflow Foundation フレームワークは、Web サービスの相互運用性をサポートします。 Windows Workflow Foundation では、Microsoft IIS 6.0 で ASP.NET を実行している Web サーバーまたはサーバー ファームで ASP.NET Web サービスとしてワークフローを発行できます。

Windows Workflow Foundation フレームワークのアクティビティ セットには、WebServiceReceive および WebServiceResponse アクティビティが含まれ、これらのアクティビティを使用すると、ワークフローを Web サービスのエンドポイントとして使用できます。

Web サービスとして公開するには、ワークフローに WebServiceReceive アクティビティを含めてクライアントからの着信呼び出しを取得する必要があります。 図 10 に示すように、ショートカット メニュー コマンドを使用してワークフローを Web サービスとして発行します。

wwfgetstart10.gif

10. ワークフローを Web サービスとして発行する

カスタム アクティビティを開発する

Windows Workflow Foundation の拡張性における重要ポイントは、カスタム アクティビティの作成です。カスタム アクティビティの作成により、ワークフロー モデルの構築に使用する構成単位のセットを拡張できます。

ここでは、電子メール メッセージを送信するカスタム アクティビティを作成して、アクティビティの内部アーキテクチャを見ていきます。 Windows Workflow Foundation には、カスタム アクティビティ用に Visual Studio 2005 テンプレートが用意されています。 このテンプレートは Workflow Activity Library という名前です。 このテンプレートは C# ファイルを作成します。ファイル名は SendMailActivity などの任意の名前に変更できます。 アクティビティは、親クラスを継承する通常のクラスです。 アクティビティは、組み込みアクティビティ、自分で作成したアクティビティ、サードパーティ ベンダから購入したアクティビティなど、既存のアクティビティから派生させることができます。 ただし、親クラスの定義済みの動作が新しいコンポーネントに追加されます。 アクティビティをゼロから構築するには、 Activity から派生させます。 次のコード サンプルは、新しいクラスのスケルトンです。

public partial class SendMailActivity : System.Workflow.ComponentModel.Activity
{
    public SendMailActivity()
    {
        InitializeComponent();
    }
    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
        return base.Execute(executionContext);
    }
}

ご覧いただくとわかるように、Execute メソッドはコンポーネントの中心であり、コンポーネントのコア タスクが実行される場所です。

開発が完了すると、アクティビティはツールボックスに配置され、新しいワークフロー アプリケーションにいつでもドラッグアンドドロップできる状態になります。 プロパティの一覧は必須ではありませんが、プロパティなしのアクティビティではほとんど役に立ちません。 多くの場合、標準プロパティでなくカスタム アクティビティ用の依存プロパティの方が有用です。 依存プロパティにより、関連データに値を結び付けることができます。関連データには、カスタム アクティビティを使用するワークフロー内にある他のアクティビティの他のプロパティが含まれます。 SendMailActivity 向けに最初の依存プロパティを定義してみましょう。 図 11 に示すように、Windows Workflow Foundation が提供するスニペットを使用すれば簡単に依存プロパティを挿入することができます。

wwfgetstart11.gif

11. スニペットを挿入する

これによって、DependencyProperty の静的インスタンスと、プロパティのランタイム値を取得するキーとして DependencyProperty を使用するラッピング メンバ プロパティが作成されます。 これは、アクティビティの各インスタンスが、静的 DependencyProperty オブジェクトをキーとして使用してアクセスできるプロパティ値の寄せ集めテーブルを持つようなものです。 スニペットを選択し、新しいプロパティをカスタマイズして、電子メールの送信者を指定することができます (図 12 参照)。

wwfgetstart12.gif

12. "From" パラメータをカスタマイズする

プロパティのランタイム値はカスタム アクティビティの基本クラスによってコントロールされるため、カスタム アクティビティのデザインと構築が完了した後、その値は宣言により他のプロパティに結合できます。 次に、ToSubjectBody、および Host 用の依存プロパティを作成し、ユーザーが送信する電子メール メッセージを完全に構成できるようにします。

最後に、Execute メソッドに手を加えて、アクティビティが実行されたときに電子メール メッセージが送信されるようにします。

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
    MailAddress toAddress = new MailAddress(To);
    MailAddress fromAddress = new MailAddress(From);
    MailAddressCollection addresses = new MailAddressCollection();
    addresses.Add(toAddress);
    MailMessage msg = new MailMessage(fromAddress, toAddress);
    msg.Subject = Subject;
    msg.Body = Body;
    SmtpClient mail = new SmtpClient(Host);
    mail.Send(msg);
    return ActivityExecutionStatus.Closed;
}

ワークフロー ソリューション内にアクティビティ プロジェクトを作成した場合は、ワークフロー ドキュメントによって、ツールボックスに表示された新しいアクティビティが自動的に検索されます (図 13 参照)。それ以外の場合は、ツールボックスを右クリックして追加する必要があります。

wwfgetstart13.gif

13. ツールボックスに表示された SendMail アクティビティ

ここまでの操作で、SendMail アクティビティがワークフローで利用できるようになったので、依存プロパティの機能を試してみることができます。 たとえば、ワークフローに SendMail を追加してその Body プロパティに <Promote...> を選択すると、前述の FirstNameLastName の場合と同じようにワークフローの新しいパラメータに電子メールの本文を渡すことができます。 これは、ワークフローの動作を一元化するために依存プロパティをどのように使用できるかを示す一例です。

図 14 では、SendMail アクティビティを実際に実行しています。

wwfgetstart14.gif

14. 実行中の SendMail アクティビティ

より現実的なワークフローを計画する

表 2 に示したいくつかのアクティビティを組み合わせて、より実際的なタスクを解決する方法を考えてみましょう。 業務アプリケーションでは、注文がいくつかの状態を経て完了する場合があります。 通常のシナリオでは、現在の状態に基づいて、注文に対して起こり得るイベントを指定するルールがあります。 たとえば、未確定の注文は処理または更新できますが、中止したり出荷したりすることはできません。

あるイベントが発生すると、State Machine ワークフローで注文の状態が遷移します。 たとえば、注文が未確定のときに BeingProcessed イベントが発生すると、State Machine ワークフローは注文を適切な状態に遷移します。 図 15 に、注文の State Machine ワークフローのサンプルを示します。

wwfgetstart15.gif

15. 注文を管理する State Machine のスキーマの例  

それでは、State Machine ワークフローを作成してみましょう。 State アクティビティを使用して、注文に対して起こり得る状態のモデルを作成します。 次に、EventDriven アクティビティを使用して、それぞれの状態から発生し得るイベントを指定します。 カスタム サービスを通じて検出された外部イベントにより、注文の状態が遷移します。 遷移を実行するには、SetState アクティビティを使用します。 ワークフローの作成後、Windows フォームのホスト アプリケーションを使用してワークフローの性能を試します。

ワークフローは、特定の目的のために設定されたサービスを通じて外部と通信します。 サービスは、ワークフロー内のイベント駆動型アクティビティによって受信されるイベントを発生します。 同様に、このサービスは、ワークフローがホストを呼び出してデータを送信するためのパブリック メソッドを公開します。 メソッドとイベントはインターフェイスで定義されます。 このインターフェイスは、データ交換サービスとしても知られています。 ワークフローが外部コンポーネントとデータをやりとりするときは、入力または出力のいずれの場合もこのサービスが必要です。

データ交換サービスは通常の .NET クラス ライブラリで、最低でもインターフェイス定義とそのインターフェイスを実装するクラスを含んでいます。 インターフェイスは必要なタスクに合わせてデザインします。 注文のライフサイクルを表す State Machine の例では、インターフェイスは 5 つのイベントから構成されます。

[ExternalDataExchange]
public interface IOrderService
{
    event EventHandler<OrderEventArgs> OrderCreated;
    event EventHandler<OrderEventArgs> OrderShipped;
    event EventHandler<OrderEventArgs> OrderUpdated;
    event EventHandler<OrderEventArgs> OrderProcessed;
    event EventHandler<OrderEventArgs> OrderCanceled;
}

[ExternalDataExchange] 属性は、 IOrderService がデータ交換サービスのインターフェイスであることを示します。これによって、ワークフロー ランタイムは、IOrderService がワークフロー インスタンスとのデータ交換に使用されるインターフェイスであることを認識します。 この例では、ホストが一連の EventDriven アクティビティのイベントを発生して、ワークフロー インスタンスにデータを送信します。 必要があれば、CallExternalMethod アクティビティを通じてワークフロー インスタンス内から IOrderService インターフェイスのメソッドを呼び出すこともできます。

インターフェイスのイベント宣言では、.NET Framework 2.0 の最新機能であるジェネリックを使用します。 EventHandler クラスはデリゲートで、イベント処理で使用する関数のプロトタイプを示します。 .NET Framework 1.x では、EventHandler は次のように定義されていました。

void EventHandler(object sender, EventArgs e) 

イベントで OrderEventArgs などのカスタム データ構造を渡すには、新しいデリゲートを作成し、EventHandler の代わりに使用する必要があります。 以下に例を示します。

delegate void OrderEventHandler(object sender, OrderEventArgs e) 

このパターンは、.NET Framework 2.0 でも使用できます。 ただし、.NET Framework 2.0 でジェネリックが登場したことにより、新しいデリゲート クラスを明示的に定義 (およびインスタンス化) せずに、同じ結果を得ることが可能になりました。 この例では、イベント データ型をパラメータとして、EventHandler<T> デリゲートのジェネリック バージョンを使用します。

イベントがクライアントに渡すデータ型は OrderEventArgs です。OrderEventArgs は、Windows Workflow Foundation の ExternalDataEventArgs クラスから派生したカスタム クラスであり、次のように同じアセンブリで定義されます。

[Serializable]
public class OrderEventArgs : ExternalDataEventArgs
{
    private string _orderId;
    public OrderEventArgs(Guid instanceId, string orderId) : base(instanceId)
    {
        _orderId = orderId;
    }
    public string OrderId
    {
       get { return _orderId; }
       set { _orderId = value; }
    }
}

次に、インターフェイスを実装するクラスを定義します。 クラスには、インターフェイスで発生するイベントと同数のパブリック メソッドが含まれます。

public class OrderService : IOrderService
{
    public OrderService()
    {
    }
    public void RaiseOrderCreatedEvent(string orderId, Guid instanceId)
    {
        if (OrderCreated != null)
            OrderCreated(null, new OrderEventArgs(instanceId, orderId));
    }
    public void RaiseOrderShippedEvent(string orderId, Guid instanceId)
    {
        if (OrderShipped != null)
            OrderShipped(null, new OrderEventArgs(instanceId, orderId));
    }
    public void RaiseOrderUpdatedEvent(string orderId, Guid instanceId)
    {
        if (OrderUpdated != null)
            OrderUpdated(null, new OrderEventArgs(instanceId, orderId));
    }
    public void RaiseOrderProcessedEvent(string orderId, Guid instanceId)
    {
        if (OrderProcessed != null)
            OrderProcessed(null, new OrderEventArgs(instanceId, orderId));
    }
    public void RaiseOrderCanceledEvent(string orderId, Guid instanceId)
    {
        if (OrderCanceled != null)
            OrderCanceled(null, new OrderEventArgs(instanceId, orderId));
    }
    public event EventHandler<OrderEventArgs> OrderCreated;
    public event EventHandler<OrderEventArgs> OrderShipped;
    public event EventHandler<OrderEventArgs> OrderUpdated;
    public event EventHandler<OrderEventArgs> OrderProcessed;
    public event EventHandler<OrderEventArgs> OrderCanceled;
}

ここで、注文サービスを伴ったアセンブリをコンパイルし、State Machine ワークフロー プロジェクトに戻ります。 ワークフロー プロジェクトでは、まず最初に、新規作成されたアセンブリへの参照を追加します。 次に、4 つの State アクティビティを追加し、それぞれに WaitingForOrderStateOrderOpenStateOrderProcessedStateOrderCompletedState という名前を付けます。

表 3 はワークフローの状態を示します。 それぞれの状態には、別の状態への遷移を可能にするいくつかのイベントがあります。

3. 注文の State Machine サンプル

状態 サポート イベント 遷移先

WaitingForOrderState

OrderCreated

OrderOpenState

OrderOpenState

OrderUpdated

OrderOpenState

 

OrderProcessed

OrderProcessedState

OrderProcessedState

OrderUpdated

OrderOpenState

 

OrderCanceled

Terminate アクティビティ

 

OrderShipped

OrderCompletedState

OrderCompletedState

 

 

図を実装するには、各 State アビリティに、この表に示したサポート イベントと同数の EventDriven ブロックを追加します。 たとえば、WaitingForOrderState という名前の State アクティビティには、 OrderCreatedEvent (名前は任意) など 1 つの EventDriven アクティビティが含まれます。 図 16 に示すように、EventDriven アクティビティには、外部イベントをキャプチャして新しい状態に遷移するための HandleExternalEvent アクティビティと SetState アクティビティが埋め込まれています。

wwfgetstart16.gif

16. OrderCreatedEvent EventDriven アクティビティの内部の表示

HandleExternalEvent アクティビティの [Properties] (プロパティ) ウィンドウで、目的のデータ交換サービス (この例では IOrderService インターフェイス) とサブスクライブするイベント名を選択します。 HandleExternalEvent アクティビティの [Properties] (プロパティ) ウィンドウで [InterfaceType] (インターフェイスの種類) エントリをクリックすると、Visual Studio 2005 によって、プロジェクトで使用可能なデータ交換サービスの一覧が表示されます。 サービスを選択すると、そのサービスによって公開されたイベントの一覧が、EventName プロパティに反映されます。 目的のイベントを選択し、次へ進みます。 OrderCreatedEvent アクティビティでは、OrderCreated イベントを選択します。

SetState アクティビティにより、マシンは TargetStateName プロパティに示された新しい状態に遷移します。 図 16 では、SetState アクティビティは OrderOpenState に設定されています。

表 3 のすべての状態およびイベント シンクに対して上記の操作を繰り返すと、図 17 のようなワークフローになります。

wwfgetstart17.gif

17. 注文の State Machine の完成

最後のステップでは、Windows フォーム アプリケーションを構築してワークフローをテストします。 ユーザー インターフェイスには、すべての保留中の注文を追跡するためのリスト ビュー、および新しい注文を作成するためのテキスト ボックスとボタンが含まれます。 その他のボタンは、注文の更新、処理、および終了のために使用されます。

State Machine ワークフローは、Form_Load イベントで初期化されます。 State Machine ワークフローの初期化は、特に状態の変化を追跡できるようにする場合、Sequential ワークフローよりも少し複雑です。 次のコード サンプルは、ワークフロー ランタイムを初期化する方法を示します。

private void StartWorkflowRuntime()
{
   // このアプリケーションの新しいワークフロー ランタイムを作成します。
   _runtime = new WorkflowRuntime();
   // WorkflowRuntime オブジェクトのイベント ハンドラを登録します。
   _runtime.WorkflowTerminated += new
          EventHandler<WorkflowTerminatedEventArgs>(WorkflowRuntime_WorkflowTerminated);
   _runtime.WorkflowCompleted += new
          EventHandler<WorkflowCompletedEventArgs>(WorkflowRuntime_WorkflowCompleted);
    // StateMachineTrackingService クラスの新規インスタンスを作成します。
    _stateMachineTrackingService = new StateMachineTrackingService(_runtime);
    // OrderService のホスト サービスを作成し、ランタイムに追加します。
    ExternalDataExchangeService dataService = new ExternalDataExchangeService();
    _runtime.AddService(dataService);
    // OrderService の新規インスタンスをホスト サービスに追加します。
    _orderService = new OrderService();
    _runtime.AddService(_orderService);
}

ランタイムに加えて、StateMachineTrackingService が実行され、ワークフローの状態の変化を追跡する機能によってランタイムが拡張されます。 データ交換サービスのインスタンスもランタイムに追加されます。

ユーザーがクリックして新しい注文を作成すると、次のコードが実行されます。

private Guid StartOrderWorkflow(string orderID)
{
   // WorkflowInstanceId の新規 GUID を作成します。
   Guid instanceID = Guid.NewGuid();
   // OrderWorkflows アセンブリを読み込みます。
   Assembly asm = Assembly.Load("OrderWorkflows");
   // OrderWorkflows.Workflow1 クラスへの型参照を取得します。
   Type workflowType = asm.GetType("OrderWorkflows.Workflow1");
   // 状態の追跡のサポートが有効な State Machine の新規インスタンスを開始します。
   StateMachineInstance stateMachine =
          _stateMachineTrackingService.RegisterInstance(workflowType, instanceID);
   stateMachine.StateChanged += new
          EventHandler<ActivityEventArgs>(StateMachine_StateChanged);
   stateMachine.StartWorkflow();
   _stateMachineInstances.Add(instanceID.ToString(), stateMachine);
   // ワークフロー GUID を返します。
   return instanceID;
}

まず初めに、ワークフロー インスタンスをインスタンス化し、状態の変化のためのイベント ハンドラを登録します。 型情報を取得するための .NET Reflection の使用は、厳密には必要ではありませんが、柔軟性がさらに向上します。 通常の従来からの typeof 演算子にも同じ効果があり、ワークフロー ランタイムにワークフロー インスタンスの型を伝えます。

図 18 に、実行中のサンプル アプリケーションを示します。 選択したワークフロー インスタンスの状態に基づいて、ボタンが使用可能になります。

wwfgetstart18.gif

18. Windows フォーム   アプリケーションでホストされた State Machine ワークフロー  

ユーザーが任意のボタンをクリックすると、通信インターフェイス上の対応するイベントが発生し、ワークフローのイベント シンクによって検出されます。 たとえば、未確定の状態のワークフロー インスタンスに対して [Order Processed] ボタンをクリックすると、次の処理が実行されます。

private void btnOrderEvent_Click(object sender, EventArgs e)
{
   // クリックされたボタンの名前を取得します。
   string buttonName = ((Button)sender).Name;
   // 選択された注文の GUID を取得します。
   Guid instanceID = GetSelectedWorkflowInstanceID();
   // 選択された注文の ID を取得します。
   string orderID = GetSelectedOrderID();
   // 先に進む前にボタンを無効にします。
   DisableButtons();
   // クリックされたボタン名に基づき、動作を決定します。
   switch(buttonName)
   {
      // Order Local Service を使用して OrderShipped イベントを起動します。
      case "btnOrderShipped":
         _orderService.RaiseOrderShippedEvent(orderID, instanceID);
     break;
      // Order Local Service を使用して OrderUpdated イベントを起動します。
      case "btnOrderUpdated":
         _orderService.RaiseOrderUpdatedEvent(orderID, instanceID);
         break;
      // Order Local Service を使用して OrderCanceled イベントを起動します。
      case "btnOrderCanceled":
         _orderService.RaiseOrderCanceledEvent(orderID, instanceID);
         break;
      // Order Local Service を使用して OrderProcessed イベントを起動します。
      case "btnOrderProcessed":
         _orderService.RaiseOrderProcessedEvent(orderID, instanceID);
         break;
     }
}

ワークフローで発生したイベントは、図 19 に示す EventDriven アクティビティによって検出されます。

wwfgetstart19.gif

19. Order Processed イベントを処理する State Machine EventDriven ブロック

HandleExternalEvent アクティビティは、イベントを検出し、SetState アクティビティによって設定された状態に遷移して、イベントを処理します。 ワークフローの状態の変化は、追加の状態追跡サービスによって検出され、StateChanged イベントを通じてホストに報告されます (上記を参照)。

http://msdn.microsoft.com/workflow (英語) に、この記事で説明したすべての例の完全なソース コードおよび詳細なワークフローの内容が掲載されています。

まとめ

Windows Workflow Foundation は、新規および既存のマイクロソフト製品のワークフロー フレームワークとなるように設計され、.NET プラットフォームのワークフロー駆動型アプリケーションを作成する必要があるすべての開発者に対して、WinFX の処理能力と Visual Studio 2005 の使いやすさを提供します。

Windows Workflow Foundation がもたらした主な利点は、多くの独自のライブラリが統一されたワークフロー モデルおよびツールのセットに置き換えられたことです。 この点で、Windows Workflow Foundation は、今日のワークフロー製品のベンダにとって重要な意味を持ちます。Windows Workflow Foundation の導入により、ベンダは下位レベルのコードを維持する必要がなくなり、上位レベルのタスクに集中できます。

Windows Workflow Foundation は、特定の種類のアプリケーションやニーズに対応するだけのワークフロー テクノロジではありません。 Windows Workflow Foundation は、すべてのレベルで拡張性を提供するように設計された幅広いフレームワークです。 このような拡張性を最もよく示している例には、カスタム アクティビティとプラグ可能なランタイム サービスがあります。 カスタム アクティビティを使用すると、ワークフローの作成に使用できる構成単位のセットが拡張されます。 データの保存や追跡などのランタイム サービスは、アプリケーションの環境に合わせて変更でき、Microsoft SQL Server または他のベンダのデータベースに保存することが可能です。

Windows Workflow Foundation のための Visual Studio 2005 の拡張により、ワークフローの視覚的なモデリングおよびコードへの直接アクセスが可能になります。

ビジュアル デザイナは、他のデザイン環境でホストすることも可能です。デザイナの提供者は、視覚的なモデリング機能を独自の環境に埋め込み、アプリケーションのユーザーに使い慣れた作業環境を提供できます。

この記事では、動作の概要、内部構造、および一般的なサンプル コードを示して、Windows Workflow Foundation のテクノロジと機能の概要のみを説明しています。

執筆者紹介

Dino EspositoSolid Quality Learning (英語) leave-msの指導者であり、『Programming Microsoft ASP.NET 2.0』 (2005 年、Microsoft Press) の著者です。 Dino はイタリアに在住し、世界各地で開催される業界のイベントで講演しています。 cutting@microsoft.com (英語) で連絡を取るか、 http://weblogs.asp.net/despos(英語) leave-ms のブログに参加してください。