简体   繁体   English

如何在C#WCF中接收Stripe API Webhook

[英]How to receive Stripe api webhook in C# WCF

I am trying to receive webhook from Stripe checkout post request. 我正在尝试从Stripe结帐发布请求中接收Webhook。 but Stripe document is only showing an example code of ASP.net whereas I am using WCF. 但是Stripe文档仅显示ASP.net的示例代码,而我正在使用WCF。 https://stripe.com/docs/payments/checkout/fulfillment#webhooks https://stripe.com/docs/payments/checkout/fulfillment#webhooks

Here is the example request of Stripe checkout. 这是Stripe checkout的示例请求。

{
  "created": 1326853478,
  "livemode": false,
  "id": "evt_00000000000000",
  "type": "checkout.session.completed",
  "object": "event",
  "request": null,
  "pending_webhooks": 1,
  "api_version": "2019-05-16",
  "data": {
    "object": {
      "id": "cs_00000000000000",
      "object": "checkout.session",
      "billing_address_collection": null,
      "cancel_url": "https://example.com/cancel",
      "client_reference_id": null,
      "customer": null,
      "customer_email": null,
      "display_items": [
        {
          "amount": 1500,
          "currency": "usd",
          "custom": {
            "description": "Comfortable cotton t-shirt",
            "images": null,
            "name": "T-shirt"
          },
          "quantity": 2,
          "type": "custom"
        }
      ],
      "livemode": false,
      "locale": null,
      "payment_intent": "pi_00000000000000",
      "payment_method_types": [
        "card"
      ],
      "submit_type": null,
      "subscription": null,
      "success_url": "https://example.com/success"
    }
  }
}

at first I tried with Stripe.Event class as a parameter. 起初,我尝试使用Stripe.Event类作为参数。

[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(Event data);

But all data were with null values. 但是所有数据均为空值。 so, I tried to use my own Model classes according to the json request. 因此,我尝试根据json请求使用自己的Model类。

    public partial class Temperatures
    {
        [DataMember]
        public long Created { get; set; }
        [DataMember]
        public bool Livemode { get; set; }
        [DataMember]
        public string Id { get; set; }
        [DataMember]
        public string Type { get; set; }
        [DataMember]
        public string Object { get; set; }
        [DataMember]
        public object Request { get; set; }
        [DataMember]
        public long PendingWebhooks { get; set; }
        [DataMember]
        public string ApiVersion { get; set; }
        [DataMember]
        public Data Data { get; set; }
    } ...

But none of them received proper data. 但是他们都没有收到适当的数据。

The last thing I tried that receiving with String param like the question I found in stackoverflow but in Java. 我尝试使用String参数进行接收的最后一件事,就像我在stackoverflow但在Java中发现的问题一样。 How to Receive Webhook from Stripe in Java He said he could print data in this way. 如何用Java用Stripe接收Webhook他说他可以用这种方式打印数据。 but I couldn't. 但我做不到

The only way I made it succeed was typing every single params as written in the json request. 我成功的唯一方法是键入json请求中编写的每个单个参数。 I tried both Wrapped and Bare as WebMessageBodyStyle too. 我也尝试了WrappedBare作为WebMessageBodyStyle

[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(long created, bool livemode, string id ...);

Then I can get data properly..but it is too long to do everything like above. 这样我就可以正确获取数据了。.但是做上述所有事情都太长时间了。 How can I receive POST request in an efficient and correct way? 如何有效,正确地接收POST请求? Please refer to the question in Java and Stripe webhook document as well. 请同时参考Java和Stripe webhook文档中的问题。
I just want to read POST request as a String object regardless of the request structure, so that I can parse it. 我只想将POST请求作为String对象读取,而不管请求结构如何,以便我可以解析它。

I have no problem deserializing that example payload when I use the following DataContract classes: 当我使用以下DataContract类时,反序列化该示例有效负载没有问题:

[DataContract]
public class Base 
{
   [DataMember(Name="livemode")]
   public bool Livemode {get;set;}
   [DataMember(Name="object")]
   public string @Object {get;set;}
   [DataMember(Name="id")]
   public string Id {get;set;}
}

[DataContract]
public class Event:Base
{
   [DataMember(Name="created")]
   public long Created {get;set;}   
   [DataMember(Name="type")]
   public string Type {get;set;}
   [DataMember(Name="data")]
   public EventData Data {get;set;}
}

[DataContract]
public class EventData
{
   [DataMember(Name="object")]
   public EventObject EventObject {get;set;}
}

[DataContract]
public class EventObject:Base
{
   [DataMember(Name="display_items")]
   public Item[] DisplayItems {get;set;}
}

[DataContract]
public class Item
{
   [DataMember(Name="amount")]
   public double Amount {get;set;}
   [DataMember(Name="currency")]
   public string Currency {get;set;}
}

I use that DataContract in this Service Contract: 我在此服务合同中使用了该DataContract:

[ServiceContract]
interface IContract 
{
   [OperationContract]
   [WebInvoke(
        Method = "POST",
        BodyStyle = WebMessageBodyStyle.Bare,
        ResponseFormat = WebMessageFormat.Json,
        RequestFormat = WebMessageFormat.Json)]
   string StripeWebhook(Event data); 
}

When I create an implementation for that service: 当我为该服务创建实现时:

public class JsonService:IContract 
{
  public  string StripeWebhook(Event data)
  {  
    data.Dump("rcvd data");
    return "{\"result\":\"success\"}";
  }
}

and feed that into a WebServiceHost: 并将其输入到WebServiceHost中:

// keeps the service running
AutoResetEvent are = new AutoResetEvent(false);

void Start() 
{
  //netsh http add urlacl url=http://+:8000/json user=USERNAME
  using (var serviceHost = new WebServiceHost(typeof(JsonService), new Uri("http://localhost:8000/json")))
  {
      serviceHost.AddServiceEndpoint(typeof(IContract), new WebHttpBinding(), "");
      serviceHost.Open();
      are.WaitOne(); // blocks 
      serviceHost.Close();
  }
}

I can call that service once I started it and POST the JSON to it: 启动该服务并将JSON张贴到该服务后,我可以对其进行调用:

void Main()
{
    new Thread(Start).Start();  
    try {
        var wc = new WebClient();
        wc.Headers.Add("content-type","application/json");
        wc.UploadString("http://localhost:8000/json/Stripewebhook", File.ReadAllText(@"example_json_wcf.json")).Dump("response");
    } catch(WebException e) {
       e.Dump("raw");
       using(var ms = new MemoryStream()) {
           e.Response.GetResponseStream().CopyTo(ms);
           Encoding.UTF8.GetString(ms.ToArray()).Dump("error");
       }
    }
    Console.WriteLine("Now Running. Enter key will stop the service.");
    Console.ReadLine();
    are.Set();
}

This is what my result looks like in LinqPad: 这是我在LinqPad中的结果:

充满数据的POCO类

Keep in mind: 记住:

  • Bare or Wrapped does matter 裸露或包裹真的很重要
  • In (de)serialization casing matters 在(反序列化)套管问题中

If deserialization fails, try to serialize your object tree first and then compare that result with what you actually need. 如果反序列化失败,请尝试首先序列化对象树,然后将该结果与实际需要的进行比较。
Or use one of many JSON to POCO services, for example: http://json2csharp.com/ (I'm not affiliated with that service, it just happened to be the first that popped up in my Google Search) 或使用许多JSON转换为POCO服务之一,例如: http : //json2csharp.com/ (我不隶属于该服务,它恰好是我的Google搜索中第一个弹出的服务)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM