2
votes

I've been trying to make this thing work since last Friday. I'm working with a C# asp.net 4.5 project, and Paypal example codes only have MVC and .net CORE examples, both of which I'm not familiar that much.

I've done very little MVC programming. So I decided to bite the bullet and I built a separate MVC project and added a controller with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace paypal_ipn.Controllers
{
    public class IPNlistenerController : Controller
    {
        // GET: IPNlistener
        public ActionResult Index()
        {
            return Receive();
        }

        [HttpPost]
        public HttpStatusCodeResult Receive()
        {
            //Store the IPN received from PayPal
            LogRequest(Request);

            //Fire and forget verification task
            Task.Run(() => VerifyTask(Request));

            //Reply back a 200 code
            return new HttpStatusCodeResult(HttpStatusCode.OK);
        }

        private void VerifyTask(HttpRequestBase ipnRequest)
        {
            ShantMailer.SendEmail("[email protected]", "IPN MVC called", "yup");
            var verificationResponse = string.Empty;

            //Post back to either sandbox or live
            string strSandbox = "https://ipnpb.sandbox.paypal.com/cgi-bin/webscr";
            string strLive = "https://ipnpb.paypal.com/cgi-bin/webscr";
            string strRequest= string.Empty;
            try
            {
                var verificationRequest = (HttpWebRequest)WebRequest.Create(strSandbox);
                //Set values for the verification request
                verificationRequest.Method = "POST";
                verificationRequest.ContentType = "application/x-www-form-urlencoded";
                var param = Request.BinaryRead(ipnRequest.ContentLength);
                strRequest = Encoding.ASCII.GetString(param);

                //Add cmd=_notify-validate to the payload
                strRequest = "cmd=_notify-validate&" + strRequest;
                verificationRequest.ContentLength = strRequest.Length;

                //Attach payload to the verification request
                var streamOut = new StreamWriter(verificationRequest.GetRequestStream(), Encoding.ASCII);
                streamOut.Write(strRequest);
                streamOut.Close();

                //Send the request to PayPal and get the response
                var streamIn = new StreamReader(verificationRequest.GetResponse().GetResponseStream());
                verificationResponse = streamIn.ReadToEnd();
                streamIn.Close();

            }
            catch (Exception ex)
            {
                string nvcs = "Name Value Pairs: <br/>";
                try
                {
                    NameValueCollection these_argies = HttpUtility.ParseQueryString(strRequest);
                    foreach (string s in these_argies)
                        foreach (string v in these_argies.GetValues(s))
                            nvcs += s + ": " + v + "<br/>";
                }
                catch { }
                ShantMailer.SendError(ex.Message + "<br/><br/>" + ex.InnerException + "<br/><br/>" + ex.StackTrace + "<br/><br/>" + nvcs + "<br/><br/>Request: " + strRequest + "<br/><br/>Response: " + verificationResponse);

                //Capture exception for manual investigation
            }

            ProcessVerificationResponse(verificationResponse, strRequest);
        }


        private void LogRequest(HttpRequestBase request)
        {
            // Persist the request values into a database or temporary data store
        }

        private void ProcessVerificationResponse(string verificationResponse, string strRequest)
        {
            if (verificationResponse.Equals("VERIFIED"))
            {
                ShantMailer.SendEmail("[email protected]", "IPN", strRequest + " <br><br><br> " + verificationResponse);
                // check that Payment_status=Completed
                // check that Txn_id has not been previously processed
                // check that Receiver_email is your Primary PayPal email
                // check that Payment_amount/Payment_currency are correct
                // process payment
            }
            else if (verificationResponse.Equals("INVALID"))
            {
                ShantMailer.SendEmail("[email protected]", "IPN", strRequest + " <br><br><br> " + verificationResponse);
                //Log for manual investigation
            }
            else
            {
                //Log error
            }
        }
    }
}

My solution explorer looks like this

Now, when I call the page from my browser I see the HttpResponse 200 in the Chrome developer console (Network tab)

And as you see I've even included checkpoints in my code that sends me email notifications for debugging purposes. I'm getting the "IPN MVC Called" email when I load the page myself in the browser. But when I give it to the IPN Simulator, Paypal keeps saying "IPN was not sent, and the handshake was not verified. Review your information."

Paypal is not consistent in their documentation, some pages say use "https://ipnpb.paypal.com/cgi-bin/webscr" and in their code samples it's "https://www.paypal.com/cgi-bin/webscr"

Or for sandbow "https://ipnpb.sandbox.paypal.com/cgi-bin/webscr" vs their code example "https://www.sandbox.paypal.com/cgi-bin/webscr"

In any case, I have tried all possible combinations and still not sure what's wrong.

This is where my listener is hosted: https://www.shantwebdesign.com/paypal_ipn/IPNlistener/Index/

Any help or lead with this is greatly appreciated. Thank you

1

1 Answers

1
votes

Problem solved. Make sure your SSL is on TLS version is 1.2 Paypal says 1.2 or above, I had 1.3 which didn't work. downgrading to 1.2 did the trick