SharePoint アドインでリモート イベント レシーバーを作成する

事前にプロバイダー向けのホスト型 SharePoint アドインについて理解していること、少なくとも "Hello World" レベル以上のものを開発した経験があると助けになります。 「プロバイダー向けのホスト型 SharePoint アドインの作成を始める」を参照してください。

また、SharePoint アドインのイベントの処理に精通している必要もあります。

リモート イベント レシーバーを作成する

この記事では、アドイン Web 内でカスタム リストの ItemAdded イベントを処理するリモート イベント レシーバー (RER) を追加して SharePoint アドインを拡張する方法を示しています。 RER は宣言型マークアップを使用してアドイン Web に登録されます。 RER はプログラムを使用してホスト Web に登録されます。 それを行うコード サンプルについては、SharePoint/PnP/Samples/Core.EventReceivers をご覧ください。

RER は SOAP Web サービスにする必要があります。 継続して用いられている例では、Windows Communication Foundation (WCF) サービスとして実装していますが、基本的には RER を Microsoft 以外のスタックに実装することが可能です。

この記事に従ってコードを自分で入力するには、 SharePoint-Add-in-CSOM-BasicDataOperations からサンプルをダウンロードし、Visual Studio でサンプルを開きます。

注:

このサンプルでは、Office Developer Tools for Visual Studio によって生成される TokenHelper.cs ファイルを使用します。 このサンプルを作成する時点では最新バージョンでしたが、この資料をお読みになる時点では最新バージョンではない可能性もあります。 しかし、このサンプルは、初めて RER を作成する際に非常に参考になります。 さらに先に進む用意ができたら、この記事の末尾にある「関連項目」セクションに記載されているサンプルを参照してください。 そこに記載されているサンプルがおそらく最新です。

リモート イベント レシーバーを登録するには

  1. Visual Studio で SharePoint アドイン プロジェクトを開きます。

  2. ソリューション エクスプローラーで、アドイン プロジェクトのノードを選択します。

  3. メニュー バーで、[プロジェクト]>[新しい項目の追加] の順に選択します。

  4. [インストールされたテンプレート] ウィンドウで、[Office/ SharePoint] ノードを選択します。

  5. [テンプレート] ウィンドウで、[リモート イベント レシーバー] テンプレートを選択します。

  6. [名前] ボックスは既定の名前 (RemoteEventReceiver1) のままにし、[追加] を選択します。

  7. [使用するイベント レシーバーの種類] ボックスの一覧で、[リスト項目イベント] を選択します。

  8. [イベント ソースとなる項目] の一覧で、[カスタム リスト] を選択します。

    この記事の例では、カスタム ジェネリック リストを使用しています。 ただし、RER は [ お知らせ] や [ 連絡先] などの標準の SharePoint リストで発生するイベントも処理できます。

  9. [次のイベントを処理] リストで、[項目が追加されています] を選択し、[完了] を選択します。

    Web サービスが、指定したリモート イベントを処理する Web アプリケーションに追加されます。 リモート イベント レシーバーは SharePoint アドインに追加され、リスト項目イベントはレシーバーの Elements.xml ファイル (アドイン Web 機能に含まれます) で参照されます。

リストを作成するには

  1. ソリューション エクスプローラーで、アドイン プロジェクトのノードを選択します。

  2. メニュー バーで、[プロジェクト]>[新しい項目の追加] の順に選択します。

  3. [インストールされたテンプレート] ウィンドウで、[Office SharePoint] ノードを選択します。

  4. [テンプレート] ウィンドウで、[リスト] テンプレートを選択します。

  5. [名前] ボックスは既定の名前 (List1) のままにし、[追加] を選択します。

  6. [既存のリスト テンプレートに基づくリスト インスタンスを作成]、リストの [カスタム リスト][完了] の順に選択します。

リモート イベント レシーバーに機能を追加するには

  1. SharePoint テスト ファームが Visual Studio が実行されているのと同じコンピューター上にない場合 (または SharePoint Online テナンシーを SharePoint テスト サイトとして使用している場合) には、Microsoft Azure サービス バスを使用してデバッグを行うようにプロジェクトを構成します。 詳しくは、「SharePoint アドインでのリモート イベント レシーバーのデバッグとトラブルシューティング」を参照してください。

  2. リモート イベント レシーバーのサービスのコード ファイル (RemoteEventReceiver1.svc.cs) で、コンテンツを次のコードで置き換えます。 このコードでは、次のタスクを実行します。

    • 有効なクライアント コンテキスト オブジェクトを取得します。

    • EventLog という名前のリストが存在しない場合は、発生するリモート イベントの名前が含まれるリストを作成します。

    • 日時のタイム スタンプを含むイベントのエントリをリストに追加します。

    注:

    この記事が書かれた時点では、レシーバーが作成されると Office Developer Tools for Visual Studio によって、必要なアセンブリすべてへの参照が追加されましたが、以降のバージョンのツールではこうした処理が実行されない可能性があります。 コンパイル エラーが発生する場合には、欠落している参照を追加します。たとえば、System.ServiceModel または System.ComponentModel.DataAnnotations への参照の追加が必要になる場合があります。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Text;
    using Microsoft.SharePoint.Client;
    using Microsoft.SharePoint.Client.EventReceivers;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    
    namespace BasicDataOperationsWeb.Services
    {
        public class RemoteEventReceiver1 : IRemoteEventService
        {
            public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
            {
                // When a "before" event occurs (such as ItemAdding), call the event 
                // receiver code.
                ListRemoteEventReceiver(properties);
                return new SPRemoteEventResult();
            }
    
            public void ProcessOneWayEvent(SPRemoteEventProperties properties)
            {
                // When an "after" event occurs (such as ItemAdded), call the event 
                // receiver code.            
            }
    
            public static void ListRemoteEventReceiver(SPRemoteEventProperties properties)
            {
                string logListTitle = "EventLog";
    
                // Return if the event is from the EventLog list itself. Otherwise, it may go into
                // an infinite loop.
                if (string.Equals(properties.ItemEventProperties.ListTitle, logListTitle, 
                    StringComparison.OrdinalIgnoreCase))
                    return;
    
                // Get the token from the request header.
                HttpRequestMessageProperty requestProperty = 
                    (HttpRequestMessageProperty)OperationContext
                    .Current.IncomingMessageProperties[HttpRequestMessageProperty.Name];
                string contextTokenString = requestProperty.Headers["X-SP-ContextToken"];
    
                // If there is a valid token, continue.
                if (contextTokenString != null)
                {
                    SharePointContextToken contextToken =
                        TokenHelper.ReadAndValidateContextToken(contextTokenString, 
                            requestProperty.Headers[HttpRequestHeader.Host]);
    
                    Uri sharepointUrl = new Uri(properties.ItemEventProperties.WebUrl);
                    string accessToken = TokenHelper.GetAccessToken(contextToken, 
                                                        sharepointUrl.Authority).AccessToken;
                    bool exists = false;
    
                    // Retrieve the log list "EventLog" and add the name of the event that occurred
                    // to it with a date/time stamp.
                    using (ClientContext clientContext = 
                        TokenHelper.GetClientContextWithAccessToken(sharepointUrl.ToString(), 
                                                                                                            accessToken))
                    {
                        clientContext.Load(clientContext.Web);
                        clientContext.ExecuteQuery();
                        List logList = clientContext.Web.Lists.GetByTitle(logListTitle);
    
                        try
                        {
                            clientContext.Load(logList);
                            clientContext.ExecuteQuery();
                            exists = true;
                        }
    
                        catch (Microsoft.SharePoint.Client.ServerUnauthorizedAccessException)
                        {
                            // If the user doesn't have permissions to access the server that's 
                            // running SharePoint, return.
                            return;
                        }
    
                        catch (Microsoft.SharePoint.Client.ServerException)
                        {
                            // If an error occurs on the server that's running SharePoint, return.
                            exists = false;
                        }
    
                        // Create a log list called "EventLog" if it doesn't already exist.
                        if (!exists)
                        {
                            ListCreationInformation listInfo = new ListCreationInformation();
                            listInfo.Title = logListTitle;
                            // Create a generic custom list.
                            listInfo.TemplateType = 100;
                            clientContext.Web.Lists.Add(listInfo);
                            clientContext.Web.Context.ExecuteQuery();
                        }
    
                        // Add the event entry to the EventLog list.
                        string itemTitle = "Event: " + properties.EventType.ToString() + 
                            " occurred on: " + 
                            DateTime.Now.ToString(" yyyy/MM/dd/HH:mm:ss:fffffff");
                        ListCollection lists = clientContext.Web.Lists;
                        List selectedList = lists.GetByTitle(logListTitle);
                        clientContext.Load<ListCollection>(lists);
                        clientContext.Load<List>(selectedList);
                        ListItemCreationInformation listItemCreationInfo = 
                            new ListItemCreationInformation();
                        var listItem = selectedList.AddItem(listItemCreationInfo);
                        listItem["Title"] = itemTitle;
                        listItem.Update();
                        clientContext.ExecuteQuery();
                    }
                }
            }
        }
    }
    
  3. Home.aspx.cs で、SPHostUrl のすべてのインスタンスを SPAppWebUrl に変更します。

    たとえば、sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]);sharepointUrl = new Uri(Request.QueryString["SPAppWebUrl"]); に変更します。

イベント ハンドラーを実行およびテストする

次に示す手順で、ハンドラーをテストします。

  1. F5 キーを選択してプロジェクトを実行します。

  2. アドインを信頼するように指示するプロンプトが表示されたら、それに従います。 SharePoint アドインが実行され、使用可能なリストの表が表示されます。これには、List1 が含まれます。

  3. List1 の ID を選択します。 その ID は [リスト項目を取得] ボックスにコピーされます。

  4. [リスト項目を取得] ボタンを選択します。 項目を含まない List1 が表示されます。

  5. [項目の追加] ボックスで「最初の項目」を指定し、[項目の追加] ボタンを選択します。 [ 最初の項目] という名前のリスト項目が List1 に追加され、これによってリモート イベント レシーバーが起動し、EventLog リストにエントリが追加されます。

  6. [リストの更新] ボタンを選択してリストの表に戻ります。 表には、EventLog という名前の新しいリストが表示されます。

  7. EventLogListID GUID 値を選択し、[リスト項目を取得] ボタンを選択します。 List1 に項目を追加したときに発生した Handle ItemAdding イベントのエントリを含む EventLog の表が表示されます。

Visual Studio を使用してイベント ハンドラーを追加または削除する

  1. ソリューション エクスプローラーで、リモート イベント レシーバーのプロジェクト ノードを選択します。

  2. [プロパティ] ウィンドウで、処理するイベントのプロパティを True に設定します。

    たとえば、ユーザーがリスト項目を追加したときに応答するには、 Handle ItemAdding プロパティの値を True に設定します。 そのイベントを処理しないようにするには、そのプロパティの値を False に設定します。

    Visual Studio での SharePoint リモート イベント

    Visual Studio での SharePoint リモート イベント

  3. イベントを追加した場合は、前のイベントで追加したのと同様に、コード ファイルにイベント処理コードを追加します。

    別の種類のイベントを処理するには、別のリモート イベント レシーバーを SharePoint アドインに追加します。 たとえば、あるリモート イベント レシーバーでリスト項目イベントを処理する場合、そのレシーバーに別のリスト項目イベントを追加できます。 ただし、リスト イベントを処理するには、別のリモート イベント レシーバーを追加する必要があります。

運用環境のリモート レシーバー イベントの URL とホストの制限

このリモート イベント レシーバーは、クラウドか、オンプレミス サーバー (SharePoint サーバーとしても使用されているものは除く) でホストできます。 運用環境のレシーバー URL で特定のポートを指定することはできません。 つまり、HTTPS のポート 443 (推奨) と HTTP のポート 80 のいずれかを使用する必要があります。 HTTPS を使用し、レシーバー サービスがオンプレミスでホストされ、アドインが SharePoint Online 上にある場合、ホスティング サーバーには、証明機関からの公的に信頼された証明書が必要となります。 (自己署名証明書が有効になるのは、アドインがオンプレミスの SharePoint ファームにある場合のみです。)

関連項目