PayPal IPN是否有任何样本

Mar*_*arc 11 c# paypal paypal-ipn asp.net-web-api

我有一个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();
    }
Run Code Online (Sandbox Code Playgroud)

编辑

到目前为止,我有以下代码

        [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;
        }
Run Code Online (Sandbox Code Playgroud)

但对于第3步,我试图将我的模型发布为json,但paypal返回HTML页面而不是VALIDATED或INVALID.我想出我必须使用application/x-www-form-urlencoded它和参数的顺序相同.

如何获取请求URL?

我会使用查询Url并添加&cmd=_notify-validate到它

Mic*_*ala 12

基于已接受的答案,我提出了以下代码实现ASP.NET MVC的IPN侦听器.该解决方案已经部署并且似乎正常运行.

[HttpPost]
public async Task<ActionResult> 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<bool> ValidateIpnAsync(IEnumerable<KeyValuePair<string, string>> 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

让我分享一下我的经验 - 上面的代码到目前为止工作得很好,但突然之间它正在处理一个IPN失败,即responseString == "INVALID".

问题原来是我的帐户设置为使用charset == windows-1252PayPal默认值.但是,FormUrlEncodedContent使用UTF-8进行编码,因此验证失败,因为国家字符如"ř".解决方案是设置charset为UTF-8,可以在Profile>我的销售工具> PayPal按钮语言编码>更多选项中完成,请参阅此SO线程.

  • 惊人的。我对这些情况感到迷失,改变编码是解决我的情况的方法。谢谢。 (2认同)

Mar*_*arc 6

这是我的代码

随意回顾是有问题的

        [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;
        }
Run Code Online (Sandbox Code Playgroud)