如何在 C# WCF 中接收 Stripe api webhook
How to receive Stripe api webhook in C# WCF
我正在尝试接收来自 Stripe 结帐 post 请求的 Webhook。但 Stripe 文档仅显示 ASP.net 的示例代码,而我使用的是 WCF。
https://stripe.com/docs/payments/checkout/fulfillment#webhooks
这里是 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"
}
}
}
起初我尝试使用Stripe.Event class作为参数。
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(Event data);
但是所有数据都是空值。
所以,我尝试根据 json 要求使用自己的模型 classes。
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; }
} ...
但是其中 none 收到了正确的数据。
我最后尝试使用 String 参数接收,就像我在 Whosebug 中发现的问题,但在 Java 中。
How to Receive Webhook from Stripe in Java
他说他可以用这种方式打印数据。但我做不到。
我成功的唯一方法是输入 json 请求中所写的每个参数。我也尝试 Wrapped 和 Bare 作为 WebMessageBodyStyle。
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(long created, bool livemode, string id ...);
然后我可以正常获取数据..但是做上面的一切都太长了。
如何以有效且正确的方式接收 POST 请求?
请参考 Java 和 Stripe webhook 文档中的问题。
我只想将 POST 请求作为字符串对象读取,而不考虑请求结构,以便我可以解析它。
当我使用以下 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;}
}
我在此服务合同中使用该 DataContract:
[ServiceContract]
interface IContract
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string StripeWebhook(Event data);
}
当我为该服务创建实现时:
public class JsonService:IContract
{
public string StripeWebhook(Event data)
{
data.Dump("rcvd data");
return "{\"result\":\"success\"}";
}
}
并将其提供给 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();
}
}
我可以在启动后调用该服务,POST 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();
}
这是我在 LinqPad 中的结果:
切记:
- 裸露或包裹很重要
- 在(反)序列化套管中很重要
如果反序列化失败,请先尝试序列化您的对象树,然后将该结果与您实际需要的结果进行比较。
或者使用许多 JSON 到 POCO 服务中的一个,例如:http://json2csharp.com/(我不隶属于该服务,它恰好是我的 Google 搜索中出现的第一个)
我正在尝试接收来自 Stripe 结帐 post 请求的 Webhook。但 Stripe 文档仅显示 ASP.net 的示例代码,而我使用的是 WCF。 https://stripe.com/docs/payments/checkout/fulfillment#webhooks
这里是 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"
}
}
}
起初我尝试使用Stripe.Event class作为参数。
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(Event data);
但是所有数据都是空值。 所以,我尝试根据 json 要求使用自己的模型 classes。
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; }
} ...
但是其中 none 收到了正确的数据。
我最后尝试使用 String 参数接收,就像我在 Whosebug 中发现的问题,但在 Java 中。 How to Receive Webhook from Stripe in Java 他说他可以用这种方式打印数据。但我做不到。
我成功的唯一方法是输入 json 请求中所写的每个参数。我也尝试 Wrapped 和 Bare 作为 WebMessageBodyStyle。
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void FromStripeCheckoutWrapped(long created, bool livemode, string id ...);
然后我可以正常获取数据..但是做上面的一切都太长了。
如何以有效且正确的方式接收 POST 请求?
请参考 Java 和 Stripe webhook 文档中的问题。
我只想将 POST 请求作为字符串对象读取,而不考虑请求结构,以便我可以解析它。
当我使用以下 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;}
}
我在此服务合同中使用该 DataContract:
[ServiceContract]
interface IContract
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string StripeWebhook(Event data);
}
当我为该服务创建实现时:
public class JsonService:IContract
{
public string StripeWebhook(Event data)
{
data.Dump("rcvd data");
return "{\"result\":\"success\"}";
}
}
并将其提供给 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();
}
}
我可以在启动后调用该服务,POST 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();
}
这是我在 LinqPad 中的结果:
切记:
- 裸露或包裹很重要
- 在(反)序列化套管中很重要
如果反序列化失败,请先尝试序列化您的对象树,然后将该结果与您实际需要的结果进行比较。
或者使用许多 JSON 到 POCO 服务中的一个,例如:http://json2csharp.com/(我不隶属于该服务,它恰好是我的 Google 搜索中出现的第一个)