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

时间:2017-02-17 09:18:52

标签: c# php asp.net wordpress asp.net-webhooks

我正在尝试为ASP.NET C#中的WordPress WooCommerce创建Webhooks发送的WebHookHandler。

我开始创建ASP.NET C#Azure API应用程序WebApplication项目并添加相关引用(Microsoft.AspNet.WebHooks.Common,Microsoft.AspNet.WebHooks.Receivers,Microsoft.AspNet.WebHooks.Receivers.WordPress)。添加了WebHookConfig,WordPressWebHookHandler并在GlobalAsax中注册了WebHookConfig。

然后我将该应用程序发布为Azure App Service。

我的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特定的一个,因为这是一个WooCommerce Webhook。或者可能在路由中处理错误并最终在另一个控制器中。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:5)

您的WebHookReceiver错误

期望HTML表单数据不匹配,实际上它应该是期待JSON。

  

WordPressWebHookHandler仍然是默认

这是导致错误的原因。如果您查看WordPressWebHookReceiver方法实施ReceiveAsync(),请调用ReadAsFormDataAsync()方法,即您想要的内容,因为Content-Typejson。所以,你想做ReadAsJsonAsync()

解决方案:请勿使用WordPressWebHookReceiver并将其切换为另一个将调用ReadAsJsonAsync()的人。

查看代码

  

我想也许我需要一个自定义WebHook而不是WordPress特定的一个,因为这是一个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
  14. 我认为CustomWebHookReceiver符合您的要求,因此可以抓住NuGet here。否则你可以实现自己的,或者从这个类等派生出来。

    配置WebHook接收器

    (从Microsoft Documentation复制)

      

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

         

    开箱即用,你可以找到对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();
        }
    }
    

答案 1 :(得分:1)

您在请求中发送的数据格式存在问题。您必须使用HTML表单的格式作为错误消息说明。

此处描述了正确的POST数据格式:How are parameters sent in an HTTP POST request?

如果您的库不这样做,请不要忘记设置Content-Length标头并更正Content-Type。通常内容类型为application/x-www-form-urlencoded

答案 2 :(得分:1)

我想对Svek的答案做一些补充,因为我现在已经完成了我的概念验证,并对接收器有了更多了解。

他的回答指出了我正确的方向,但需要一点点补充。

<强> WordpressWebHookReceiver 可以接受类型为HttpPost的Wordpress Webhooks。这不适用于Woocommerce,因为Woocommerce发送Json Webhook消息,并且将无法通过构建到WordpressWebHookReceiver类中的HttpPost验证。

<强> CustomWebHookReceiver 可以采用自定义ASP.NET Webhooks。自定义ASP.NET webhooks具有特定的验证合作伙伴,包括但不限于“ms-signature”。即使添加标题也是不够的,因为签名也以与开箱即用的Woocommerce不同的方式用于加密消息。基本上没有改变Wohommerce的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);
    }
}