環境:
Internet Information Services 7.0
Visual Studio 2008 Beta 2
こんにちは。
Tech ED 準備もまっさかりです。今日は、シェアポのデモ作りで1日が終わりました。
さて、連載中の以下ですが、今日は Part2 ということで、前回作成したアクティビティを使って、ワークフローを組んでいきましょう。(sample code は Part1 で添付しています。)
Part1 : アクティビティ (Activity) の実装
Part2 : フロー (Workflow) の実装
Part3 : IHttpHandler を使ったホストの実装
前回作成した [Sequential Workflow Library] のプロジェクトで (無論、StateMachine でも構いません) をそのまま使用しましょう。(実際、前回作成したアクティビティは汎用性があり、今回作成するフローのほうは「支払い処理」、「受注処理」などある処理に特化しているので、現実の開発では、ネーミングを変えてプロジェクトをわけておいたほうが良いでしょう。)
このシナリオでは、「商品選択画面」(Select アクションと命名します)で商品選択をおこない、「支払いと送付先確認画面」(Payment アクションと命名します)で確定がキャンセルかをユーザが選択し、確定であれば「確認画面」(Confirmアクションとしましょう)を表示して終了し、キャンセルであればまた「商品選択画面」に戻ってユーザに選択をやり直しをおこなうようにしましょう。
ですので、ワークフローのデザイナー上では、while の中に Select アクションに相当するアクティビティ (第1回で作成した画面アクティビティ) と Payment アクションに相当するアクティビティ (第1回で作成した画面アクティビティ) を入れて、while を抜けたら Confirm アクションに相当するアクティビティ (第1回で作成した画面アクティビティ) をツールボックスからドラッグアンドドロップして挿入します。(名前もわかりやすいように適当に変更してください。)
下図のようになります。
さて、挿入した各 BuyActivity アクティビティのプロパティを設定していきましょう。
前回記載した通り、このアクティビティには、ActionType (画面の種類を教える)、WorkflowId (アクティビティ側で CallExternalMethod を呼ぶだめに実行中のワークフローIDを渡す) のプロパティをそれぞれ渡す仕様になっていました。
そこで、バインドの準備として、コードに、以下の変数を定義して準備します。
public const string ActionTypeSelect = "Select";public const string ActionTypePayment = "Payment";public const string ActionTypeConfirm = "Confirm";public Guid InstanceId{get { return WorkflowEnvironment.WorkflowInstanceId; }}
そして、これら変数を ActionType、WorkflowId の各プロパティに、デザイナーを使ってバインドしておきます。
なお、入力欄の右の […] のボタンを押しても正しくバインド用のダイアログボックスが表示されない場合は、プロパティウィンドウの中のフィールド名の右にある小さなアイコンをダブルクリックしてみてください。(ここが、正式なバインド専用のランチャーです。)
もう 1 つ、プロパティがありました。今度は、ホストの画面側からアクティビティに送られてくるユーザの指定したデータ一式の Hashtable である BuyVariables プロパティです。これをワークフロー側で受け取って処理できるよう、以下の変数も作成して、同様に、デザイナー上で、この内部変数とプロパティをバインドしておきます。
private Hashtable buyVariables = null;public Hashtable BuyVariables{get { return buyVariables; }set { buyVariables = value; }}
あとは、While アクティビティの条件を指定しておく必要があります。
今回は、ユーザが [確定] ボタンを押したら抜けて、[キャンセル] の場合はループするという処理になるので、「確定」か「キャンセル」なのかがわかる目印が必要になります。この辺りは、デザイン上さまざまなベストプラクティスが考えられますが、今回は、ワークフローと画面の間の約束(契約)として、Hashtable の “SubmitType” というキーを目印に、ここに “Ok” という文字列が入っていたら「確定」、”Cancel” という文字が入っていたら「キャンセル」という約束にしておきましょう。(他にも、例えば、汎用的なクラスであるアクティビティが決める約束として、Ok, Cancel, Yes、No, … など決まった雛形のインタフェース方法を決めておき、この方法に準じて、ワークフローの種類に係わらず同じ方法でインタフェースをおこなうといった方法も美しいでしょう。このあたりは、もっときれいな実装が可能となるでしょう。)
そこで今回は、While をコード条件として指定し、判断する関数を IsProceed という名前で以下の通り作成しておきます。
private void IsProceed(object sender, ConditionalEventArgs e){e.Result = true;if(BuyVariables == null)return;if(BuyVariables["SubmitType"].ToString() == "Ok")e.Result = false;}
また補修工事として、このままでは、”SubmitType” や “Ok” といった約束語を 画面とワークフローの両方がそろえておく必要があるので、ワークフローを使うすべてのホストでこの約束語をリファレンスして使えるように、以下の通り定数として宣言し、公開しておくと良いでしょう。
またこれにあわせ、上記の IsProceed の中も、ConditionKey や ConditionValueOK を使って書き換えておきましょう。
public const string ConditionKey = "SubmitType";public const string ConditionValueOK = "Ok";public const string ConditionValueCancel = "Cancel";
では、さいごに、作成されたアクティビティとワークフローの流れをもう1度おさらいしておきましょう。
まず、ホスト側がワークフローインスタンスを開始します。すると、上記のワークフローが動いて、上図の SelectActivity の中で、CallExternalMethod を使い、”Select” を action パラメータ (Part1 を参照) としてホスト側に画面遷移を要求します。ホスト側は、この要求を受けて、専用の「商品選択画面」などの適切な画面に遷移します。ここでいったんワークフローインスタンス側は idle 状態になります。
つぎに、画面でユーザの入力など一連の操作がおわって確定されると、今度は、ホスト側がイベントを渡してきます。これをアイドル状態であったワークフローインスタンスの HandleExternalEvemt アクティビティ (上図の SelectActivity の中に入っています) がキャッチし、またワークフローインスタンスのスケジュールが開始され、すぐさま上図の PaymentActivity の中の CallExternalMethod が、今度は action パラメータを “Payment” として実行します。この処理の間、ホスト側は待機していることになります。
いや、ちょっと待ってください!! ワークフローインスタンスは、デフォルトでは、ホストとは別のスレッドで動くはずでした。ということは待機などするはずもありません!!!!! なんか動かないような気がしてきましたね、、、
この答えは、すべてホスト側の処理にあります。次回は、このホスト側の処理について記述をおこなっていきます。
Categories: Uncategorized
PingBack from http://blogs.msdn.com/tsmatsuz/archive/2007/08/16/wf-web-part-1.aspx
LikeLike