WordPress WooCommerce ASP.net API WebHookHandler: WebHook请求必须包含格式为HTML表单数据的实体主体。

12

我正在尝试在ASP.NET C#中为从WordPress WooCommerce发送的Webhooks创建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 request log

但不幸的是,在调试过程中从未收到它,我看到以下错误:

Webook request log error

我认为可能需要一个自定义WebHook而不是WordPress特定的WebHook,因为这是WooCommerce Webhook。或者可能在路由处理中处理有误,导致其进入另一个控制器。

非常感谢任何帮助。

3个回答

5

您的WebHookReceiver有误

期望接收HTML表单数据,但实际上应该是JSON数据的不匹配。

WordPressWebHookHandler仍是默认值

这是导致错误的原因。如果您查看WordPressWebHookReceiver,则ReceiveAsync()方法实现会调用 ReadAsFormDataAsync()方法,这不是您需要的,因为您的Content-Typejson。所以,您应该使用ReadAsJsonAsync()

解决方案:不要使用WordPressWebHookReceiver,将其切换到另一个将调用ReadAsJsonAsync()的接收器。


查看代码

我想也许我需要一个自定义WebHook,而不是WordPress特定的WebHook,因为这是一个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()方法的类的代码库进行快速搜索,可以看到以下接收器实现了它:
  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文档

Microsoft.AspNet.WebHooks.Receivers.Custom支持接收由ASP.NET WebHooks生成的WebHooks

开箱即用,您可以找到针对Dropbox、GitHub、MailChimp、PayPal、Pusher、Salesforce、Slack、Stripe、Trello和WordPress的支持,但也可以支持任意数量的其他提供程序。

初始化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();
    }
}

我在这里有一件事不明白。我正在我的Zendesk Web API项目中实现这个?我需要创建一个路由为api/webhooks/incoming的控制器吗?如何调用WebHookHandler类? - coder771
@coder771 你可能想要在网上搜索一下,因为有很多不同的方法可以在你的项目中实现WebHooks。在得出需要控制器的结论之前,我建议先了解一下asp net core中请求管道机制的工作原理。 - Svek

1
你发送请求时的数据格式存在问题。你需要按照错误信息中所述的HTML表单格式来发送请求。
正确的POST数据格式可在此处找到:HTTP POST请求中参数是如何发送的? 如果你的库没有设置,不要忘记设置Content-Length头和正确的Content-Type。通常,内容类型为application/x-www-form-urlencoded

亲爱的Alexander,谢谢你的回复。不幸的是,Woocommerce / Wordpress默认以Json格式发送内容,这也是我首选的标准。我看到很多关于ASP.NET Webhooks接收Json的帖子,但是对我来说似乎并没有起作用。 - Kevin Hendricks

1
我想对Svek的回答进行一些补充,因为我现在已经完成了我的Proof-of-concept,并且对接收者有了更多的了解。
他的回答指引了我正确的方向,但还需要一点补充。 WordpressWebHookReceiver 可以接收类型为HttpPost的Wordpress Webhooks。这无法与Woocommerce配合使用,因为Woocommerce会发送Json Webhook消息,并且会失败HttpPost验证,这是内置于WordpressWebHookReceiver类中的。 CustomWebHookReceiver 可以接收自定义的ASP.NET Webhooks。自定义的ASP.NET Webhooks具有特定的验证伙伴,其中包括但不限于“ms-signature”。即使添加了标题也不足够,因为签名也以与开箱即用的Woocommerce不同的方式用于加密消息。基本上,如果不更改Woocommerce的Webhook类,则无法将Woocommerce与CustomWebHookReceiver集成。

GenericWebHookReceiver 这是您需要的接收器,它可以接受基本的Json数据,并能够使用“code”查询参数来验证您可以添加到asp.net api应用程序的web.config中的密钥。我使用此接收器完成了概念验证,并在方法调用中将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);
    }
}

没问题,我认为你应该得到这个详细回答的荣誉,它指引了我正确的方向。再次感谢你。 - Kevin Hendricks
你好。我使用的是WooComm 4.0.1,尝试了我们的方法但完全不起作用。“错误:交付URL返回响应代码:415”。如果我继续触发挂钩,我可以在WordPress日志中看到它已经通过了。但在.net侧的日志中说:w3wp.exe信息:0:正在使用接收器“genericjson”和ID“crcpn”处理传入的WebHook请求。 w3wp.exe信息:0:WebHook请求必须包含格式为JSON的实体正文。不确定我错在哪里。求帮助! - Mudasser Mian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接