Я пытаюсь создать 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 вместо конкретного WordPress, так как это WooCommerce Webhook. Или, возможно, он неправильно обрабатывается в маршрутизации и заканчивается в другом контроллере.
Буду признателен за любую оказанную помощь.
Существует несоответствие ожидания данных формы 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()
метод, показывает, что следующие приемники реализуют его:
Я предположил, что CustomWebHookReceiver будет соответствовать вашим требованиям, так что можете взять NuGet здесь. В противном случае вы можете реализовать свой собственный, или извлечь его из этого класса и т. Д.
(Скопировано из Документация Microsoft)
Microsoft.AspNet.WebHooks.Receivers.Custom обеспечивает поддержку
получение WebHooks, сгенерированных ASP.NET WebHooksИз коробки вы можете найти поддержку Dropbox, GitHub, MailChimp,
PayPal, Pusher, Salesforce, Slack, Stripe, Trello и WordPress, но
можно поддерживать любое количество других провайдеров
Приемники 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
,
Я хотел бы сделать некоторые дополнения к ответу Свека, так как теперь я завершил свою проверку концепции и немного разбираюсь в приемниках.
Его ответ указал мне правильное направление, но нуждается в небольшом дополнении.
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);
}
}