WWF永続化サンプルその2

前々回の記事で書いた永続化の話の続きです。
今回は永続化とイベント処理のサンプルを見つけたので紹介します。
前々回に紹介したサンプルは遅延アクティビティに入ったら、
自動的に永続化され、タイマーサービスを使って一定時間後に
ワークフローが起動されるサンプルでした。
今回は、イベントを使ってワークフローの起動を行っている重要なサンプルです。

Raise Event To Load Workflow Sample
WWF Help > Windows Workflow Foundation Samples > Technology Samples
  > Hosting > Raise Event To Load Workflow


1. ワークフローの修正
サンプルを実行する前に、いくつかソースコードを修正する必要がありました。
まずは ビルドを行って、インターフェース定義を参照できるようにします。
その後ワークフローの2つのアクティビティのプロパティを修正します。
今回のサンプルはデータベースは必要ありません、永続化にはファイルを使っています。

SendDocumentアクティビティ
以下のプロパティを指定します。

InterfaceType: Microsoft.Samples.Workflow.Technologies.Hosting.RaiseEventToLoadWorkflow.IDocumentApproval
MethodName : RequestDocumentApproval
MethodInvoking : sendDocumentMethodInvoking

DocumentApprovedアクティビティ
以下のプロパティを指定します。

InterfaceType: Microsoft.Samples.Workflow.Technologies.Hosting.RaiseEventToLoadWorkflow.IDocumentApproval
EventName : DocumentApproved
MethodInvoking : documentApprovedInvoked

以上の修正でサンプルを実行できるはずです。

2. サンプルの実行
デバッグ実行してサンプルがどのように動作するか確認します。
イベントによって処理がアチコチに飛ぶので、
どの順番で何が動くか確認しておくことをお勧めします。

3. インターフェース定義の確認
いつものごとく、大切なものはソースコードの中にあります。
まずはイベントを処理するインターフェース定義を確認します。
下は、DocumentApprovalInterfaceプロジェクトの
DocumentApprovalInterface.csファイル内の定義です。

    [Serializable]
    public class DocumentEventArgs : WorkflowMessageEventArgs
    {
        private Guid documentId;

        public DocumentEventArgs(Guid instanceId)
            : base(instanceId)
        {
            this.documentId = instanceId;
        }

        public Guid DocumentId
        {
            get { return this.documentId; }
            set { this.documentId = value; }
        }
    }

    [DataExchangeService]
    public interface IDocumentApproval
    {
        // send Documentument for approval
        void RequestDocumentApproval(Guid documentId, String approver);
        
        // received Documentument approval
        event EventHandler<DocumentEventArgs> DocumentApproved;
    }

インターフェース定義だけ見ても?な感じなので実装コードも確認しましょう。

4.実装コードの確認
さきほどのインターフェース定義の実装クラスと
それをワークフローで利用しているコードになります。
これはDocumentApprovalWorkflowプロジェクト内のProgram.csファイルにあります。

    class Program
    {
        static AutoResetEvent waitHandle = new AutoResetEvent(false);
        static DocumentApprovalService documentApprover = new DocumentApprovalService();

        static void Main(string[] args)
        {
            WorkflowRuntime workflowRuntime = new WorkflowRuntime();

            workflowRuntime.UnloadOnIdle = true;
            workflowRuntime.AddService(new FilePersistenceService());
            workflowRuntime.StartRuntime();
            workflowRuntime.AddService(documentApprover);

            workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
            workflowRuntime.WorkflowIdled += OnWorkflowIdled;
            workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;
            workflowRuntime.ExceptionNotHandled += onExceptionNotHandled;

            Type type = typeof(Microsoft.Samples.Workflow.Technologies.Hosting.RaiseEventToLoadWorkflow.Workflow1);
            workflowRuntime.StartWorkflow(type);

            waitHandle.WaitOne();
        }

        class DocumentApprovalService : IDocumentApproval
        {
            private Guid documentId;
            private string approver;
 
  ...
        }

サンプル内のコメントや例外処理のコードは、見やすくなるように削除しています。
ポイントは、インターフェース定義を実装したクラスを
ワークフローランタイムにカスタムのサービスとして追加している箇所です。
つまり、ワークフロー上で発生したイベントがワークフローランタイムに通知され、
そのイベントを処理するカスタムのサービスを処理するサービスも追加できるということです。
コードだけだと理解しにくいのでイメージ図を描いてみました。

永続化サンプル2のイベント処理イメージ図

あと、このサンプルを動かしてみてわかったんですが、
WWFの永続化のタイミングは特定のアクティビティに入った時点で行われるようです。
遅延(Delay)アクティビティやEventSinkアクティビティに入った時点でイベントが発生します。
他にも永続化のイベントが発生するアクティビティはありそうですね。

今日は長くなってしまったので、これぐらいで。