Verwenden von Azure-Funktionen für SharePoint-Webhooks

Azure Functions bietet eine einfache Möglichkeit zum Hosten Ihrer SharePoint-Webhooks: Sie können den C#- oder Javascript-Code Ihres Webhooks über den Browser hinzufügen und Azure kümmert sich um das Hosting und die Skalierung Ihrer Funktion.

In diesem Leitfaden erfahren Sie, wie Sie mithilfe der Azure-Portal Azure Functions für Ihre Webhooks einrichten und verwenden. Alternativ können Sie den Artikel Erstellen von Azure Functions für SharePoint-Webhooks mithilfe einer azd-Vorlage lesen, um den gesamten Prozess mithilfe einer azd-Vorlage zu automatisieren.

Erstellen einer Azure-Funktionsapp

Im ersten Schritt müssen Sie eine Azure-Funktions-App erstellen, wobei es sich um eine besondere Azure-Web-App handelt, die auf das Hosten von Azure Functions ausgerichtet ist.

  1. Navigieren Sie zu https://portal.azure.com, und suchen Sie nach Funktions-App. Wählen Sie in den Suchergebnissen Funktions-App aus.

    Erstellen einer Azure-Funktions-App

  2. Klicken Sie auf die Option Hinzufügen.

    Hinzufügen einer Azure-Funktions-App

  3. Geben Sie die erforderlichen Informationen zum Erstellen der Funktions-App ein, und klicken Sie dann auf Überprüfen und erstellen.

    Eingeben der Details zur Azure-Funktions-App

  4. Klicken Sie auf Erstellen.

    Bestätigungsseite der Azure-Funktions-App

  5. Klicken Sie nach Abschluss der Bereitstellung auf Zur Ressource wechseln.

    Seite „Abgeschlossen“ der Azure-Funktions-App

Erstellen einer Azure-Funktion

Nachdem nun die App zum Hosten der Funktionen fertiggestellt ist, fahren Sie mit dem Erstellen der ersten Azure-Funktion fort, indem Sie auf den Link Neue Funktion klicken.

Startseite der Azure-Funktions-App

Damit können Sie die Funktion von einer Vorlage aus starten. Bei SharePoint-Webhooks benötigen wir eine durch HTTP ausgelöste Funktion, und da wir in unserem Beispiel C#-Code schreiben, verwenden wir die Funktionsvorlage HttpTrigger-CSharp.

  1. Wählen Sie die Option für die Im Portal-Entwicklungsumgebung aus, und klicken Sie dann auf Weiter.

    Seite „Entwicklungsumgebung auswählen“

  2. Wählen Sie den Triggertyp Webhook + API aus, und klicken Sie dann auf Erstellen.

    Seite „Triggertyp auswählen“

    Das Ergebnis ist eine in C# verfasste Azure-Funktion „default“ (Standard).

    Entwicklungsumgebungsseite mit C#-Standardcode

In unserem Fall soll sich diese Azure-Funktion wie ein SharePoint-Webhookdienst verhalten. Daher müssen wir Folgendes in C# implementieren:

  • Das validationtoken zurückgeben, falls es als URL-Parameter für den Aufruf angegeben wurde. Gehen Sie dabei wie im Thema Erstellen eines neuen Abonnements beschrieben vor. SharePoint erwartet, dass die Antwort innerhalb von 5 Sekunden erfolgt.
  • Verarbeiten der JSON-Webhook-Benachrichtigung. Im folgenden Beispiel haben wir uns entschieden, die JSON-Benachrichtigung in einer Speicherwarteschlange zu speichern, sodass sie von einem Azure-Webauftrag aufgenommen und asynchron verarbeitet werden kann.
  • Je nach Ihren Anforderungen können Sie die Benachrichtigung auch direkt im Webhook-Dienst verarbeiten. Alle Aufrufe des Webhook-Diensts müssen jedoch innerhalb von 5 Sekunden ausgeführt werden, deshalb sollte ein asynchrones Modell verwendet werden.

Dies erzielen Sie, indem Sie den Standardcode durch den folgenden Code ersetzen:

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

public static async Task<IActionResult> Run(HttpRequest req,
  ICollector<string> outputQueueItem, ILogger log)
{
  log.LogInformation($"Webhook was triggered!");

  // Grab the validationToken URL parameter
  string validationToken = req.Query["validationtoken"];

  // If a validation token is present, we need to respond within 5 seconds by
  // returning the given validation token. This only happens when a new
  // webhook is being added
  if (validationToken != null)
  {
    log.LogInformation($"Validation token {validationToken} received");
    return (ActionResult)new OkObjectResult(validationToken);
  }

  log.LogInformation($"SharePoint triggered our webhook...great :-)");
  var content = await new StreamReader(req.Body).ReadToEndAsync();
  log.LogInformation($"Received following payload: {content}");

  var notifications = JsonConvert.DeserializeObject<ResponseModel<NotificationModel>>(content).Value;
  log.LogInformation($"Found {notifications.Count} notifications");

  if (notifications.Count > 0)
  {
    log.LogInformation($"Processing notifications...");
    foreach(var notification in notifications)
    {
      // add message to the queue
      string message = JsonConvert.SerializeObject(notification);
      log.LogInformation($"Before adding a message to the queue. Message content: {message}");
      outputQueueItem.Add(message);
      log.LogInformation($"Message added :-)");
    }
  }

  // if we get here we assume the request was well received
  return (ActionResult)new OkObjectResult($"Added to queue");
}

// supporting classes
public class ResponseModel<T>
{
  [JsonProperty(PropertyName = "value")]
  public List<T> Value { get; set; }
}

public class NotificationModel
{
  [JsonProperty(PropertyName = "subscriptionId")]
  public string SubscriptionId { get; set; }

  [JsonProperty(PropertyName = "clientState")]
  public string ClientState { get; set; }

  [JsonProperty(PropertyName = "expirationDateTime")]
  public DateTime ExpirationDateTime { get; set; }

  [JsonProperty(PropertyName = "resource")]
  public string Resource { get; set; }

  [JsonProperty(PropertyName = "tenantId")]
  public string TenantId { get; set; }

  [JsonProperty(PropertyName = "siteUrl")]
  public string SiteUrl { get; set; }

  [JsonProperty(PropertyName = "webId")]
  public string WebId { get; set; }
}

public class SubscriptionModel
{
  [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
  public string Id { get; set; }

  [JsonProperty(PropertyName = "clientState", NullValueHandling = NullValueHandling.Ignore)]
  public string ClientState { get; set; }

  [JsonProperty(PropertyName = "expirationDateTime")]
  public DateTime ExpirationDateTime { get; set; }

  [JsonProperty(PropertyName = "notificationUrl")]
  public string NotificationUrl {get;set;}

  [JsonProperty(PropertyName = "resource", NullValueHandling = NullValueHandling.Ignore)]
  public string Resource { get; set; }
}

Konfigurieren der Azure-Funktion

Da wir zu Beginn bereits die richtige Vorlage ausgewählt haben, ist unsere Konfiguration fast fertig. Das einzige, was Sie noch machen müssen, ist Azure Queue Storage als Ausgabebindung zu konfigurieren, damit wir der Warteschlange Nachrichten hinzufügen können, sobald sie eingehen.

  1. Wählen Sie Integrieren und dann Neue Ausgabe aus, um die Ausgabebindung hinzuzufügen.

    Einstellungen für die Integration der Azure-Funktion

  2. Wählen Sie Azure Queue Storage als Bindungstyp aus, und klicken Sie dann auf Auswählen.

    Auswahl der Azure-Funktionsbindung

  3. Klicken Sie auf Speichern.

    Azure Queue Storage-Einstellungen für Azure-Funktion

Testen Ihrer Azure-Funktion (Überprüfungstokentest)

Nun können Sie den ersten Test Ihrer Azure-Funktion durchführen.

  1. Navigieren Sie zurück zum Codebildschirm, indem Sie im Navigationsbereich auf den Namen der Funktion HttpTrigger1 klicken. Klicken Sie dann auf die Registerkarte Test, um den Testbereich auf der rechten Seite zu öffnen.

    Navigieren zum Testbereich für die Azure-Funktion

  2. Fügen Sie den URL-Parameter validationtoken mit einer beliebigen Zeichenfolge als Wert hinzu.

Mit diesem Setup imitieren wir das Verhalten von SharePoint, indem der Webhook-Dienst bei der Überprüfung einer neuen Webhook-Ergänzung aufgerufen wird.

Klicken Sie auf Ausführen, um den Test zu starten.

Einrichten des Überprüfungstokentests für Ihre Azure-Funktion

Bei erfolgreicher Ausführung sehen Sie im Protokollbereich, dass der Dienst aufgerufen wurde und den übergebenen Wert mit einer HTTP 200-Antwort zurückgegeben hat.

Ergebnisse des validationToken-Tests

Testen Ihrer Azure-Funktion (SharePoint-Listenereignistest)

Nun zum zweiten Test. Mit diesem wird Ihre Funktion so getestet, als ob sie von einem SharePoint-Listenereignis aufgerufen würde.

  1. Löschen Sie im Testbereich den URL-Parameter validationtoken, und ersetzen Sie den Anforderungstext durch das folgende JSON-Objekt. Klicken Sie dann auf Ausführen.
{
  "value": [{
    "subscriptionId":"1111111111-3ef7-4917-ada1-xxxxxxxxxxxxx",
    "clientState":null,
    "expirationDateTime":"2020-06-14T16:22:51.2160000Z","resource":"xxxxxx-c0ba-4063-a078-xxxxxxxxx","tenantId":"4e2a1952-1ed1-4da3-85a6-xxxxxxxxxx",
    "siteUrl":"/sites/webhooktest",
    "webId":"xxxxx-3a7c-417b-964e-39f421c55d59"
  }]
}

Wenn alles in Ordnung ist, sollten alle Protokollmeldungen angezeigt werden, einschließlich der Meldung, die angibt, dass die Nachricht der Warteschlange hinzugefügt wurde.

Ergebnisse des Webhook-Benachrichtigungstests

Verwenden der Webhook-URL für Ihre Implementierung

SharePoint muss die Webhook-URL kennen, die wir verwenden. Dazu kopieren wir die URL der Azure-Funktion.

  1. Klicken Sie auf Funktions-URL abrufen.

    Protokollmeldungskonsole

  2. Klicken Sie auf Kopieren, um die URL der Azure-Funktions-App in die Zwischenablage zu kopieren.

    Abrufen des Funktions-URL-Links

In unserem Fall lautet die zu verwendende Webhook-URL also wie folgt:

https://fa-acto-spwebhook-dev-westus.azurewebsites.net/api/HttpTrigger1?code=LTFbMHrbVVQkhbL2xUplGRmY5XnAI9q/E4s5jvfeIh00KsF9Y7QsJw==

Siehe auch