松崎 剛 Blog

This Blog's theme : エンタープライズ開発 (Server side)、Office サーバ開発

SharePoint 2013 Apps: Remote Event Receiver の開発と Debug

SharePoint 2013 Apps: Remote Event Receiver の開発と Debug

  • Comments 0

環境 :
Office 365 (Preview)
Visual Studio 2012
Microsoft Office Developer Tools for Visual Studio 2012 (Preview2)

SharePoint 2013 Apps 開発

こんにちは。

今回は、リモート・イベント・レシーバー (Remote Event Receiver) の作成方法について解説します。

 

Remote Event Receiver とは ?

SharePoint 開発では、例えば、「リスト アイテムが追���された」、「変更された」などのイベントを検知して、カスタムの処理を実装できます。これを Event Receiver と呼んでいます。

SharePoint 2013 Apps では、従来の SharePoint 開発における Event Receiver (SharePoint 2010 までの Event Receiver) と異なり、リモート実行のモデルで動作します。(この実行モデルについては、「Apps for SharePoint 2013 の動作と概要」を参照してください。) プログラマーが作成した Event Receiver は、利用者 (エンドユーザー) が使用している SharePoint サイト (Server) 上で実行されるのではなく、Windows Azure などの別のリモート サイトにホストされて、SharePoint から呼び出されます。このため、この新しい Event Receiver は Remote Event Receiver と呼ばれます。
ユーザーから見た Remote Event Receiver の動作は従来の (SharePoint 2010 までの) Event Receiver と同様ですが、下記の通り、使用するクラスやプログラミング方法がまったく異なっており、プログラマーの方は、SharePoint 2013 Apps で刷新された新しい Event Receiver と考えてください。

SharePoint 2013 の Remote Event Receiver では、リスト (List)、リスト アイテム (List Item)、サイト (Web)、アプリ (App) の各イベントを処理できます。(「App がインストールされた」、「リストが削除された」など)

補足 : Remote Event Receiver は、一般に App web 上の要素 (リストなど) に対して適用しますが、プログラム コード (CSOM) を使って設定することで、Host web の要素 (リストなど) に対して Remote Event Receiver を適用することもできます。

補足 : 下記では、リスト アイテム (List Item) の Receiver を作成しますが、App の Receiver (App Event Receiver) を作成する場合は、下図の通り、プロジェクトのプロパティから追加します。
App Event Receiver のプログラミングについては、「List Definition の開発と Client Side Rendering (CSR)」を参照してください。

Remote Event Receiver は SharePoint の Feature として作成しますが、後述しますが、処理自体は、BasicHttpBinding (Simple な SOAP Web Service) による WCF サービスとして実装します。(Feature 内で、この WCF サービスの Url を定義します。) WCF については、「.NET 4 の WCF / WF 入門」を参照してください。

 

SharePoint 連携における Token (Authentication)

これまで見てきた Page のアプリケーション (App part 含む) では、SharePoint との連携 (SharePoint の処理の呼び出し) のための認証・認可用の Token を HTTP の POST データとして渡していました。(「.NET CSOM を使ったプログラミングと認証」を参照。) しかし、 Remote Event Receiver は、上述の通り、WCF サービス (SOAP Web サービス) であるため、この方法で Token を取得することはできません。代わりに、Remote Event Receiver では、WCF 呼び出しの際の HTTP ヘッダーを使って Token を送信します。
WCF の処理の中から、下記の通り、「X-SP-ContextToken」ヘッダーを取得することで、「.NET CSOM を使ったプログラミングと認証」と同じ Token を取得できます。

HttpRequestMessageProperty reqProp
  = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties[
    HttpRequestMessageProperty.Name];
string contextTokenString = reqProp.Headers["X-SP-ContextToken"];

また、Remote Event Receiver においても、「.NET CSOM を使ったプログラミングと認証」で述べた TokenHelper クラスが使用できますので、上記のようなコードを書かずに簡単に認証のためのプログラミングができます。(後述するサンプル コードを参照。)

注意 : 現在 (2013年02月)、ItemAdded などの非同期メソッド (後述する ProcessOneWayEvent メソッド) の場合は、X-SP-ContextToken ヘッダーの内容は渡されません。このため、非同期メソッドから SharePoint の処理を呼び出すには、特別な処理が必要になります。(例えば、同期メソッドで Access Token を取得して保持する、など)

 

Remote Event Receiver のプログラミング (構築手順)

では、構築方法や注意点を見ていきます。

Visual Studio 2012 を開き、[Apps for SharePoint 2013] のプロジェクトを新規作成します。今回は、[SharePoint-hosted] (SharePoint ホスト型) で作成します。

今回は、リスト アイテムが作成される際に呼ばれる Remote Event Receiver を作成するので、準備として、「List Definition の開発と Client Side Rendering (CSR)」に記載した方法で、List Definition (リスト定義) と List Instance (リスト インスタンス) を作成します。(この名前を「List1」とします。)
今回、下図の通り、Title、Address の 2 つの Column (列) をリストに設定します。

つぎに、プロジェクトをマウスで右クリックして、[追加] - [新しい項目] メニューを選択して、[リモート イベント レシーバー] (Remote Event Receiver) を追加します。

今回は、上記で作成した「List1」の項目 (List Item) 作成時のイベント・レシーバーを作成するため、表示されるウィザードで、下図の通り、「List1」と [項目が追加されています] (Item Adding) を選択して [完了] ボタンを押します。
Remote Event Receiver の Feature と WCF サービス (RemoteEventReceiver1.svc) が作成されます。(なお、この方法では、Autohosted のサービスとして作成されます。)

追加された Remote Event Receiver の Feature の Elements.xml には、下記の通り記述されているはずです。

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="10000">
    <Receiver>
      <Name>RemoteEventReceiver1ItemAdding</Name>
      <Type>ItemAdding</Type>
      <SequenceNumber>10000</SequenceNumber>
      <Url>~remoteAppUrl/RemoteEventReceiver1.svc</Url>
    </Receiver>
  </Receivers>
</Elements>

上記の ListTemplateId には、この Remote Event Receiver を設定するリストの Type 番号を指定します。これは、List Instance (リスト インスタンス) ではなく、List Definition (リスト定義) の番号です。例えば、ある List Definition から、List1、List2 の 2 つの List Instance を作成している場合、これら双方の List (List Instance) に Remote Event Receiver が適用されます。
もし、特定の List Instance だけに Remote Event Receiver を適用したい場合は、下記 (太字) の通り記述します。

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListUrl="Lists/List2">
  . . .
  </Receivers>
</Elements>

また、上記の <Url /> には、Remote Event Receiver の WCF サービスの URL を設定します。
この Url に固定のパス (https://...) を記述しても構いません。ただし、この際、Provider-hosted の App としてあらかじめ登録されている App domain と同じドメインの URL を指定してください。(セキュリティ上の理由から、異なるドメインのサービスは呼び出せないためです。)
なお、開発時は、下図の通り、/_layouts/15/AppRegNew.aspx を表示して、App の Title、Client Id、Client Secret を登録しておいてください。(登録した内容は、/_layouts/15/AppInv.aspx や Azure Active Directory で確認できます。)
また、Azure Website に配置して確認したところ、http (Non-SSL) でも、ちゃんと呼び出せるようですが、「MSDN : Tips and FAQs - OAuth and remote apps for SharePoint 2013」に記載されている通り、本来は、https (SSL) を使用したほうが良いでしょう。(この WCF サービスは SharePoint のサーバーから呼び出されるため、https では、VeriSign が発行する証明書など、SharePoint と Authority を共有する証明書を使用する必要があります。)

なお、同じイベントで、複数のイベント レシーバーを登録することも可能であり、この場合、上記 (Elements.xml) の <SequenceNumber /> を使って実行順序を制御できます。

では、Remote Event Receiver の処理本体のプログラミングを解説しましょう。
まず、作成された WCF サービスは、IRemoteEventService インターフェイスを実装したクラスで、下記の通り、2 つのメソッド (ProcessEvent、ProcessOneWayEvent) を持っています。

public class RemoteEventReceiver1 : IRemoteEventService
{
  public SPRemoteEventResult ProcessEvent(
    SPRemoteEventProperties properties)
  {
    . . .
  }

  public void ProcessOneWayEvent(
    SPRemoteEventProperties properties)
  {
    . . .
  }
}

上記の ProcessEvent メソッドは、ItemAdding イベントなど、処理の完了前に呼ばれるメソッドで、属性を変更したり、処理をキャンセルすることなどが可能です。(このメソッドは、処理と同期して呼ばれます。つまり、この ProcessEvent が完了しないと、SharePoint 上の操作も完了しません。)
一方、ProcessOneWayEvent メソッドは、ItemAdded イベントなど、処理の完了後に非同期に呼ばれるメソッドです。例えば、処理後に、関係するシステムの更新をおこなう場合などに使用できます。

今回は、ItemAdding の処理を作成するため、ProcessEvent メソッドを下記の通り実装します。下記では、同じ Title のアイテムがリスト内に存在している場合に、そのアイテムの Address を、登録済みのアイテムの Address に書き換えます。

. . .

public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
{
  SPRemoteEventResult result = new SPRemoteEventResult();

  using (ClientContext clientContext =
    TokenHelper.CreateRemoteEventReceiverClientContext(properties))
  {
    if (clientContext != null)
    {
      string title =
        properties.ItemEventProperties.AfterProperties["Title"].ToString();
      string address =
        properties.ItemEventProperties.AfterProperties["Address"].ToString();

      ListCollection lists = clientContext.Web.Lists;
      clientContext.Load<ListCollection>(lists);
      List list =
        lists.GetByTitle(properties.ItemEventProperties.ListTitle);
      clientContext.Load<List>(list);
      // This time, iterate all items...
      // (Please query one specific item from many items !)
      ListItemCollection items =
        list.GetItems(CamlQuery.CreateAllItemsQuery());
      clientContext.Load<ListItemCollection>(items);
      clientContext.ExecuteQuery();
      foreach (var item in items)
      {
        if (item["Title"].ToString() == title)
        {
          result.ChangedItemProperties["Address"] =
            item["Address"];
          break;
        }
      }
    }
  }

  return result;
}
. . .

上記の TokenHelper.CreateRemoteEventReceiverClientContext によって、前述の Token を使った SharePoint への (リモートの) 認証処理をおこなっています。

補足 : 上述の通り、現在、ProcessOneWayEvent メソッドでは Token は渡されないので、別のプログラミングをおこなって認証してください。

さいごに、いつものように Permission の設定をおこなってください。(今回は、面倒なので、Site Collection の Full Control 権限を付与しておきます。)

アプリケーションのプログラミングが完了したら、まず、Provider-hosted の Remote Event Receiver (WCF サービス) を Azure などクラウド上に配置 (発行) します。
つぎに、App のプロジェクト (Web アプリケーションのプロジェクトではありません) をマウスで右クリックして、[発行] メニューを選択して、.app パッケージを作成します。
作成されたパッケージ (.app ファイル) を、開発サイトの「テスト中アプリ」 (Apps in Testing) のドキュメント ライブラリーに登録して展開します。(これにより、.app が、このサイトに追加されます。)

この App を配置して実行すると、下図のように、同じ Title のアイテムを登録した場合に、強制的に同じ Address に書き換えます。
バックエンドでは、クラウド上に登録された WCF サービスが呼び出されています。

 

Debug はどうすべきか ? (最大の疑問 ...)

Apps for SharePoint 2013 における Remote Event Receiver や Workflow などの開発で最も頭を悩ませる点は、デバッグ (Debug) です。
ご存じの通り、Visual Studio で普通にデバッグ実行すると、Remote App は localhost (IIS Express) にホストされます。その結果、SharePoint Online (Office 365) の Server から localhost への呼び出しがおこなわれますが、当然、この呼び出しには失敗します。(On-Premise ならこうした問題は回避できますが、実際、Apps for SharePoint 2013 の開発では、Office 365 を使用している方がほとんどでしょう。)

では、どのようにして Debug をおこなったら良いのでしょうか ? 解決方法は、3 つ考えられます。

まず、単純な発想として、On-Premise の SharePoint Server 2013 で Debug をおこなう方法です。
SharePoint Server 2013 (On-Premise) で動く Apps の開発手法については、「SharePoint 2013 Apps: On-Premises と Office 365 で動く App を作成するには (Authentication)」を参照してください。ただ、この方法は、もちろん、localhost に SharePoint Server のインストールが必要となるため、そう簡単な話ではありません。(SharePoint 2013 からは、クライアント OS へのインストールもサポートされていません。)

2 つめの方法として、Azure Service Bus を使うことで、Proxy 設定などに依存しない方法で、デバッグ環境 (localhost) との連携 (インターネットから localhost 上のサービスへの接続) をおこなう方法です。
Azure Service Bus については、「Windows Azure Service Bus でオンプレミスとクラウド間の通信をおこなう」を参照してください。(ここでは、Windows Azure ServiceBus の解説は省略します。) サービス自体は localhost で起動し、エンドポイントをインターネット上に公開することで、インターネット上の Office 365 (SharePoint Online) から呼び出せるようにします。
この Debug の方法については、最近、「Office and SharePoint Apps team blog : Debugging Remote Event Receivers with Visual Studio」にサンプル コード付きで紹介されましたので、是非、参考にしてください。

補足 (2013/03/08 追記) : RTM 版の Microsoft Office Developer Tools for Visual Studio 2012 で、下図の通り、Debug 用の Service Bus の設定ができるようになりました。(プロジェクトのプロパティを表示して、[SharePoint] タブを選択してください。)

3 つめの方法は、Remote Debug を使って回避する方法です。
Remote Event Receiver の WCF サービスをインターネット上で稼働させて、ローカル (localhost) の Debugger からこのサービスに接続して Debug を行う方法です。この方法については、事前準備として、「Visual Studio で Windows Azure のプロジェクトを Remote Debug する」に投稿しておきましたので、参考にしてください。

なお、いずれの方法も、Provider-hosted (プロバイダー向けのホスト型) で作成し、Remote Event Receiver の Elements.xml の Url に固定のパスを指定する必要があります。また、Office 365 では、上述の通り、https を使用する場合、開発用の Self-Signed の証明書は使用できないので注意してください。ブラウザーからアクセスする場合と異なり、証明書のエラー (警告) が回避できないためです。

補足 : Provider-hosted (プロバイダー向けのホスト型) の発行方法については、「App for SharePoint の Autohosted から Provider-hosted への移行」を参照してください。(Office store に登録する App では、Seller Dashboard から Client ID と Client Secret を発行できます。)

いろいろと苦労するポイントは多いですが、非常に自由度の高い開発ができますので、是非活用してみてください。

 

Windows Azure のトライアル (無償試用) について

 

Leave a Comment
  • Please add 8 and 8 and type the answer here:
  • Post