SharePoint webhook の使用を開始する

この記事では、SharePoint Webhook 要求を追加して処理するアプリケーションを構築する方法について説明します。 Postman クライアントを使用して、Webhook レシーバーとして単純な ASP.NET Web APIと対話しながら、SharePoint Webhook 要求をすばやく構築して実行する方法について説明します。

webhook の動作を理解しやすくするため、単純な HTTP 要求を使用します。

この記事の段階的な指示を実行するには、次のツールをダウンロードしてインストールします。

手順 1: Postman クライアント用に Azure AD アプリケーションを登録する

Postman クライアントが SharePoint とやり取りするには、Office 365 テナントと関連する Microsoft Azure Active Directory (Azure AD) テナントに Azure AD アプリを登録する必要があります。

  1. アプリケーションは、Web アプリケーションとして登録する必要があります。

  2. SharePoint Online にアクセスするには、Azure AD アプリに Office 365 SharePoint Online アプリケーションへのアクセス許可を付与し、すべてのサイト コレクションのアイテムとリストの読み取り/書き込みアクセス許可を選ぶことが重要です。

    注:

    Azure AD アプリケーションの追加と、アプリケーションへのアクセス許可の詳細については、「アプリケーションの追加」をご覧ください。

  3. アプリの応答 (リダイレクト) URL として、次のエンドポイントを入力します。 これは、認証が成功した場合に、アクセス トークンを含む、Azure AD が認証応答を送信するエンドポイントです。

    https://www.getpostman.com/oauth2/callback
    
  4. クライアント シークレットになる Key を生成します。

  5. 次のプロパティは後の手順で必要になるため、安全な場所にコピーしておきます。

    • クライアント ID
    • クライアント シークレット

手順 2:webhook レシーバーを作成する

このプロジェクトでは、webhook レシーバーを作成するために Visual Studio Web API プロジェクトを使用します。

新しい ASP.NET Web API プロジェクトの作成

  1. Visual Studio を開きます。
  2. [ファイル]>[新規作成]>[プロジェクト] の順に選択します。
  3. [テンプレート] ウィンドウで、[インストールされているテンプレート] を選び、[Visual C#] ノードを展開します。
  4. [Visual C#] では [Web] を選択します。
  5. プロジェクト テンプレートのリストで、ASP.NET Web Application を選択します。
  6. プロジェクトに「SPWebhooksReceiver」という名前を付けて、[OK] を選択します。
  7. [新しい ASP.NET プロジェクト] ダイアログで [Web API] テンプレートを ASP.NET 4.5. グループから選択します。
  8. [認証の変更] ボタンを選んで認証を [認証なし] に変更します。
  9. [OK] を選んで Web API プロジェクトを作成します。

注:

このプロジェクトはクラウドに展開しないので、[クラウドにホストする] チェック ボックスをオフにできます。

Visual Studio によってプロジェクトが作成されます。

webhook レシーバーを作成する

NuGet パッケージをインストールする

ASP.NET Web API Tracing を使用して SharePoint からの要求をログに記録します。 次の手順で、トレースのパッケージをインストールします。

  1. Visual Studio でソリューション エクスプローラーに移動します。
  2. プロジェクトのコンテキスト メニュー (右クリック) を開き、[NuGet パッケージの管理] を選びます。
  3. 検索ボックスに「Microsoft.AspNet.WebApi.Tracing」と入力します。
  4. 検索結果で「Microsoft.AspNet.WebApi.Tracing」パッケージを選び、[インストール] を選んでパッケージをインストールします。

SPWebhookNotification モデルを作成する

サービスによって生成されるそれぞれの通知は、webhookNotifiation インスタンスにシリアル化されます。 この通知インスタンスを表す単純なモデルを作成する必要があります。

  1. Visual Studio でソリューション エクスプローラーに移動します。

  2. Models フォルダーのコンテキスト メニュー (右クリック) を開き、[追加]>[クラス] の順に選択します。

  3. クラス名として「SPWebhookNotification」を入力し、[追加] を選んでクラスをプロジェクトに追加します。

  4. SPWebhookNotification クラスの本文に以下のコードを追加します。

    public string SubscriptionId { get; set; }
    public string ClientState { get; set; }
    public string ExpirationDateTime { get; set; }
    public string Resource { get; set; }
    public string TenantId { get; set; }
    public string SiteUrl { get; set; }
    public string WebId { get; set; }
    

SPWebhookContent モデルを作成する

複数の通知が 1 つの要求として webhook レシーバーに送信されることがあるため、複数の通知は 1 つの配列値を持つ 1 つのオブジェクトにまとめられます。 配列を表す単純なモデルを作成します。

  1. Visual Studio でソリューション エクスプローラーに移動します。

  2. Models フォルダーのコンテキスト メニュー (右クリック) を開き、[追加]>[クラス] の順に選択します。

  3. クラス名として「SPWebhookContent」を入力し、[追加] を選んでクラスをプロジェクトに追加します。

  4. SPWebhookContent クラスの本文に以下のコードを追加します。

      public List<SPWebhookNotification> Value { get; set; }
    

SharePoint webhook クライアントの状態を追加する

webhook は、サブスクリプションへの通知メッセージに入れて送り返されるオプションの文字列値を使用する機能を提供します。 これは、要求が実際に信頼できるソース (この場合は SharePoint) からのものであることを検証するために使用できます。

アプリケーションが着信要求を検証するために使用できるよう、クライアント状態値を追加します。

  1. Visual Studio でソリューション エクスプローラーに移動します。

  2. web.config ファイルを開き、クライアントの状態として次のキーを <appSettings> セクションへ追加します。

    <add key="webhookclientstate" value="A0A354EC-97D4-4D83-9DDB-144077ADB449"/>
    

トレースを有効にする

web.config ファイルで <configuration> セクションの <system.web> 要素内に以下のキーを追加してトレースを有効にします。

<trace enabled="true"/>

トレース ライターが必要なため、コントローラー構成にトレース ライターを追加する必要があります (この場合は、System.Diagnostics のトレース ライターを使用します)。

  1. Visual Studio で [ソリューション エクスプローラー] に移動します。

  2. App_Start フォルダーの WebApiConfig.cs を開きます。

  3. 次の行を Register メソッド内に追加します。

    config.EnableSystemDiagnosticsTracing();
    

SharePoint webhook コントローラーを作成する

これで、SharePoint から受信した要求を処理し、それに応じてアクションを実行する webhook レシーバーのコントローラーを作成できるようになりました。

  1. Visual Studio でソリューション エクスプローラーに移動します。

  2. Controllers フォルダーのコンテキスト メニュー (右クリック) を開き、[追加]>[コントローラー] の順に選択します。

  3. [スキャフォールディングの追加] ダイアログで [Web API 2 コントローラー – 空] を選びます。

  4. [追加] を選択します。

  5. コントローラーに「SPWebhookController」という名前を付けて [追加] を選び、API コントローラーをプロジェクトに追加します。

  6. using ステートメントを次のコードと置き換えます。

    using Newtonsoft.Json;
    using SPWebhooksReceiver.Models;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Tracing;
    
  7. SPWebhookController クラス内のコードを次のコードと置き換えます。

    [HttpPost]
    public HttpResponseMessage HandleRequest()
    {
        HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.BadRequest);
        var traceWriter = Configuration.Services.GetTraceWriter();
        string validationToken = string.Empty;
        IEnumerable<string> clientStateHeader = new List<string>();
        string webhookClientState = ConfigurationManager.AppSettings["webhookclientstate"].ToString();
    
        if (Request.Headers.TryGetValues("ClientState", out clientStateHeader))
        {
            string clientStateHeaderValue = clientStateHeader.FirstOrDefault() ?? string.Empty;
    
            if (!string.IsNullOrEmpty(clientStateHeaderValue) && clientStateHeaderValue.Equals(webhookClientState))
            {
                traceWriter.Trace(Request, "SPWebhooks",
                    TraceLevel.Info,
                    string.Format("Received client state: {0}", clientStateHeaderValue));
    
                var queryStringParams = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    
                if (queryStringParams.AllKeys.Contains("validationtoken"))
                {
                    httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
                    validationToken = queryStringParams.GetValues("validationtoken")[0].ToString();
                    httpResponse.Content = new StringContent(validationToken);
    
                    traceWriter.Trace(Request, "SPWebhooks",
                        TraceLevel.Info,
                        string.Format("Received validation token: {0}", validationToken));
                    return httpResponse;
                }
                else
                {
                    var requestContent = Request.Content.ReadAsStringAsync().Result;
    
                    if (!string.IsNullOrEmpty(requestContent))
                    {
                        SPWebhookNotification notification = null;
    
                        try
                        {
                            var objNotification = JsonConvert.DeserializeObject<SPWebhookContent>(requestContent);
                            notification = objNotification.Value[0];
                        }
                        catch (JsonException ex)
                        {
                            traceWriter.Trace(Request, "SPWebhooks",
                                TraceLevel.Error,
                                string.Format("JSON deserialization error: {0}", ex.InnerException));
                            return httpResponse;
                        }
    
                        if (notification != null)
                        {
                            Task.Factory.StartNew(() =>
                            {
                                  //handle the notification here
                                  //you can send this to an Azure queue to be processed later
                                //for this sample, we just log to the trace
    
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("Resource: {0}", notification.Resource));
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("SubscriptionId: {0}", notification.SubscriptionId));
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("TenantId: {0}", notification.TenantId));
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("SiteUrl: {0}", notification.SiteUrl));
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("WebId: {0}", notification.WebId));
                                traceWriter.Trace(Request, "SPWebhook Notification",
                                    TraceLevel.Info, string.Format("ExpirationDateTime: {0}", notification.ExpirationDateTime));
    
                            });
    
                            httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
                        }
                    }
                }
            }
            else
            {
                httpResponse = new HttpResponseMessage(HttpStatusCode.Forbidden);
            }
        }
    
        return httpResponse;
    }
    
  8. ファイルを保存します。

手順 3: webhook レシーバーをデバッグする

  1. F5 キーを選択し、webhook レシーバーをデバッグします。
  2. ブラウザーが開いたら、アドレス バーからポート番号をコピーします。 例: http://localhost:<_port-number_>

手順 4: ngrok プロキシを実行する

  1. コンソール ターミナルを開きます。

  2. 抽出した ngrok フォルダーに移動します。

  3. 前の手順のポート番号 URL と以下を入力して ngrok を開始します。

    ./ngrok http port-number --host-header=localhost:port-number
    

    ngrok が実行していることがわかります。

  4. 転送先の HTTPS アドレスをコピーします。 SharePoint が要求を送信するためのサービス プロキシとして、このアドレスを使用します。

手順 5:Postman を使用して webhook サブスクリプションを追加する

新しいアクセス トークンを取得する

Postman を使用すると、API の操作が非常に簡単になります。 最初の手順は、SharePoint に API 要求を送信できるように、Azure AD で認証するように Postman を構成することです。 手順 1 で登録した Azure AD アプリを使用します。

  1. Postman を開きます。 サイドバー要求エディターが表示されます。

  2. 要求エディター[認証] タブを選びます。

  3. [種類] リストで、OAuth 2.0 を選択します。

  4. [新しいアクセス トークンを取得する] ボタンを選びます。

  5. ダイアログ ウィンドウに以下のように入力します。

    • 認証 URL:
      • https://login.microsoftonline.com/common/oauth2/authorize?resource=https%3A%2F%2F<_your-sharepoint-tenant-url-without-https_>
      • your-sharepoint-tenant-url-without-httpshttps のプレフィックスなしで、テナントの URL と置き換えます。
    • アクセス トークン URL: https://login.microsoftonline.com/common/oauth2/token
    • クライアント ID: 前の手順 1 で登録したアプリのクライアント ID です。
    • クライアント シークレット: 前の手順 1 で登録したアプリのクライアント シークレットです。
    • トークン名: sp_webhooks_token
    • 許可タイプ: 承認コード
  6. [トークンを要求する] を選び、サインインして同意し、セッションのトークンを取得します。

  7. トークンが正常に取得されると、[承認] タブaccess_token追加された変数が表示されます。

  8. [ヘッダーにトークンを追加する] オプションを選びます。

  9. access_token変数をダブルクリックして、要求のヘッダーにトークンを追加します。

    Postman が新しいアクセス トークンを取得する

ドキュメント リスト ID の取得

既定のドキュメント ライブラリの Webhook を管理する必要があります。既定のサイト コレクションで [ ドキュメント] という名前でプロビジョニングされます。 GET 要求を発行して、この一覧の ID を取得 します。

  1. 以下の要求 URL を入力します。

    https://site-collection/_api/web/lists/getbytitle('Documents')?$select=Title,Id
    
  2. site-collection を実際のサイト コレクションと置き換えます。

    Postman が要求を実行し、成功すると結果が表示されます。

  3. 結果から ID をコピーします。 後でこの ID を使用して webhook 要求を作成します。

webhook サブスクリプションを追加する

これで必要な情報が揃ったので、webhook サブスクリプションを追加するためのクエリと要求を構築します。 次の手順には要求エディターを使用します。

  1. 要求を GET から POST に変更します。

  2. 要求 URL として次のように入力します。

    https://site-collection/_api/web/lists('list-id')/subscriptions
    
  3. site-collection を実際のサイト コレクションと置き換えます。

  4. [ヘッダー] タブに移動します。

  5. Authorization ヘッダーがまだあることを確認します。 ない場合は、新しいアクセス トークンを要求する必要があります。

  6. 次のヘッダーのキー>のペアを追加します。

    • Accept: application/json;odata=nometadata
    • Content-Type: application/json
  7. [本文] タブに移動して [raw (未加工)] の形式を選びます。

  8. 本文として以下の JSON を貼り付けます。

    {
      "resource": "https://site-collection/_api/web/lists('list-id')",
      "notificationUrl": "https://ngrok-forwarding-address/api/spwebhook/handlerequest",
      "expirationDateTime": "2016-10-27T16:17:57+00:00",
      "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449"
    }
    

    Postman が webhook 本文を追加する

  9. expirationDateTime が最大でも今日から 6 か月先であることを確認します。

  10. 手順 4 に示すように、必ず webhook レシーバーをデバッグします。

  11. [送信] を選択して要求を実行します。

    要求が成功した場合は、サブスクリプションの詳細を示す SharePoint からの応答が表示されます。 次の例では、新しく作成したサブスクリプションの応答を示しています。

    {
      "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449",
      "expirationDateTime": "2016-10-27T16:17:57Z",
      "id": "32b95d9-4d20-4a17-bfa3-2957cb38ead8",
      "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest",
      "resource": "c34420f9-2ad7-4e54-94c9-b67798d2299b"
    }
    
  12. サブスクリプション ID をコピーします。これは次の要求セットで必要になります。

  13. Visual Studio の webhook レシーバー プロジェクトに移動して、[出力] ウィンドウを確認します。 以下のトレースのようなトレース ログとその他のメッセージが表示されます。

    iisexpress.exe Information: 0 : Message='Received client state: A0A354EC-97D4-4D83-9DDB-144077ADB449'
    iisexpress.exe Information: 0 : Message='Received validation token: daf2803c-43cf-44c7-8dff-7066eaa40f13'
    

    トレースは、webhook が最初に検証要求を受信したことを示します。 コードを確認すると、SharePoint が要求を検証できるように、すぐに検証トークンが返されていることがわかります。

    if (queryStringParams.AllKeys.Contains("validationtoken"))
    {
      httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
      validationToken = queryStringParams.GetValues("validationtoken")[0].ToString();
      httpResponse.Content = new StringContent(validationToken);
    
      traceWriter.Trace(Request, "SPWebhooks",
        TraceLevel.Info,
        string.Format("Received validation token: {0}", validationToken));
      return httpResponse;
    }
    

手順 6:サブスクリプションの詳細を取得する

ここで、Postman のクエリを実行してサブスクリプションの詳細を取得します。

  1. Postman クライアントを開きます。

  2. 要求を POST から GET に変更します。

  3. 要求として次のように入力します。

    https://site-collection/_api/web/lists('list-id')/subscriptions
    
  4. site-collection を実際のサイト コレクションと置き換えます。

  5. [送信] を選択して要求を実行します。

    成功すると、SharePoint からこのリスト リソースのサブスクリプションが返されることがわかります。 1 つだけ追加したため、少なくとも 1 つのサブスクリプションが返されます。 次の例では、1 つのサブスクリプションの応答を示しています。

    {
      "value": [
        {
          "clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449",
          "expirationDateTime": "2016-10-27T16:17:57Z",
          "id": "32b95add-4d20-4a17-bfa3-2957cb38ead8",
          "notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest",
          "resource": "c34420f9-2a67-4e54-94c9-b67798229f9b"
        }
      ]
    }
    
  6. 以下のクエリを実行すると、特定のサブスクリプションの詳細を取得できます。

    https://site-collection/_api/web/lists('list-id')/subscriptions('subscription-id')
    
  7. subscription-id をサブスクリプション ID と置き換えます。

手順 7: webhook 通知をテストする

ここで、ファイルをドキュメント ライブラリに追加して、SharePoint からの通知を webhook レシーバーで取得するかどうかをテストします。

  1. Visual Studio に移動します。

  2. SPWebhookController で、次のコード行にブレークポイントを配置します。

    var requestContent = Request.Content.ReadAsStringAsync().Result;
    
  3. ドキュメント ライブラリに移動します。 既定のサイト コレクションでは、「Shared Documents」という名前のライブラリになります。

  4. 新しいファイルを追加します。

  5. Visual Studio に移動し、ブレークポイントに達するまで待ちます。

    待機時間は数秒から 5 分にも及ぶ場合があります。 ブレークポイントに達する直前に、webhook レシーバーは SharePoint からの通知を受け取っています。

  6. F5 を選んで続けます。

  7. 通知データをトレース ログに追加しているため、通知データを確認するには、[出力] ウィンドウで次のエントリを確認します。

    iisexpress.exe Information: 0 : Message='Resource: c34420f9-2a67-4e54-94c9-b6770892299b'
    iisexpress.exe Information: 0 : Message='SubscriptionId: 32b95ad9-4d20-4a17-bfa3-2957cb38ead8'
    iisexpress.exe Information: 0 : Message='TenantId: 7a17cb7d-6898-423f-8839-45f363076f06'
    iisexpress.exe Information: 0 : Message='SiteUrl: /'
    iisexpress.exe Information: 0 : Message='WebId: 62b80e0b-f889-4974-a519-cc138413be40'
    iisexpress.exe Information: 0 : Message='ExpirationDateTime: 2016-10-27T16:17:57.0000000Z'
    

このプロジェクトでは、トレース ログに情報が書き込まれまるだけです。 ただし、レシーバーでテーブルやキューにこの情報を送信し、SharePoint からの情報を取得するために、受信データを処理することができます。

このデータを使用すると、URL を作成し、GetChanges API で最新の変更内容を取得することができます。

次の手順

この記事では、Postman クライアントとシンプルな Web API を使用してサブスクライブし、SharePoint から webhook 通知を受け取りました。

次に、SharePoint webhooks サンプル リファレンス実装を確認します。これは、Azure Storage Queues を使用して情報を処理し、SharePoint から変更を取得し、それらの変更を SharePoint リストに再びプッシュする、エンドツーエンドのサンプルを示します。