11

我正在尝试为从 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 请求日志

但不幸的是,调试时从未收到它,我看到以下错误。

Webbook 请求日志错误

我在想也许我需要一个自定义 WebHook 而不是 WordPress 特定的,因为这是一个 WooCommerce Webhook。或者可能在路由中处理错误并最终在另一个控制器中。

任何帮助深表感谢。

4

3 回答 3

5

您的 WebHookReceiver 错误

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

WordPressWebHookHandler 仍然是默认的

这就是导致您的错误的原因。如果您查看方法实现WordPressWebHookReceiver,则ReceiveAsync()调用ReadAsFormDataAsync()方法,这不是您想要的,因为您Content-Typejson. 所以,你想做ReadAsJsonAsync().

解决方案:不要使用WordPressWebHookReceiver并将其切换到另一个会调用ReadAsJsonAsync().


看代码

我在想也许我需要一个自定义 WebHook 而不是 WordPress 特定的,因为这是一个 WooCommerce Webhook。

你的想法是对的,所以我挖掘了一些代码来解释为什么会发生这种情况。

下面的代码块是在WordPressWebHookReceiverReceiveAsync()中被覆盖的方法。你可以看到它正在调用which 这不是你想要的......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. 自定义WebHookReceiver
  9. DropboxWebHookReceiver
  10. GitHubWebHookReceiver
  11. PaypalWebHookReceiver
  12. StripeWebHookReceiver
  13. PusherWebHookReceiver

我假设CustomWebHookReceiver符合您的要求,因此可以在此处获取 NuGet。否则,您可以实现自己的,或从此类派生,等等。


配置 WebHook 接收器

(从微软文档复制)

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();
    }
}
于 2017-02-20T09:32:42.610 回答
1

您在请求中发送的数据格式存在问题。如您的错误消息所述,您必须使用 HTML 表单的格式。

此处描述了正确的 POST 数据格式:如何在 HTTP POST 请求中发送参数?

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

于 2017-02-20T08:33:25.567 回答
1

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

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

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

CustomWebHookReceiver 可以接受自定义 ASP.NET Webhook。自定义 ASP.NET webhook 有一个特定的验证伙伴,包括但不限于“ms 签名”。即使添加标头也不够,因为签名也以与开箱即用的 Woocommerce 不同的方式用于加密消息。基本上,如果不更改 Woocommerce 的 Webhook 类,就无法将 Woocommerce 与 CustomWebHookReceiver 集成。

GenericWebHookReceiver 这是您想要的接收器,它基本上接受一组通用的 Json 数据,并且能够使用“代码”查询参数来验证您可以添加到您的 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);
    }
}
于 2017-02-27T07:54:25.640 回答