WordPress WooCommerce ASP.net API WebHookHandler:WebHook 请求必须包含格式为 HTML 表单数据的实体正文
WordPress WooCommerce ASP.net API WebHookHandler: The WebHook request must contain an entity body formatted as HTML Form Data
我正在尝试在 ASP.NET C# 中为从 WordPress WooCommerce 发送的 Webhook 创建一个 WebHookHandler。
我开始创建一个 ASP.NET C# Azure API App WebApplication 项目并添加相关参考(Microsoft.AspNet.WebHooks.Common、Microsoft.AspNet.WebHooks.Receivers、Microsoft.AspNet.WebHooks.Receivers.WordPress ).添加WebHookConfig、WordPressWebHookHandler 并在GlobalAsax 中注册WebHookConfig。
然后我将该应用程序发布为 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);
}
}
在 WooCommerce 中测试用户创建 WebHook 时,我可以在日志中看到如下请求。
但不幸的是,调试时从未收到它,我看到以下错误。
我在想也许我需要一个自定义的 WebHook 而不是 WordPress 特定的 WebHook,因为这是一个 WooCommerce Webhook。或者它可能在路由中处理错误并最终在另一个控制器中。
非常感谢任何帮助。
您在请求中发送的数据格式有问题。您必须使用 HTML 格式,如您的错误消息所述。
此处描述了正确的 POST 数据格式:How are parameters sent in an HTTP POST request?
如果您的图书馆不这样做,请不要忘记设置 Content-Length header 并更正 Content-Type。通常内容类型是application/x-www-form-urlencoded
.
你的 WebHookReceiver 是错误的
期望 HTML 表单数据不匹配,而实际上它应该期望 JSON.
WordPressWebHookHandler is still the default
这就是导致错误的原因。 如果您查看 WordPressWebHookReceiver
,ReceiveAsync()
方法实现,调用 ReadAsFormDataAsync()
方法,这 不是您想要的 ,因为您的 Content-Type
是 json
。所以,你想做 ReadAsJsonAsync()
.
解决方法:不要使用WordPressWebHookReceiver
,换成另一个会调用ReadAsJsonAsync()
.
的
看代码
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook.
你的想法是正确的,所以我挖掘了一些代码来解释为什么会发生这种情况。
下面的代码块是 WordPressWebHookReceiver 中重写的 ReceiveAsync()
方法。你可以看到它正在调用 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()
方法的 classes,显示以下接收者实现了它:
- DynamicsCrmWebHookReceiver
- ZendeskWebHookReceiver
- AzureAlertWebHookReceiver
- KuduWebHookReceiver
- MyGetWebHookReceiver
- VstsWebHookReceiver
- BitbucketWebHookReceiver
- CustomWebHookReceiver
- DropboxWebHookReceiver
- GitHubWebHookReceiver
- PaypalWebHookReceiver
- StripeWebHookReceiver
- PusherWebHookReceiver
我认为 CustomWebHookReceiver 会满足您的要求,因此可以在此处获取 NuGet。否则你可以实现你自己的,或者从这个 class 派生它,等等
配置 WebHook 接收器
(从 Microsoft Documentation 复制)
Microsoft.AspNet.WebHooks.Receivers.Custom provides support for
receiving WebHooks generated by ASP.NET WebHooks
Out of the box you can find support for Dropbox, GitHub, MailChimp,
PayPal, Pusher, Salesforce, Slack, Stripe, Trello, and WordPress but
it is possible to support any number of other providers
正在初始化 WebHook 接收器
WebHook Receivers are initialized by registering them, typically in
the WebApiConfig
static class, for example:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
// Load receivers
config.InitializeReceiveGitHubWebHooks();
}
}
我想对 Svek 的回答做一些补充,因为我现在 Proof-of-concept 已经完成并且对接收者有了更多的了解。
他的回答为我指明了正确的方向,但需要补充一点。
WordPressWebHookReceiver
可以接受 HttpPost 类型的 Wordpress Webhooks。这不适用于 Woocommerce,因为 Woocommerce 发送 Json Webhook 消息并且将无法通过内置在 WordpressWebHookReceiver class.
中的 HttpPost 验证
CustomWebHookReceiver
可以接受自定义 ASP.NET Webhooks。自定义 ASP.NET webhooks 有一个特定的验证合作伙伴,包括但不限于 'ms-signature'。即使添加 header 也不够,因为签名还以不同于开箱即用的 Woocommerce 的方式用于加密消息。基本上,如果不更改 Woocommerce 的 Webhook classes,就无法将 Woocommerce 与 CustomWebHookReceiver 集成。
GenericWebHookReceiver
这是你想要的接收器,它基本上接受一组通用的 Json 数据,并且能够使用 "code" 查询参数来验证你可以在 web.config 中添加的秘密您的 asp.net api 应用程序。我用这个接收器完成了 Proof-of-concept 并获得了签名验证以及消息的解密工作权。
我的基本 class 我将开始构建到一个真正的解决方案中,可以在下面查看并将 JObject 更改为我从 class 调用的方法中的动态 object .如您所见,我目前添加了两种方法,一种用于客户创建,一种用于订单创建,以调用相应的方法,这些方法会插入到 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);
}
}
我正在尝试在 ASP.NET C# 中为从 WordPress WooCommerce 发送的 Webhook 创建一个 WebHookHandler。
我开始创建一个 ASP.NET C# Azure API App WebApplication 项目并添加相关参考(Microsoft.AspNet.WebHooks.Common、Microsoft.AspNet.WebHooks.Receivers、Microsoft.AspNet.WebHooks.Receivers.WordPress ).添加WebHookConfig、WordPressWebHookHandler 并在GlobalAsax 中注册WebHookConfig。
然后我将该应用程序发布为 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);
}
}
在 WooCommerce 中测试用户创建 WebHook 时,我可以在日志中看到如下请求。
但不幸的是,调试时从未收到它,我看到以下错误。
我在想也许我需要一个自定义的 WebHook 而不是 WordPress 特定的 WebHook,因为这是一个 WooCommerce Webhook。或者它可能在路由中处理错误并最终在另一个控制器中。
非常感谢任何帮助。
您在请求中发送的数据格式有问题。您必须使用 HTML 格式,如您的错误消息所述。
此处描述了正确的 POST 数据格式:How are parameters sent in an HTTP POST request?
如果您的图书馆不这样做,请不要忘记设置 Content-Length header 并更正 Content-Type。通常内容类型是application/x-www-form-urlencoded
.
你的 WebHookReceiver 是错误的
期望 HTML 表单数据不匹配,而实际上它应该期望 JSON.
WordPressWebHookHandler is still the default
这就是导致错误的原因。 如果您查看 WordPressWebHookReceiver
,ReceiveAsync()
方法实现,调用 ReadAsFormDataAsync()
方法,这 不是您想要的 ,因为您的 Content-Type
是 json
。所以,你想做 ReadAsJsonAsync()
.
解决方法:不要使用WordPressWebHookReceiver
,换成另一个会调用ReadAsJsonAsync()
.
看代码
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook.
你的想法是正确的,所以我挖掘了一些代码来解释为什么会发生这种情况。
下面的代码块是 WordPressWebHookReceiver 中重写的 ReceiveAsync()
方法。你可以看到它正在调用 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()
方法的 classes,显示以下接收者实现了它:
- DynamicsCrmWebHookReceiver
- ZendeskWebHookReceiver
- AzureAlertWebHookReceiver
- KuduWebHookReceiver
- MyGetWebHookReceiver
- VstsWebHookReceiver
- BitbucketWebHookReceiver
- CustomWebHookReceiver
- DropboxWebHookReceiver
- GitHubWebHookReceiver
- PaypalWebHookReceiver
- StripeWebHookReceiver
- PusherWebHookReceiver
我认为 CustomWebHookReceiver 会满足您的要求,因此可以在此处获取 NuGet。否则你可以实现你自己的,或者从这个 class 派生它,等等
配置 WebHook 接收器
(从 Microsoft Documentation 复制)
Microsoft.AspNet.WebHooks.Receivers.Custom provides support for receiving WebHooks generated by ASP.NET WebHooks
Out of the box you can find support for Dropbox, GitHub, MailChimp, PayPal, Pusher, Salesforce, Slack, Stripe, Trello, and WordPress but it is possible to support any number of other providers
正在初始化 WebHook 接收器
WebHook Receivers are initialized by registering them, typically in the
WebApiConfig
static class, for example:public static class WebApiConfig { public static void Register(HttpConfiguration config) { ... // Load receivers config.InitializeReceiveGitHubWebHooks(); } }
我想对 Svek 的回答做一些补充,因为我现在 Proof-of-concept 已经完成并且对接收者有了更多的了解。
他的回答为我指明了正确的方向,但需要补充一点。
WordPressWebHookReceiver 可以接受 HttpPost 类型的 Wordpress Webhooks。这不适用于 Woocommerce,因为 Woocommerce 发送 Json Webhook 消息并且将无法通过内置在 WordpressWebHookReceiver class.
中的 HttpPost 验证CustomWebHookReceiver 可以接受自定义 ASP.NET Webhooks。自定义 ASP.NET webhooks 有一个特定的验证合作伙伴,包括但不限于 'ms-signature'。即使添加 header 也不够,因为签名还以不同于开箱即用的 Woocommerce 的方式用于加密消息。基本上,如果不更改 Woocommerce 的 Webhook classes,就无法将 Woocommerce 与 CustomWebHookReceiver 集成。
GenericWebHookReceiver 这是你想要的接收器,它基本上接受一组通用的 Json 数据,并且能够使用 "code" 查询参数来验证你可以在 web.config 中添加的秘密您的 asp.net api 应用程序。我用这个接收器完成了 Proof-of-concept 并获得了签名验证以及消息的解密工作权。
我的基本 class 我将开始构建到一个真正的解决方案中,可以在下面查看并将 JObject 更改为我从 class 调用的方法中的动态 object .如您所见,我目前添加了两种方法,一种用于客户创建,一种用于订单创建,以调用相应的方法,这些方法会插入到 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);
}
}