PayPal IPN是否有任何样本
我有一个Asp.Net WEB API 2项目,我想实现一个即时支付通知(IPN)监听器控制器。
我找不到任何示例和nuget包。 我只需要承认用户使用Paypal上的标准html按钮付款。 这很简单。
所有nuget包都是创建发票或自定义按钮。 这不是我需要的
paypal上的示例适用于经典的asp.net,而不适用于MVC或WEB API MVC
我肯定有人已经这样做了,当我开始编码时,我感觉我正在重新发明轮子。
是否有任何IPN侦听器控制器示例?
至少一个PaypalIPNBindingModel绑定Paypal查询。
[Route("IPN")] [HttpPost] public IHttpActionResult IPN(PaypalIPNBindingModel model) { if (!ModelState.IsValid) { return BadRequest(); } return Ok(); }
编辑
到目前为止,我有以下代码
[Route("IPN")] [HttpPost] public void IPN(PaypalIPNBindingModel model) { if (!ModelState.IsValid) { // if you want to use the PayPal sandbox change this from false to true string response = GetPayPalResponse(model, true); if (response == "VERIFIED") { } } } string GetPayPalResponse(PaypalIPNBindingModel model, bool useSandbox) { string responseState = "INVALID"; // Parse the variables // Choose whether to use sandbox or live environment string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/" : "https://www.paypal.com/"; using (var client = new HttpClient()) { client.BaseAddress = new Uri(paypalUrl); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded")); //STEP 2 in the paypal protocol //Send HTTP CODE 200 HttpResponseMessage response = client.PostAsJsonAsync("cgi-bin/webscr", "").Result; if (response.IsSuccessStatusCode) { //STEP 3 //Send the paypal request back with _notify-validate model.cmd = "_notify-validate"; response = client.PostAsync("cgi-bin/webscr", THE RAW PAYPAL REQUEST in THE SAME ORDER ).Result; if(response.IsSuccessStatusCode) { responseState = response.Content.ReadAsStringAsync().Result; } } } return responseState; }
但对于第3步,我尝试将我的模型发布为json,但paypal返回HTML页面而不是VALIDATED或INVALID。 我发现我必须使用application/x-www-form-urlencoded
,并且参数的顺序相同。
如何获取请求URL?
我会使用查询Url并向其添加&cmd=_notify-validate
基于已接受的答案,我想出了以下代码实现ASP.NET MVC的IPN监听器。 该解决方案已经部署并且似乎正常工作。
[HttpPost] public async Task Ipn() { var ipn = Request.Form.AllKeys.ToDictionary(k => k, k => Request[k]); ipn.Add("cmd", "_notify-validate"); var isIpnValid = await ValidateIpnAsync(ipn); if (isIpnValid) { // process the IPN } return new EmptyResult(); } private static async Task ValidateIpnAsync(IEnumerable> ipn) { using (var client = new HttpClient()) { const string PayPalUrl = "https://www.paypal.com/cgi-bin/webscr"; // This is necessary in order for PayPal to not resend the IPN. await client.PostAsync(PayPalUrl, new StringContent(string.Empty)); var response = await client.PostAsync(PayPalUrl, new FormUrlEncodedContent(ipn)); var responseString = await response.Content.ReadAsStringAsync(); return (responseString == "VERIFIED"); } }
编辑:
让我分享一下我的经验 – 上面的代码到目前为止工作得很好,但突然之间它正在处理一个IPN失败,即responseString == "INVALID"
。
问题原来是我的帐户设置为使用charset == windows-1252
,这是PayPal的默认值。 但是, FormUrlEncodedContent
使用UTF-8进行编码,因此validation失败,因为国家字符如“ř”。 解决方案是将charset
设置为UTF-8,可以在Profile>我的销售工具> PayPal按钮语言编码>更多选项中完成,请参阅此SO线程 。
这是我的代码
随意回顾是有问题的
[Route("IPN")] [HttpPost] public IHttpActionResult IPN() { // if you want to use the PayPal sandbox change this from false to true string response = GetPayPalResponse(true); if (response == "VERIFIED") { //Database stuff } else { return BadRequest(); } return Ok(); } string GetPayPalResponse(bool useSandbox) { string responseState = "INVALID"; // Parse the variables // Choose whether to use sandbox or live environment string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/" : "https://www.paypal.com/"; using (var client = new HttpClient()) { client.BaseAddress = new Uri(paypalUrl); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded")); //STEP 2 in the paypal protocol //Send HTTP CODE 200 HttpResponseMessage response = client.PostAsJsonAsync("cgi-bin/webscr", "").Result; if (response.IsSuccessStatusCode) { //STEP 3 //Send the paypal request back with _notify-validate string rawRequest = response.Content.ReadAsStringAsync().Result; rawRequest += "&cmd=_notify-validate"; HttpContent content = new StringContent(rawRequest); response = client.PostAsync("cgi-bin/webscr", content).Result; if(response.IsSuccessStatusCode) { responseState = response.Content.ReadAsStringAsync().Result; } } } return responseState; }
扩展Michal Hosala的答案 ,与PayPal成功握手需要两件事
首先,在向PayPal发出请求之前设置安全协议
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
其次,避免使用字典,因为要进行validation,PayPal要求数据以相同的顺序发回,并以cmd变量开头。 我最终这样做了
Request.InputStream.Seek(0, SeekOrigin.Begin); string rawRequestBody = new StreamReader(Request.InputStream).ReadToEnd(); var ipnVarsWithCmd = rawRequestBody.Split('&').Select(x => new KeyValuePair(x.Split('=')[0], x.Split('=')[1])).ToList(); ipnVarsWithCmd.Insert(0, new KeyValuePair("cmd", "_notify-validate"));
我也在寻找类似于OP的原始问题的解决方案Is there any IPN listener controller example? At least a PaypalIPNBindingModel to bind the Paypal query.
Is there any IPN listener controller example? At least a PaypalIPNBindingModel to bind the Paypal query.
我到了这个页面。 我尝试了这个线程中提到的其他解决方案,他们都工作但我真的需要PayPal查询到模型解决方案,所以我谷歌搜索,直到我偶然发现Carlos Rodriguez的创建PayPal IPN Web API端点博客。
以下是卡洛斯所做的概述:
-
创建一个模型。 根据您从PayPal获得的ipn响应,在模型中定义属性。
public class IPNBindingModel { public string PaymentStatus { get; set; } public string RawRequest { get; set; } public string CustomField { get; set; } }
-
创建一个PayPal Validator类。
public class PayPalValidator { public bool ValidateIPN(string body) { var paypalResponse = GetPayPalResponse(true, body); return paypalResponse.Equals("VERIFIED"); } private string GetPayPalResponse(bool useSandbox, string rawRequest) { string responseState = "INVALID"; string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/" : "https://www.paypal.com/"; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; using (var client = new HttpClient()) { client.BaseAddress = new Uri(paypalUrl); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded")); HttpResponseMessage response = client.PostAsJsonAsync("cgi-bin/webscr", "").Result; if (response.IsSuccessStatusCode) { rawRequest += "&cmd=_notify-validate"; HttpContent content = new StringContent(rawRequest); response = client.PostAsync("cgi-bin/webscr", content).Result; if (response.IsSuccessStatusCode) { responseState = response.Content.ReadAsStringAsync().Result; } } } return responseState; } }
-
创建你的控制器。
[RoutePrefix("paypal")] public class PayPalController : ApiController { private PayPalValidator _validator; public PayPalController() { this._validator = new PayPalValidator(); } [HttpPost] [Route("ipn")] public void ReceiveIPN(IPNBindingModel model) { if (!_validator.ValidateIPN(model.RawRequest)) throw new Exception("Error validating payment"); switch (model.PaymentStatus) { case "Completed": //Business Logic break; } } }
-
创建一个模型绑定器,用于定义Web Api将如何自动为您创建模型。
public class IPNModelBinder : IModelBinder { public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { if (bindingContext.ModelType != typeof(IPNBindingModel)) { return false; } var postedRaw = actionContext.Request.Content.ReadAsStringAsync().Result; Dictionary postedData = ParsePaypalIPN(postedRaw); IPNBindingModel ipn = new IPNBindingModel { PaymentStatus = postedData["payment_status"], RawRequest = postedRaw, CustomField = postedData["custom"] }; bindingContext.Model = ipn; return true; } private Dictionary ParsePaypalIPN(string postedRaw) { var result = new Dictionary(); var keyValuePairs = postedRaw.Split('&'); foreach (var kvp in keyValuePairs) { var keyvalue = kvp.Split('='); var key = keyvalue[0]; var value = keyvalue[1]; result.Add(key, value); } return result; } } }
-
将模型绑定器注册到WebApiConfig.cs。
config.BindParameter(typeof(IPNBindingModel), new IPNModelBinder());
希望这有助于其他人。 谢谢Carlos Rodriguez的惊人代码。
这里有一个官方的c#示例: https : //github.com/paypal/ipn-code-samples in path c#paypal_ipn_mvc.cs
C#示例显示了一个ASP.NET MVC控制器,其中包含响应IPN的操作。
上述就是C#学习教程:PayPal IPN是否有任何样本分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/942746.html