(Part 2) SharePoint ワークフローで Modification Form (修正フォーム) を開発する際のいくつかのポイント

※ 以下、Tech ED T-405 セッションに関するフォローアップ記事 Part 2 です。 

  1. SharePoint Designer のカスタムアクティビティの開発で workflowProperties と同等の変数を使うには 
  2. SharePoint ワークフローで Modification Form (修正フォーム) を開発する際のいくつかのポイント
  3. Replicator を使いこなす (実行時にワークフローの流れを変える)
  4. SharePoint ワークフローにおけるカスタムなワークフローステータスの設定
  5. SharePoint ワークフロー : 上級者のための IListItemService の活用
  6. SharePoint の Workflow 用 Web Service を使ってシステム連携をおこなう

環境:
Microsoft Office SharePoint Server 2007
Visual Studio 2005 (及び Workflow 用の extensions)
Office SharePoint Server 2007 SDK

こんにちは。

Modification Form (修正フォーム) については、フォーム統合のデモで一緒にご説明する予定でしたが (デモで準備していたのですが)、まったく時間がないので割愛してしました。この修正フォームというワークフローフォームの実装ですが、実は、作成の際にいくつかポイントがありますので、以下ではそのポイント(当日説明しようと思っていた内容)を記載していきます。

【コツ1 : Modification Form の実行タイミング】

以前も記載しましたが、ワークフローの Modification Form (修正フォーム) では、他のワークフローフォームと異なり、実行中に常に呼びだして実行できる必要があります。これをワークフローを使って実現しようと思うと、フローの随所で修正フォームのイベントを扱う処理(アクティビティなど)を埋め込む必要があるように思われるかもしれませんが、こうした場合には、EventHandlingScope アクティビティが使用できます。(WF のアクティビティ説明については、こちら を参照。)

このアクティビティは、バックで処理できるメインのワークフローとは別のワークフローを作成し、メインのフロー実行中にいつでも何度でもバックエンドのフローを処理できるというアクティビティです。

この EventHandlingScope アクティビティを使った修正フォームのサンプルコードについては、SharePoint SDK (ECM Starter Kit) のサンプル「Modification Sample」に入っていますので参照しておいてください。

尚、EventHandlingScope アクティビティは、通常は、SequenceActivitiy (Sequential Workflow もこの SequenceActivitiy から継承されたアクティビティです) の中などに入れて使います。ですので、ステートマシンワークフロー全体で、この EventHandlingScope アクティビティと同様の技は使用できませんので注意してください。(その意味からすると、修正フォームと State Machine Workflow は相性が悪いということになります。)

【コツ2 : EnableWorkflowModification の呼び出しとワークフローコンテキスト】

俗っぽい書き方ですみませんが、ワークフローの「modify されたぞイベント」(OnWorkflowModified アクティビティによるイベント処理) を有効にするには、IWorkflowModificationService インタフェースが提供している EnableWorkflowModification メソッドを呼び出す必要があります。
このメソッドですが、ツールボックスに表示されている EnableWorkflowModification アクティビティを使うことで呼び出すことができますので、通常はそのようにします。

しかし、話は、実はそう簡単ではありません。
EnableWorkflowModification アクティビティですが、CallExternalMethodActivity の継承アクティビティです。そしてこの処理は、毎回 Modification が実行されるたび (OnWorkflowModified アクティビティを処理するたびに)、次回も Modification を待機できるように毎回呼び出す必要があります (これをしないと、1 度更新したら以降は更新用のリンクが表示されなくなります)。さて、初回の実行は、前述した EnableWorkflowModification アクティビティを使えば良いのですが、実は、2 回目以降は、この方法ではダメなのです。
EnableWorkflowModification アクティビティでは、Modification 用の Correlation Token を設定しますが、このアクティビティを使用してメソッドを実行すると、実はこのトークンの初期化処理というものが内部でおこなわれています。ですので、この Correlation Token の初期化が同じトークンに対して何度も実施されると、エラー (Exception) が発生てしまうのです。
先ほど、EnableWorkflowModification アクティビティは CallExternalMethodActivity の継承アクティビティであると説明しましたが、この「Correlation Token の初期化」という一見余計な処理は、SharePoint 独自機能ではなく、WF が提供する CallExternalMethodActivity の Execute (すべての WF のアクティビティで、この Execute が呼ばれて実行されます) の中でおこなわれています。通常はこうした処理 (CallExternalMethod アクティビティによる初期化) は便利なのですが、こうした SharePoint の修正フォームのように、何度も呼び出す場合にはこの処理が邪魔になってしまうわけです。

そこで、これを回避するには、2 回目以降では、設定された IWorkflowModificationService の実装 (Implementation) を直接取得して、この中の EnableWorkflowModification を直接呼び出すことが必要になるわけです。方法はいくつか存在しますが、皆さんが身近にもっている ECM Starter Kit のサンプル (Modification Sample) を例にしたほうがコードも見られて良いでしょうから、以下はこの例に沿ってワークアラウンドを説明します。(すみません、Tech ED では、専用のコードを用意していましたが、ここでは、ECM Starter Kit のサンプルを例にご紹介します。)
サンプル「Modification Sample」では、この 2 回目以降の処理で、サンプル「ECMActivities」の中で作成されているカスタムアクティビティ WSSUpdateModificationContextActivity を呼び出しているのがおわかり頂けるでしょう。このように、カスタムアクティビティとして作成しておけば、Execute の引数で渡してくる ActivityExecutionContext からインタフェースの実装を GetService メソッドでそのまま取り出して実行することができるので、こうした方法で回避しているわけです。

【コツ3 : Contact Selector との相性】

このポイントは、ECM Starter Kit のサンプルには載っていません。

以前も記載しましたが、InfoPath のワークフローフォームでは、Contact Selector という SharePoint でお馴染みのユーザ選択用の ActiveX コントロールを使用することができます。(デモでお見せした ASP.NET に張り付いたものは、同じ用途のものですが People Picker と呼ばれます。これの ActiveX 版とお考えください。)

実はこの Contact Selector ですが、少し癖のあるコントロールなのです (以下、バグと言われても仕方ありませんが、Known Issue とお考えください)。
Contact Selector は、その内部で、XML の論理的なスキーマ構成でなく、宣言文字列を意識した実装がおこなわれており、結論を書くと、「my」というネームスペース (名前空間) の名前定義 (つまり、xmlns:my=@”[… form namespace …]” と記述) を宣言しておかないとエラーになります。この独特の癖は、通常の Initiation Form などでは出くわすことは少なかったことでしょう。なぜなら、InfoPath が my という名前を自動で生成してくれるからです。しかし、Modification Form (修正フォーム) では、通常のシナリオでは、変更前の XML (データ) を渡して処理するところから開始されるので、この現象と戦わなければならなくなります。この渡す XML に my が宣言されていないと、論理的に同じスキーマ構成の同じ XML データであっても、Contact Selector を使ってユーザ確認用のボタンやユーザ検索をおこなった際に 「my は宣言されていません」 とエラーが表示されます。
なお、こちら で記載しているような xsd.exe コマンドによる方法でクラスから XML に Serialize しても、my は挿入されず、このエラーに遭遇してしまいます。

このワークアラウンド (解決方法) も方法はいくつかあると思いますが、こうした理由さえ理解すれば、例えば以下のような手順で回避することができるでしょう。

  1. 作成した InfoPath の xsn をクライアントで起動し、ダミーデータを xml ファイルとして保存する (こうしておけば、その中で 「my」 が宣言されています)
  2. 上記の xml ファイルを Visual Studio のプロジェクトに取り込み、[ビルドアクション] を [埋め込まれたリソース] (embedded resource) に設定する (以下、これを text.xml としましょう)
  3. EnableWorkflowModification アクティビティの MethodInvoking ハンドラなど、xml のデータを context data に渡す箇所で、以下の要領で記載する。(変数や namespace などは適宜変更してください。)

// my を含む XmlDocument 雛型の作成
XmlDocument xDoc = new XmlDocument();
Assembly asm = Assembly.GetExecutingAssembly();
string[] resources = asm.GetManifestResourceNames();
foreach (string resource in resources)
{
    if (resource.EndsWith(“test.xml”))
    {
        Stream stream = asm.GetManifestResourceStream(resource);
        xDoc.Load(stream);
    }
}
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xDoc.NameTable);
nsMgr.AddNamespace(“my”, @”http://schemas.microsoft.com/office/infopath/2003/myXSD/2007-08-08T09:49:22″);

// Contact Selector への値渡し
SPUser myUser = workflowProperties.Web.AllUsers[userid];
Contact myContact = Contact.FromPrincipal(myUser);
XmlNodeList personList = xDoc.SelectNodes(@”/my:myFields/my:Reviewers/my:Person”, nsMgr);
XmlNode ndAccountId = personList[0].SelectSingleNode(@”./my:AccountId”, nsMgr);
ndAccountId.InnerText = myContact.LoginName;
XmlNode ndDisplayName = personList[0].SelectSingleNode(@”./my:DisplayName”, nsMgr);
ndDisplayName.InnerText = myContact.DisplayName;
XmlNode ndAccountType = personList[0].SelectSingleNode(@”./my:AccountType”, nsMgr);
ndAccountType.InnerText = Microsoft.SharePoint.WebControls.PeopleEditor.AccountType.User.ToString();

// その他属性への値渡し
XmlNode ndInstruction = xDoc.SelectSingleNode(@”/my:myFields/my:Instructions”, nsMgr);
ndInstruction.InnerText = “テスト”;

// ContextData へデータを渡す
this.modificationContextData1 = xDoc.InnerXml;

尚、ECM Starter Kit (SharePoint SDK) のサンプルでは Contact Selector を使わないように実装しています。(話を複雑にしないため、修正フォームの箇所のみ、単にテキストボックスを使って処理しています。)

Advertisements

2 thoughts on “(Part 2) SharePoint ワークフローで Modification Form (修正フォーム) を開発する際のいくつかのポイント

  1. こんにちは。 Tech ED 「T4-405 : Microsoft SharePoint Products and Technologies におけるワークフロー : 開発者向け詳述」 にご参加いただいた皆様、申し訳ございませんでした。もりだくさんすぎて、結局、予定していたデモの多くを残す結果となってしまいました。

    Like

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