API WordPress WooCommerce ASP.net WebHookHandler: запрос WebHook должен содержать тело объекта, отформатированное как данные формы HTML

Я пытаюсь создать WebHookHandler для веб-крючков, отправленных из WordPress WooCommerce в ASP.NET C#.

Я начал с создания проекта веб-приложения API ASP.NET C# Azure и добавления соответствующих ссылок (Microsoft.AspNet.WebHooks.Common, Microsoft.AspNet.WebHooks.Receivers, Microsoft.AspNet.WebHooks.Receivers.WordPress). Добавил WebHookConfig, WordPressWebHookHandler и зарегистрировал WebHookConfig в GlobalAsax.

Затем я опубликовал приложение в качестве службы приложений Azure.

Мой WordPressWebHookHandler по-прежнему является примером по умолчанию и выглядит так:

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

При тестировании WebHook Создание пользователя в WooCommerce я вижу запрос в журнале, как показано ниже.

Журнал запросов Webhook

Но, к сожалению, он никогда не получен во время отладки, и я вижу ошибку ниже.

Ошибка журнала запроса Webook

Я думаю, может быть, мне нужен собственный WebHook вместо конкретного WordPress, так как это WooCommerce Webhook. Или, возможно, он неправильно обрабатывается в маршрутизации и заканчивается в другом контроллере.

Буду признателен за любую оказанную помощь.

3 ответа

Решение

Я хотел бы внести некоторые дополнения в ответ Свека, так как теперь я получил законченное доказательство концепции и немного разбираюсь в приемниках.

Его ответ указал мне правильное направление, но нуждается в небольшом дополнении.

WordpressWebHookReceiver Может принимать в Wordpress Webhooks типа HttpPost. Это не работает с Woocommerce, так как Woocommerce отправляет сообщения Json Webhook и не проходит проверку HttpPost, встроенную в класс WordpressWebHookReceiver.

CustomWebHookReceiver Может принимать пользовательские ASP.NET Webhooks. У пользовательских веб-зацепок ASP.NET есть специальный партнер для проверки, который включает, но не ограничивается "ms-signature". Даже добавления заголовка будет недостаточно, поскольку подпись также используется не по умолчанию, а из Woocommerce для шифрования сообщения. По сути, доходит до того, что вы не можете интегрировать WooCommerce с CustomWebHookReceiver без изменения классов Webhook WooCommerce.

GenericWebHookReceiver Это требуемый приемник, который принимает в основном общий набор данных Json и сможет использовать параметр запроса "code" для проверки секрета, который вы можете добавить в web.config вашего API-приложения asp.net. Я использовал этот приемник для завершения проверки концепции и получил как проверку подписи, так и расшифровку сообщения, работающего прямо на летучей мыши.

Мой базовый класс, который я начну встраивать в реальное решение, можно посмотреть ниже и изменить JObject на динамический объект в методах, которые я вызываю из класса. Как вы можете видеть, у меня есть два добавленных метода: один для создания клиента и один для создания заказа для вызова соответствующих методов, которые выполняют вставку в Dynamics 365 (прежняя версия 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);
    }
}

Ваш WebHookReceiver неправильный

Существует несоответствие ожидания данных формы HTML, тогда как на самом деле это ожидание JSON.

WordPressWebHookHandler по-прежнему по умолчанию

Это то, что вызывает вашу ошибку. Если вы посмотрите на WordPressWebHookReceiver, ReceiveAsync() реализация метода, призывает к ReadAsFormDataAsync() метод, который не то, что вы хотите, как ваш Content-Type является json, Итак, вы хотите делать ReadAsJsonAsync(),

Решение: не используйте WordPressWebHookReceiver и переключите его на другой, который будет вызывать ReadAsJsonAsync(),


Глядя на код

Я думаю, может быть, мне нужен собственный WebHook вместо конкретного WordPress, так как это WooCommerce Webhook.

У вас была правильная идея, поэтому я выкопал часть кода, чтобы точно объяснить, почему это происходит.

Блок кода ниже является ReceiveAsync() метод, который переопределяется в WordPressWebHookReceiver. Вы можете видеть, что это вызывает ReadAsFormDataAsync() что не то, что вы хотите...

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

Быстрый поиск в хранилище классов, которые вызывают ReadAsJsonAsync() метод, показывает, что следующие приемники реализуют его:

  1. DynamicsCrmWebHookReceiver
  2. ZendeskWebHookReceiver
  3. AzureAlertWebHookReceiver
  4. KuduWebHookReceiver
  5. MyGetWebHookReceiver
  6. VstsWebHookReceiver
  7. BitbucketWebHookReceiver
  8. CustomWebHookReceiver
  9. DropboxWebHookReceiver
  10. GitHubWebHookReceiver
  11. PaypalWebHookReceiver
  12. StripeWebHookReceiver
  13. PusherWebHookReceiver

Я предположил, что CustomWebHookReceiver будет соответствовать вашим требованиям, поэтому можете взять NuGet здесь. В противном случае вы можете реализовать свой собственный, или извлечь его из этого класса и т. Д.


Настройка получателя WebHook

(Скопировано из документации Microsoft)

https://www.nuget.org/packages?q=Microsoft.AspNet.WebHooks.Receivers.Custom обеспечивает поддержку для получения веб-книг, сгенерированных ASP.NET веб-книг

Из коробки вы можете найти поддержку Dropbox, GitHub, MailChimp, PayPal, Pusher, Salesforce, Slack, Stripe, Trello и WordPress, но можно поддерживать любое количество других провайдеров.

Инициализация Приемника WebHook

Приемники WebHook инициализируются путем их регистрации, как правило, в WebApiConfig статический класс, например:

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

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

Существует проблема с форматом данных, который вы отправляете в своем запросе. Вы должны использовать формат формы HTML, как указано в сообщении об ошибке.

Правильный формат данных POST описан здесь: Как параметры отправляются в запросе HTTP POST?

Не забудьте установить заголовок Content-Length и исправить Content-Type, если ваша библиотека этого не делает. Обычно тип контента application/x-www-form-urlencoded,

Другие вопросы по тегам