WordPress WooCommerce ASP.net API WebHookHandler: la solicitud de WebHook debe contener un cuerpo de entidad formateado como datos de formulario HTML

7 minutos de lectura

avatar de usuario
kevin hendricks

Estoy tratando de crear un WebHookHandler para enviar Webhooks desde WordPress WooCommerce en ASP.NET C#.

Comencé con la creación de un proyecto de aplicación web ASP.NET C# Azure API App y agregué las referencias relevantes (Microsoft.AspNet.WebHooks.Common, Microsoft.AspNet.WebHooks.Receivers, Microsoft.AspNet.WebHooks.Receivers.WordPress). Se agregó WebHookConfig, WordPressWebHookHandler y se registró WebHookConfig en GlobalAsax.

Luego publiqué la aplicación como Azure App Service.

Mi WordPressWebHookHandler sigue siendo el predeterminado de los ejemplos y se ve así:

public class WordPressWebHookHandler : WebHookHandler
{
    public override Task ExecuteAsync(string receiver, WebHookHandlerContext context)
    {
        // make sure we're only processing the intended type of hook
        if("WordPress".Equals(receiver, System.StringComparison.CurrentCultureIgnoreCase))
        {
            // todo: replace this placeholder functionality with your own code
            string action = context.Actions.First();
            JObject incoming = context.GetDataOrDefault<JObject>();
        }

        return Task.FromResult(true);
    }
}

Al probar un WebHook de creación de usuarios en WooCommerce, puedo ver la solicitud en el registro como se muestra a continuación.

Registro de solicitud de webhook

Pero desafortunadamente nunca se recibe durante la depuración y veo el siguiente error.

Error de registro de solicitud de libro web

Estoy pensando que tal vez necesito un WebHook personalizado en lugar del específico de WordPress, ya que este es un Webhook de WooCommerce. O posiblemente se maneje mal en el enrutamiento y termine en otro controlador.

Cualquier ayuda es muy apreciada.

avatar de usuario
Svek

Su WebHookReceiver es incorrecto

Hay una falta de coincidencia al esperar datos de formulario HTML, cuando en realidad debería estar esperando JSON.

WordPressWebHookHandler sigue siendo el predeterminado

Esto es lo que está causando su error. Si miras el WordPressWebHookReceiverla ReceiveAsync() implementación del método, llama a ReadAsFormDataAsync() método, que es no lo que quieres, como tu Content-Type es json. Entonces, quieres estar haciendo ReadAsJsonAsync().

Solución: no use el WordPressWebHookReceiver y cambiarlo a otro que llamará ReadAsJsonAsync().


Mirando el código

Estoy pensando que tal vez necesito un WebHook personalizado en lugar del específico de WordPress, ya que este es un Webhook de WooCommerce.

Tuviste la idea correcta, así que desenterré parte del código para explicar exactamente por qué sucedía esto.

El bloque de código a continuación es el ReceiveAsync() método que se anula en el WordPressWebHookReceiver. Puedes ver que está llamando al ReadAsFormDataAsync() que no es lo que quieres…

public override async Task<HttpResponseMessage> ReceiveAsync(
    string id, HttpRequestContext context, HttpRequestMessage request)
{
    ...
    if (request.Method == HttpMethod.Post)
    {
        // here is what you don't want to be called
        // you want ReadAsJsonAsync(), In short, USE A DIFFERENT RECEIVER.
        NameValueCollection data = await ReadAsFormDataAsync(request);
        ...
    }
    else
    {
       return CreateBadMethodResponse(request);
    }
}

Una búsqueda rápida a través del repositorio de clases que llaman al ReadAsJsonAsync() método, muestra que los siguientes receptores lo implementan:

  1. DynamicsCrmWebHookReceiver
  2. ZendeskWebHookReceptor
  3. AzureAlertWebHookReceiver
  4. KuduWebHookReceptor
  5. MyGetWebHookReceiver
  6. VstsWebHookReceptor
  7. BitbucketWebHookReceiver
  8. CustomWebHookReceiver
  9. DropboxWebHookReceiver
  10. GitHubWebHookReceptor
  11. PaypalWebHookReceiver
  12. StripeWebGanchoReceptor
  13. empujadorwebganchoreceptor

Supuse que el CustomWebHookReceiver se ajustaría a sus requisitos, por lo que puede tomar el NuObtener aquí. De lo contrario, puede implementar el suyo propio o derivarlo de esta clase, etc.


Configuración de un receptor WebHook

(Copiado de la Documentación de Microsoft)

Microsoft.AspNet.WebHooks.Receivers.Personalizado proporciona soporte para recibir WebHooks generados por ASP.NET WebHooks

De fábrica, puede encontrar soporte para Dropbox, GitHub, MailChimp, PayPal, Pusher, Salesforce, Slack, Stripe, Trello y WordPress, pero es posible admitir cualquier número de otros proveedores.

Inicialización de un receptor WebHook

Los receptores WebHook se inicializan registrándolos, normalmente en el WebApiConfig clase estática, por ejemplo:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ...

        // Load receivers
        config.InitializeReceiveGitHubWebHooks();
    }
}

  • No entiendo una cosa ahí. ¿Estoy implementando esto en mi proyecto web api para zendesk? ¿Tengo que crear un controlador con ruta api/webhooks/incoming? y ¿cómo llamo a la clase WebHookHandler?

    – codificador771

    16 oct 2018 a las 8:20

  • @ coder771 Es posible que desee considerar buscar un poco en línea, ya que hay muchas formas diferentes de implementar WebHooks en su proyecto. Comenzaría por comprender cómo funciona la mecánica de canalización de solicitudes en asp net core antes de llegar a la conclusión de que necesita un controlador.

    – Svek

    16 oct 2018 a las 9:59

avatar de usuario
Alejandro Ushakov

Hay un problema con el formato de los datos que envías en tu solicitud. Debe usar el formato de formulario HTML como dice su mensaje de error.

El formato de datos POST adecuado se describe aquí: ¿Cómo se envían los parámetros en una solicitud HTTP POST?

No olvide configurar el encabezado Content-Length y corregir Content-Type si su biblioteca no lo hace. Por lo general, el tipo de contenido es application/x-www-form-urlencoded.

  • Hola Alejandro, gracias por tu respuesta. Desafortunadamente, Woocommerce / WordPress envía el contenido en Json listo para usar, que también es mi estándar preferido. Veo muchas publicaciones sobre cómo recibir Json con ASP.NET Webhooks en general, sin embargo, parece que no funciona para mí.

    –Kevin Hendricks

    20 de febrero de 2017 a las 8:43

Me gustaría hacer algunas adiciones a la respuesta de Svek, ya que ahora completé mi prueba de concepto y entiendo un poco más sobre los receptores.

Su respuesta me apuntó en la dirección correcta, pero necesita una pequeña adición.

WordPressWebHookReceiver
Puede admitir WordPress Webhooks de tipo HttpPost. Esto no funciona con Woocommerce, ya que Woocommerce envía mensajes Json Webhook y fallará la validación HttpPost que está integrada en la clase WordPressWebHookReceiver.

CustomWebHookReceiver
Puede admitir Webhooks ASP.NET personalizados. Los webhooks ASP.NET personalizados tienen un socio específico para la validación que incluye, entre otros, la ‘firma de ms’. Incluso agregar el encabezado no será suficiente, ya que la firma también se usa de una manera diferente a Woocommerce listo para usar para cifrar el mensaje. Básicamente, llega a un punto en el que no puede integrar Woocommerce con CustomWebHookReceiver sin cambiar las clases de Webhook de Woocommerce.

GenericWebHookReceiver
Este es el receptor que desea, que acepta básicamente un conjunto genérico de datos Json y podrá usar el parámetro de consulta “código” para verificar el secreto que puede agregar en el web.config de su aplicación api asp.net. Usé este receptor para terminar la prueba de concepto y obtuve tanto la validación de la firma como el descifrado del mensaje inmediatamente.

Mi clase básica que comenzaré a construir en una solución real se puede ver a continuación y cambia el JObject en un objeto dinámico en los métodos que llamo desde la clase. Como puede ver, tengo dos métodos agregados actualmente, uno para la creación del cliente y otro para la creación del pedido para llamar a los métodos respectivos que hacen una inserción en Dynamics 365 (antiguo CRM).

public class GenericJsonWebHookHandler : WebHookHandler
{
    public GenericJsonWebHookHandler()
    {
        this.Receiver = "genericjson";
    }

    public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
    {
        var result = false;

        try
        {
            // Get JSON from WebHook
            var data = context.GetDataOrDefault<JObject>();

            if(context.Id != "crcu" && context.Id != "cror")
                return Task.FromResult(true);

            if (context.Id == "crcu")
            {
                result = WoocommerceCRMIntegrations.Entities.Contact.CreateContactInCRM(data);
            }
            else if (context.Id == "cror")
            {
                result = WoocommerceCRMIntegrations.Entities.Order.CreateOrderInCRM(data);
            }
        }
        catch (Exception ex)
        {
            result = false;
        }


        return Task.FromResult(result);
    }
}

  • No hay problema, pensé que mereces los créditos por la extensa respuesta que me indicó la dirección correcta. Gracias de nuevo

    –Kevin Hendricks

    28 de febrero de 2017 a las 15:14

  • Hola. Estoy usando WooComm 4.0.1 y probé nuestro enfoque, pero no me funciona en absoluto. “Error: la URL de entrega devolvió el código de respuesta: 415” Si voy y activo el enlace de todos modos, veo que pasó en los registros de wordpress. Pero en el lado .net dice en el registro: w3wp.exe Información: 0: Procesando la solicitud WebHook entrante con el receptor ‘genericjson’ y la identificación ‘crcpn’. Información de w3wp.exe: 0: la solicitud de WebHook debe contener un cuerpo de entidad con formato JSON. No estoy seguro de dónde me equivoco. ¡Ayuda por favor!

    – Mudasser Mian

    12 mayo 2020 a las 15:45

¿Ha sido útil esta solución?