Introducción a los webhooks de SharePoint

En este artículo se describe cómo crear una aplicación que agrega y controla solicitudes de webhook de SharePoint. Obtendrá información sobre cómo usar el cliente de Postman para crear y ejecutar solicitudes de webhook de SharePoint rápidamente mientras interactúa con un ASP.NET Web API sencillo como el receptor de webhook.

Usará solicitudes HTTP estándar, que son útiles para ayudarle a entender el funcionamiento de los webhooks.

Para completar las instrucciones paso a paso de este artículo, descargue e instale las siguientes herramientas:

Paso 1: Registrar una aplicación de Azure AD para el cliente de Postman

Para que el cliente de Postman se comunique con SharePoint, necesita registrar una aplicación de Microsoft Azure Active Directory (Azure AD) en su espacio empresarial de Azure AD asociado a su espacio empresarial de Office 365.

  1. Asegúrese de que registra la aplicación como Aplicación web.

  2. Para tener acceso a SharePoint Online, es importante conceder a la aplicación de Azure AD permisos para la aplicación de Office 365 SharePoint Online y seleccionar el permiso leer y escribir elementos y listas en todas las colecciones de sitios.

    Nota:

    Para obtener más información sobre cómo agregar una aplicación de Azure AD y conceder permisos a las aplicaciones, consulte Agregar una aplicación.

  3. Escriba el siguiente punto de conexión como la dirección URL de respuesta (redireccionamiento) de la aplicación. Este es el punto de conexión al que Azure AD enviará la respuesta de autenticación, incluido el token de acceso, si la autenticación se realizó correctamente.

     https://www.getpostman.com/oauth2/callback
    
  4. Genere también una clave, que será el secreto de cliente.

  5. Las siguientes propiedades se necesitan en pasos posteriores, así que cópielas en un lugar seguro:

    • Identificador de cliente
    • Secreto de cliente

Paso 2: Crear un receptor de webhook

Para este proyecto, use el proyecto de Web API de Visual Studio para crear el receptor de webhook.

Crear un nuevo proyecto de ASP.NET Web API

  1. Abra Visual Studio.

  2. Seleccione Archivo>Nuevo>Proyecto.

  3. En el panel Plantillas, seleccione Plantillas instaladas y expanda el nodo Visual C#.

  4. En Visual C#, seleccione Web.

  5. En la lista de plantillas de proyecto, seleccione Aplicación web ASP.NET.

  6. Asigne al proyecto el nombre SPWebhooksReceiver y seleccione Aceptar.

  7. En el cuadro de diálogo Nuevo proyecto de ASP.NET, seleccione la plantilla Web API del grupo ASP.NET 4.5..

  8. Cambie la autenticación a Sin autenticación; para ello, seleccione el botón Cambiar autenticación.

  9. Seleccione Aceptar para crear el proyecto de Web API.

Nota:

Puede desactivar la casilla Host en la nube porque este proyecto no se implementará en la nube.

Visual Studio crea el proyecto.

Compilar el receptor de webhook

Instalar paquetes NuGet

Use ASP.NET Web API Tracing para registrar las solicitudes que provengan de SharePoint. Los pasos siguientes instalan el paquete de seguimiento:

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra el menú contextual (haga clic con el botón derecho) del proyecto y seleccione Administrar paquetes NuGet.

  3. En el cuadro de búsqueda, escriba Microsoft.AspNet.WebApi.Tracing.

  4. En los resultados de la búsqueda, seleccione el paquete Microsoft.AspNet.WebApi.Tracing y seleccione Instalar para instalar el paquete.

Compilar el modelo SPWebhookNotification

Cada notificación que ha generado el servicio se serializa en una instancia webhookNotification. Necesita crear un modelo sencillo que represente esta instancia de notificación.

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra el menú contextual (haga clic con el botón derecho) de la carpeta Modelos y seleccione Agregar>Clase.

  3. Escriba SPWebhookNotification como el nombre de clase y seleccione Agregar para agregar la clase al proyecto.

  4. Agregue el siguiente código al cuerpo de la clase 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; }
    

Compilar el modelo SPWebhookContent

Como pueden enviarse varias notificaciones a su receptor de webhook en una sola solicitud, se combinan conjuntamente en un objeto con un valor individual de matriz. Cree un modelo sencillo que represente la matriz.

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra el menú contextual (haga clic con el botón derecho) de la carpeta Modelos y seleccione Agregar>Clase.

  3. Escriba SPWebhookContent como el nombre de clase y seleccione Agregar para agregar la clase al proyecto.

  4. Agregue el siguiente código al cuerpo de la clase SPWebhookContent:

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

Agregar el estado del cliente de webhook de SharePoint

Los webhooks proporcionan la capacidad de usar un valor de cadena opcional que se pasa al mensaje de notificación de su suscripción. Puede usarse para comprobar que la solicitud proviene realmente del origen de confianza, en este caso, de SharePoint.

Agregue un valor de estado del cliente con el que la aplicación pueda comprobar las solicitudes entrantes.

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra el archivo web.config y agregue la siguiente clave como el estado del cliente a la sección <appSettings>:

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

Habilitar el seguimiento

En el archivo web.config, habilite el seguimiento agregando la siguiente clave dentro del elemento <system.web> de la sección <configuration>:

<trace enabled="true"/>

Se necesita un escritor de seguimiento, por lo que debe agregar uno a la configuración del controlador (en este caso use la de System.Diagnostics).

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra WebApiConfig.cs en la carpeta App_Start.

  3. Agregue la siguiente línea dentro del método Register:

     config.EnableSystemDiagnosticsTracing();
    

Compilar el controlador de webhook de SharePoint

Ahora, cree el controlador del receptor de webhook que controla las solicitudes entrantes de SharePoint y actúe en consecuencia.

  1. Vaya al Explorador de soluciones en Visual Studio.

  2. Abra el menú contextual (haga clic con el botón derecho) de la carpeta Controladores y seleccione Agregar>Controlador.

  3. En el cuadro de diálogo Agregar scaffold, seleccione Controlador de Web API 2 – en blanco.

  4. Seleccione Agregar.

  5. Asigne al controlador el nombre SPWebhookController y seleccione Agregar para agregar el controlador de la API al proyecto.

  6. Reemplace las instrucciones using por el siguiente código:

     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. Reemplace el código de la clase SPWebhookController por el siguiente código:

     [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. Guarde el archivo.

Paso 3: Depurar un receptor de webhook

  1. Seleccione F5 para depurar el receptor de webhook.

  2. Cuando tenga abierto el explorador, copie el número de puerto de la barra de direcciones. Por ejemplo: http://localhost:<_port-number_>

Paso 4: Ejecutar el proxy de ngrok

  1. Abra un terminal de la consola.

  2. Vaya a la carpeta extraída de ngrok.

  3. Escriba lo siguiente con la dirección URL del número de puerto del paso anterior para iniciar ngrok:

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

    Debería ver que ngrok se ejecuta.

  4. Copie la dirección HTTPS de reenvío. Usará esta dirección como el proxy de servicio para que SharePoint envíe las solicitudes.

Paso 5: Agregar una suscripción de webhook con Postman

Obtener el nuevo token de acceso

Postman facilita mucho el trabajo con las API. El primer paso consiste en configurar Postman para autenticarse con Azure AD de forma que pueda enviar solicitudes de API a SharePoint. Usará la aplicación de Azure AD que ha registrado en el paso 1.

  1. Abra Postman. Aparece una barra lateral y un editor de solicitudes.

  2. Seleccione la pestaña Autorización en el Editor de solicitudes.

  3. Seleccione OAuth 2.0 en la lista Tipo.

  4. Seleccione el botón Obtener un token de acceso nuevo.

  5. En la ventana del cuadro de diálogo, escriba lo siguiente:

    • URL de autorización:
      • https://login.microsoftonline.com/common/oauth2/authorize?resource=https%3A%2F%2F<_your-sharepoint-tenant-url-without-https_>
      • Reemplace your-sharepoint-tenant-url-without-https con la dirección URL de su espacio empresarial sin el prefijo https.
    • URL del token de acceso: https://login.microsoftonline.com/common/oauth2/token
    • Id. de cliente: id. de cliente de la aplicación que ha registrado anteriormente en el primer paso.
    • Secreto de cliente: secreto de cliente de la aplicación que ha registrado anteriormente en el primer paso.
    • Nombre del token: sp_webhooks_token
    • Tipo de concesión: código de autorización
  6. Seleccione Solicitar token para iniciar sesión, aceptar y obtener el token de la sesión.

  7. Cuando el token se recupera correctamente, debería ver access_token variable agregada a la pestaña Autorización .

  8. Seleccione la opción para Agregar token al encabezado.

  9. Haga doble clic en la variable access_token para agregar el token al encabezado de la solicitud.

    Postman obtiene el nuevo token de acceso

Obtener el identificador de la lista de documentos

Necesita administrar webhooks para la biblioteca de documentos predeterminada, que se aprovisiona en su colección de sitios predeterminada con el nombre Documentos. Obtenga el identificador de esta lista emitiendo una solicitud GET:

  1. Escriba la siguiente dirección URL de solicitud:

     https://site-collection/_api/web/lists/getbytitle('Documents')?$select=Title,Id
    
  2. Reemplace site-collection por su colección de sitios.

    Postman ejecuta su solicitud y, si es correcta, debe ver el resultado.

  3. Copie el identificador de los resultados. Después, usará el identificador para realizar solicitudes de webhook.

Agregar una suscripción de webhook

Ahora que tiene la información necesaria, cree la consulta y la solicitud para agregar una suscripción de webhook. Use el editor de solicitudes para los siguientes pasos:

  1. Cambie la solicitud a POST de GET.

  2. Escriba lo siguiente como la dirección URL de solicitud:

     https://site-collection/_api/web/lists('list-id')/subscriptions
    
  3. Reemplace site-collection por su colección de sitios.

  4. Vaya a la pestaña Encabezados.

  5. Asegúrese de que todavía tiene el encabezado Autorización. Si no es así, debe solicitar un nuevo token de acceso.

  6. Agregue los siguientes pares de encabezado clave>valor:

    • Accept > application/json;odata=nometadata
    • Application/json de tipo > de contenido
  7. Vaya a la pestaña Cuerpo y seleccione el formato sin procesar.

  8. Pegue el siguiente JSON como el cuerpo:

     {
       "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 add webhook body

  9. Asegúrese de que expirationDateTime es de 6 meses a partir de hoy como máximo.

  10. Asegúrese de que está depurando el receptor de webhook como en el paso 4.

  11. Seleccione Enviar para ejecutar la solicitud.

    Si la solicitud se realiza correctamente, debe ver la respuesta de SharePoint que proporciona los detalles de la suscripción. En el siguiente ejemplo se muestra una respuesta para una suscripción recién creada:

    {
      "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. Copie el identificador de la suscripción. La necesitará para el siguiente conjunto de solicitudes.

  13. Vaya al proyecto del receptor de webhook en Visual Studio y examine la ventana de salida. Debe ver los registros de seguimiento que tienen un aspecto similar al siguiente seguimiento, junto con otros mensajes:

    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'
    

    El seguimiento indica que el webhook ha recibido inicialmente una solicitud de validación. Si observa el código, verá que devuelve el token de validación inmediatamente de manera que SharePoint pueda validar la solicitud:

    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;
    }
    

Paso 6: Obtener detalles de la suscripción

Ahora, ejecutará consultas en Postman para obtener los detalles de la suscripción.

  1. Abra el cliente de Postman.

  2. Cambie la solicitud a GET de POST.

  3. Escriba lo siguiente como la solicitud:

     https://site-collection/_api/web/lists('list-id')/subscriptions
    
  4. Reemplace site-collection por su colección de sitios.

  5. Seleccione Enviar para ejecutar la solicitud.

    Si se realiza correctamente, debe ver que SharePoint devuelve las suscripciones de este recurso de lista. Como acaba de agregar uno, debe ver al menos una suscripción devuelta. En el siguiente ejemplo se muestra una respuesta con una suscripción:

     {
       "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. Ejecute la siguiente consulta para obtener detalles de la suscripción determinada:

     https://site-collection/_api/web/lists('list-id')/subscriptions('subscription-id')
    
  7. Reemplace subscription-id con el identificador de la suscripción.

Paso 7: Probar la notificación de webhook

Ahora, agregue un archivo a la biblioteca de documentos y pruebe si obtiene una notificación de SharePoint en el receptor de webhook.

  1. Vaya a Visual Studio.

  2. En SPWebhookController, coloque un punto de interrupción en la siguiente línea de código:

     var requestContent = Request.Content.ReadAsStringAsync().Result;
    
  3. Vaya a la biblioteca Documentos. Se denomina biblioteca de documentos compartidos en su colección de sitios predeterminada.

  4. Agregue un archivo nuevo.

  5. Vaya a Visual Studio y espere hasta que se alcance el punto de interrupción.

    El tiempo de espera puede variar de unos segundos a cinco minutos. Cuando se alcance el punto de interrupción, el receptor de webhook acaba de recibir una notificación de SharePoint.

  6. Seleccione F5 para continuar.

  7. Para ver los datos de la notificación, busque en la ventana de salida las siguientes entradas, ya que ha agregado los datos de la notificación en el registro de seguimiento:

     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'
    

Este proyecto solo escribe la información en el registro de seguimiento. En cambio, en su receptor, envía esta información a una tabla o una cola que pueda procesar los datos recibidos para obtener información de SharePoint.

Con estos datos, puede crear la dirección URL y usar la API de GetChanges para obtener los últimos cambios.

Pasos siguientes

En este artículo, ha usado el cliente de Postman y una API web sencilla para suscribirse y recibir notificaciones de webhook de SharePoint.

Después, consulte SharePoint webhooks sample reference implementation (Implementación de referencias de ejemplo de webhooks de SharePoint), que muestra un ejemplo integral que usa Azure Storage Queues para procesar la información, obtener cambios de SharePoint y traspasar esos cambios de nuevo a una lista de SharePoint.