WF 4 のカスタム TrackingParticipant の実装 (Tech Ed 2010 セッション補足 1)

環境:
Visual Studio 2010 (.NET Framework 4)

トラッキングのカスタマイズ

こんにちは。

Tech Ed Japan 2010 のセッション (T6-402 「Windows Server AppFabric を使用したサービスホスティングと分散キャッシュの実践ノウハウ」) にご参加いただいた皆様、ありがとうございました。
いつものことで申し訳ありませんが、セッションでスッ飛ばしたデモの数々のうち、まずは、カスタムトラッキングのサンプルについてフォローさせていただきます。(1 回で記載するのは大変ですので、4 回連載で記載します。) この連載の終わりには、昨日説明したカスタムのトラッキングプロファイル (Tracking Profile) の手法などと組み合わせ、自由自在なトラッキングのカスタマイズがおこなえるよう、ステップ・バイ・ステップで記載していきます。

なお、セッションでご紹介したカスタムのトラッキングプロファイル (及び、そこで使用する XML ファイル) ですが、下記の WorkflowTrackingProfileEditor を使用すると、リホスティングされた WF のデザイナーを使って、昨日紹介したようなカスタムの変数のトラッキングなどをおこなうトラッキングプロファイル (.tp ファイル) を作成できます。慣れてきたら XML を直接編集して頂いてOKですが、これからはじめる方は是非活用してみてください。

http://blogs.technet.com/b/chriscraft/archive/2010/05/01/a-sample-net-4-wf-tracking-profile-editor.aspx

では、手始めとして、今回は、簡単なカスタム TrackingParticipant を作成して実際にこれを使用してみましょう。

まず、Visual Studio 2010 を起動してコンソールアプリケーションを新規作成し (ターゲットフレームワークは、もちろん .NET Framework 4 です)、System.Activities.dll を参照追加します。

つぎに、TrackingParticipant クラスから継承された独自の (カスタムの) TrackingParticipant を作成します。今回は、c:tmptest.txt にトラッキングされた内容を出力します。
クラスを新規追加し、以下の通り記述しましょう。

. . .

using System.IO;
using System.Activities.Tracking;

class MyTrackingParticipant : TrackingParticipant
{
    protected override void Track(TrackingRecord record, TimeSpan timeout)
    {
        FileStream st = File.Open(@"c:tmptest.txt", FileMode.Append);
        StreamWriter writer = new StreamWriter(st);
        writer.WriteLine("Record#:{0}",
            record.RecordNumber);
        writer.WriteLine("Type:{0}, Level:{1}",
            record.GetType().FullName,
            record.Level);

        if (record is WorkflowInstanceRecord)
        {
            // ワークフローインスタンスのトラック
            WorkflowInstanceRecord workflowInstanceRecord =
                record as WorkflowInstanceRecord;
            writer.WriteLine("InstanceID: {0} State: {1}",
                record.InstanceId,
                workflowInstanceRecord.State);
        }
        else if (record is ActivityStateRecord)
        {
            // アクティビティのトラック
            ActivityStateRecord activityStateRecord =
                record as ActivityStateRecord;
            writer.WriteLine("ActivityName: {0}, InstanceState: {1}",
                activityStateRecord.Activity.Name,
                activityStateRecord.State);
            // Variables は activityStateRecord.Variables で取得可 (省略)
        }
        else if (record is CustomTrackingRecord)
        {
            // カスタムデータのトラック
            CustomTrackingRecord customTrackingRecord =
                record as CustomTrackingRecord;
            writer.WriteLine("カスタムデータです!");
            // customTrackingRecord.Data で Key-Value ペアを取得可能 (省略)
        }
        else
        {
            writer.WriteLine("その他の場合");
        }

        writer.WriteLine();

        writer.Close();
        st.Close();
    }
}

トラッキングでは、インスタンスの開始・終了や、アクティビティの実行開始・クローズなど、さまざまなタイプのトラッキング情報がやってきます。この際、到着するトラッキングのタイプによってレコードの型が異なるため、上記の通り、キャストをおこなって専用の型に変換し、必要な情報を取得します。
なお、上記で CustomTrackingRecord という型を使用していますが、これについてはあとで補足しましょう。

さいごに、このカスタムの TrackingParticipant を WorkflowInvoker の Extension に Add すれば終わりです。ただし、昨日述べたように、どのようなトラッキングプロファイル(エラー、情報など、トラッキングをおこなう「レベル」や、開始、完了など、トラッキングする「状態」など)を使用するか TrackingProfile に指定する必要があります。昨日のセッションでは、すべて、構成ファイル (.config) でこの記述をおこないましたが、今回は、プログラミングによってこの指定をおこないます。 (上記を構成ファイルで指定させる方法については、この連載の第 3 回で説明します。)
Main に下記の通り記述します。

. . .

using System.Activities;
using System.Activities.Statements;
using System.Activities.Tracking;

static void Main(string[] args)
{
    MyTrackingParticipant myTracking =
        new MyTrackingParticipant()
    {
        TrackingProfile = new TrackingProfile()
        {
            Name = "CustomTrackingProfile",
            Queries = 
            {
                new CustomTrackingQuery() 
                {
                    Name = "*",
                    ActivityName = "*"
                },
                new WorkflowInstanceQuery()
                {
                    States = { WorkflowInstanceStates.Started,
                        WorkflowInstanceStates.Completed },
                },
                new ActivityStateQuery()
                {
                    ActivityName = "*",
                    States = { "*" },
                    Variables = 
                    {                                
                        { "*" }   
                    }
                }   
            }
        }
    };

    WorkflowInvoker invoker = new WorkflowInvoker(new Sequence()
    {
        Activities =
        {
            new WriteLine() { Text = "開始" },
            new Delay() { Duration=new InArgument<TimeSpan>(new TimeSpan(0, 0, 3))},
            new WriteLine() { Text = "終了" },
        }
    });

    invoker.Extensions.Add(myTracking);

    invoker.Invoke();

    Console.ReadLine();
}

以上でプログラミングは終了です。

これを実行すると、c:tmptest.txt に以下の通り出力されるはずです。

Record#:0
Type:System.Activities.Tracking.WorkflowInstanceRecord, Level:Info
InstanceID: e10fdc28-b1a1-4483-a1cd-5e3e3df6b149 State: Started

Record#:2
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: Sequence, InstanceState: Executing

Record#:4
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: WriteLine, InstanceState: Executing

Record#:5
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: WriteLine, InstanceState: Closed

Record#:6
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: Delay, InstanceState: Executing

Record#:8
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: Delay, InstanceState: Closed

Record#:9
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: WriteLine, InstanceState: Executing

Record#:10
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: WriteLine, InstanceState: Closed

Record#:11
Type:System.Activities.Tracking.ActivityStateRecord, Level:Info
ActivityName: Sequence, InstanceState: Closed

Record#:12
Type:System.Activities.Tracking.WorkflowInstanceRecord, Level:Info
InstanceID: e10fdc28-b1a1-4483-a1cd-5e3e3df6b149 State: Completed

ところで、上記でカスタムのトラッキング情報 (CustomTrackingRecord) を使用していましたが、カスタムアクティビティなどで、注文番号や、発注数など、そのアクティビティ独自のカスタムなデータをトラッキングする場合にこの CustomTrackingRecord を使用します。

なお、昨日のセッションで説明したように、アクティビティの入出力データの場合は、わざわざこのようなことをしなくても、カスタムのトラッキングプロファイルを設定するだけで、これらのデータを出力 (トラッキング) できます。

以下に、このカスタムのトラッキング情報を出力するカスタムアクティビティのサンプルを例示しておきます。(下記の通り、Key-Value のペアをデータとして渡します。)

class CustomTrackDemoActivity : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
        CustomTrackingRecord customRecord = new CustomTrackingRecord("OrderIn")
        {
            Data = 
            {
                {"OrderId", 200},
                {"OrderDate", "20 Aug 2001"}
            }
        };
        context.Track(customRecord);
    }
}

まもなく Tech Ed フィナーレとなりますが、3 日間、お疲れ様でした。
月曜はお休みを頂きますので、続きは、ちょっとあとになります。。。

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s