0

I am implementing CoinPayments IPN in my application and I have trouble with passing data to the method that take their Callback. I have tried like everything I could find: TempData, SessionVariables, tried to implement it somewhere in forms and maybe Request it but that didn`t work for me. So I also tried to implement it with Global static variables. And it worked! But then came another issue: if more than one user were to buy something from website at the same time or even in between any callbacks their data will get mixed. So here I am, trying again to make Session Variables work and have no clue why they are not working as I used them before. Probably what I can think of is that because its a callback from CoinPayments and I handle something wrongly.

Here is the code I have right now: Tho I tried different variations like implementing Session in Get Payment method. Now I ended up with it and it still comes out as null in POST METHOD.

Class for handling Session Variables:

 public static class MyGlobalVariables
    {
        public static int TokenChoice
        {
            get
            {
                if (System.Web.HttpContext.Current.Session["TokenChoice"] == null)
                {
                    return -1;
                }
                else
                {
                    return (int)System.Web.HttpContext.Current.Session["TokenChoice"];
                }
            }
            set
            {
                System.Web.HttpContext.Current.Session["TokenChoice"] = value;
            }
        }
        public static int PaymentChoice
        {
            get
            {
                if (System.Web.HttpContext.Current.Session["PaymentChoice"] == null)
                {
                    return -1;
                }
                else
                {
                    return (int)System.Web.HttpContext.Current.Session["PaymentChoice"];
                }
            }
            set
            {
                System.Web.HttpContext.Current.Session["PaymentChoice"] = value;
            }
        }
        public static string CurrentUser
        {
            get
            {
                System.Web.HttpContext.Current.Session["CurrentUser"] = System.Web.HttpContext.Current.User.Identity.Name;
                return (string)System.Web.HttpContext.Current.Session["CurrentUser"];
            }
        }

    }

Class that returns view where you click on CoinPayments button:

 public ActionResult Payment(int tokenChoice, int paymentChoice)
    {

        ViewBag.Payment = paymentChoice;
        MyGlobalVariables.PaymentChoice = paymentChoice;
        MyGlobalVariables.TokenChoice = tokenChoice;

        return View();
    }

Callback class that handles Callback from CoinPayments:

  [HttpPost]
    public ActionResult Payment()
    {
        NameValueCollection nvc = Request.Form;


        var merchant_id = id;
            var ipn_secret = secret;
        var order_total = MyGlobalVariables.PaymentChoice;

            if (String.IsNullOrEmpty(nvc["ipn_mode"]) || nvc["ipn_mode"] != "hmac")
            {
                Trace.WriteLine("IPN Mode is not HMAC");
                return View();
            }

            if (String.IsNullOrEmpty(HTTP_HMAC))
            {
                Trace.WriteLine("No HMAC signature sent");
                return View();
            }

            if (String.IsNullOrEmpty(nvc["merchant"]) || nvc["merchant"] != merchant_id.Trim())
            {
                Trace.WriteLine("No or incorrect Merchant ID passed");
                return View();
            }

            //var hmac = hash_hmac("sha512", request, ipn_secret.Trim());

            var txn_id = nvc["txn_id"]; 
            var item_name = nvc["item_name"]; 
            var item_number = nvc["item_number"];
            var amount1 = nvc["amount1"];
            var amount2 = float.Parse(nvc["amount2"], CultureInfo.InvariantCulture.NumberFormat);
            var currency1 = nvc["currency1"];
            var currency2 = nvc["currency2"];
            var status = Convert.ToInt32(nvc["status"]);
            var status_text = nvc["status_text"];
            Trace.WriteLine(status);
            if (currency1 != "USD") {
                Trace.WriteLine("Original currency mismatch!");
                return View();
            }

        if (Convert.ToInt32(amount1) < Convert.ToInt32(order_total))
        {
            Trace.WriteLine("Amount is less than order total!");
            return View();
        }

        if (status >= 100 || status == 2) {

                using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
                {
                var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
                if (account != null && account.Paid == 0)
                {
                    Trace.WriteLine("Payment Completed");
                    Trace.WriteLine("Tokens to add: " + MyGlobalVariables.TokenChoice);
                    account.Tokens += MyGlobalVariables.TokenChoice;
                    account.Paid = 1;
                    dc.Configuration.ValidateOnSaveEnabled = false;
                    dc.SaveChanges();
                }
                }
              } else if (status < 0)
            {
                Trace.WriteLine(
                    "payment error, this is usually final but payments will sometimes be reopened if there was no exchange rate conversion or with seller consent");
            } else {
            using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
            {
                var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
                if (account != null)
                {
                    account.Paid = 0;
                    dc.Configuration.ValidateOnSaveEnabled = false;
                    dc.SaveChanges();
                }
            }
            Trace.WriteLine("Payment is pending");
            }

        return View();
    }

As you can see there are only 3 variables I need to handle. Also someone might ask why I use Session Variable for Current.User? Well for some reason Callback method can not read Current.User as it return null. And well... nothing really changed as for now.

If you have ever experienced something like that or can find an issue I would be so thankful since I wasted already over 2 days on that issue.

EDIT: After some testing I found out variables works fine if I run Post method on my own. So the problem is with handling callback from CoinPayments. Is there a specific way to deal with this?

wowkin2
  • 5,895
  • 5
  • 23
  • 66
D.Weltrowski
  • 321
  • 1
  • 4
  • 15
  • 1
    Isn't the callback a web request initiated by the third-party provider? Why would that contain session data from the user who initiated the original request? Save the data to a database with a key that will let you correlate the callback to the original request. Maybe I'm not understanding something (I didn't look at all of your code and I'm not really familiar with the provider you're using), but if I've caught the gist correctly, this is the problem. – ErikE Sep 25 '18 at 23:51
  • Yea that is a good point. Thanks for that. Do You have any idea for a key to be used here. Since I can not get any data in this Callback I somehow need to get a way to get data from this table where I will store informations. – D.Weltrowski Sep 26 '18 at 00:02
  • I’d be shocked if the provider didn’t let you pass in a value or token that it presents on post-back so you can correlate to the original request. Or, when you initiate the call, it provides you with its own request ID. Either one will work. Look into those two options. – ErikE Sep 26 '18 at 00:57

0 Answers0