Marc Marc - 1 month ago 17
C# Question

Is there any sample for PayPal IPN

I have an Asp.Net WEB API 2 project and I would like to implement an Instant Payment Notification (IPN) listener controller.

I can't find any example and nuget package. All I need is to acknowledge that the user paid with the standard html button on Paypal. It's quite simple.

All the nuget packages are to create invoice or custom button. It's not what I need

The samples on paypal are for classic asp.net and not for MVC or WEB API MVC

I'm sure somebody did that already and when I started coding I had a feeling that I was reinventing the wheel.

Is there any IPN listener controller example?

At least a PaypalIPNBindingModel to bind the Paypal query.

[Route("IPN")]
[HttpPost]
public IHttpActionResult IPN(PaypalIPNBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest();
}

return Ok();
}


EDIT

So far I have the following code

[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;
}


but for the step 3 I tried to post my model as json but paypal returns a HTML page instead of VALIDATED or INVALID. I figured out that I have to use
application/x-www-form-urlencoded
and it the parameters as to be in the same order.

How can I get the request URL?

I would use the query Url and add
&cmd=_notify-validate
to it

Answer

This is my code

Feel free to review is something is wrong

        [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;
        }
Comments