ブックマークによる入力待機など高機能を利用できるNativeActivity
WF 4の機能の中で、外部と情報のやりとりを行うために用意されているのがブックマークと呼ばれる機能です。簡単に言うと、一時的にワークフローの実行を中断し外部からの入力を待機する処理を行うものです。その利用シーンとしてはさまざまで、別プロセスの結果を元に何かしらのワークフローを実行させたり、反対にワークフローが別プロセスの制御を行うために利用することがあります。海外のサイトではASP.NET MVCのコントローラ制御をWF 4にて行うといった形で利用しているものも公開されています。
このように何かしらのやりとりを行う際に必須となるブックマークですが、なぜかWF 4の標準アクティビティとしては提供されていません。ここではブックマークを作成し外部からの入力を受け取るアクティビティを実装してみます。
Imports System.Activities
Public Class SampleBookmarkActivity
Inherits NativeActivity
Public Property HostValue As OutArgument(Of String)
Protected Overrides ReadOnly Property CanInduceIdle As Boolean
Get
Return True
End Get
End Property
Protected Overloads Overrides Sub Execute(ByVal context As System.Activities.NativeActivityContext)
context.CreateBookmark("TestBookmark", New BookmarkCallback(AddressOf OnResume))
End Sub
Private Sub OnResume(ByVal context As NativeActivityContext, ByVal bookmark As Bookmark, ByVal value As Object)
context.SetValue(Me.HostValue, value)
End Sub
End Class
Imports System.Activities
Imports System.Activities.Statements
Imports System.Threading
Imports System.Activities.XamlIntegration
Module Module1
Sub Main()
Dim outValue As New Variable(Of String) With {.Name = "hostvalue"}
Dim actBm As New SampleBookmarkActivity With {
.HostValue = outValue
}
Dim actWl As New WriteLine With {
.Text = New InArgument(Of String)(Function(env) outValue.Get(env) + " が入力されました")
}
Dim seq As New Sequence
seq.Variables.Add(outValue)
seq.Activities.Add(actBm)
seq.Activities.Add(actWl)
Dim resetEvent As New AutoResetEvent(False)
Dim wfApp As New System.Activities.WorkflowApplication(seq)
'ワークフロー実行完了時に待機状態を終了する
wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs)
resetEvent.Set()
End Sub
wfApp.Run()
Console.WriteLine("何か値を入力してください")
wfApp.ResumeBookmark("TestBookmark", Console.ReadLine())
resetEvent.WaitOne()
Console.ReadLine()
End Sub
End Module
using System;
using System.Activities;
namespace SampleBookmark
{
class SampleBookmarkActivity:NativeActivity
{
public OutArgument HostValue { get; set; }
protected override bool CanInduceIdle { get { return true; } }
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark("TestBookmark", OnResume);
}
private void OnResume(NativeActivityContext context, Bookmark bookmark,Object value)
{
context.SetValue(this.HostValue, (string)value);
}
}
}
using System;
using System.Activities;
using System.Activities.Statements;
using System.Threading;
namespace SampleBookmark
{
class Program
{
static void Main(string[] args)
{
Variable outValue = new Variable
{
Name = "outValue"
};
Activity seq = new Sequence
{
Variables = { outValue },
Activities = {
new SampleBookmarkActivity()
{
HostValue=outValue
},
new WriteLine()
{
Text = new InArgument((env) => outValue.Get(env) + " が入力されました")
}
}
};
AutoResetEvent resetEvent = new AutoResetEvent(false);
WorkflowApplication wfApp = new WorkflowApplication(seq);
//ワークフロー実行完了時に待機状態を終了する
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
resetEvent.Set();
};
wfApp.Run();
Console.WriteLine("何か値を入力してください");
wfApp.ResumeBookmark("TestBookmark", Console.ReadLine());
resetEvent.WaitOne();
Console.ReadLine();
}
}
}
実行すると上記のようにワークフローのホスト側にて入力を求められます。そこで入力した値は、アクティビティにより作成されたブックマークを用いて、待機状態となっているワークフローへと引き渡されます。渡された値がWriteLineアクティビティにて標準出力へとそのまま出力されているのがわかると思います。
このような形でワークフローをホストするアプリケーションと、実行されているワークフローとの間で値のやりとりを行うことができます。その際に必要となるのがブックマーク名です。これは自由に名付けて構わないのですが、ワークフローランタイム上で重複しないことが必要です。ワークフローを数多く実行させる際には、何らかの重複しない名前付け規則が必要になります。
