AspBucket offers ASP.NET, C#, VB, Jquery, CSS, Ajax, SQL tutorials. It is the best place for programmers to learn

Sunday 8 May 2016

How to integrate PayPal express checkout in asp.net application?

In this blog post I will discuss How to integrate PayPal express checkout in asp.net application?  PayPal is third-party payment processors that specialize in online shopping that address scalability and security. Please follow below processes to implement PayPal express checkout.

Step- 1 Create PayPal sandbox account for testing environment.



Step- 2 Add following app setting in your web config file.
  </appSettings>
   <!--Paypal Enviroment Variables-->
    <add key="IsSandbox" value="true" />
    
    <add key="PaypalEndPointURL" value="https://api-3t.paypal.com/nvp" />
    <add key="Paypalhost" value="www.paypal.com" />

    <add key="PaypalEndPointURL_SB" value="https://api-3t.sandbox.paypal.com/nvp" />
    <add key="Paypalhost_SB" value="www.sandbox.paypal.com" />
    
    <add key="PayPalAPIUsername" value="put_value" />
    <add key="PayPalAPIPassword" value="put_value" />
    <add key="PayPalAPISignature" value="put_value" />
    <add key="PayPalBNCode" value="PP-ECWizard" />
    <add key="PayPalTimeout" value="50000"/>
    <add key="PayPalreturnURL" value="put_value"/>
    <add key="PayPalcancelURL" value="put_value"/>

  </appSettings>

Step 3- Create separate class to access these App Settings constants.
 public class AppSettings
    {
       #region--PayPal Settings

        public static bool IsSandbox
        {
            get { return bool.Parse((ConfigurationManager.AppSettings["IsSandbox"] != null ? ConfigurationManager.AppSettings["IsSandbox"].ToString() : "false")); }
        }       

        public static string PaypalEndPointURL
        {
            get { return (ConfigurationManager.AppSettings["PaypalEndPointURL"] != null ? ConfigurationManager.AppSettings["PaypalEndPointURL"].ToString() : ""); }
        }

        public static string Paypalhost
        {
            get { return (ConfigurationManager.AppSettings["Paypalhost"] != null ? ConfigurationManager.AppSettings["Paypalhost"].ToString() : ""); }
        }

        public static string PaypalEndPointURL_SB
        {
            get { return (ConfigurationManager.AppSettings["PaypalEndPointURL_SB"] != null ? ConfigurationManager.AppSettings["PaypalEndPointURL_SB"].ToString() : ""); }
        }

        public static string Paypalhost_SB
        {
            get { return (ConfigurationManager.AppSettings["Paypalhost_SB"] != null ? ConfigurationManager.AppSettings["Paypalhost_SB"].ToString() : ""); }
        }              

        public static string PayPalAPIUsername
        {
            get { return (ConfigurationManager.AppSettings["PayPalAPIUsername"] != null ? ConfigurationManager.AppSettings["PayPalAPIUsername"].ToString() : ""); }
        }

        public static string PayPalAPIPassword
        {
            get { return (ConfigurationManager.AppSettings["PayPalAPIPassword"] != null ? ConfigurationManager.AppSettings["PayPalAPIPassword"].ToString() : ""); }
        }

        public static string PayPalAPISignature
        {
            get { return (ConfigurationManager.AppSettings["PayPalAPISignature"] != null ? ConfigurationManager.AppSettings["PayPalAPISignature"].ToString() : ""); }
        }

        public static string PayPalBNCode
        {
            get { return (ConfigurationManager.AppSettings["PayPalBNCode"] != null ? ConfigurationManager.AppSettings["PayPalBNCode"].ToString() : ""); }
        }

        public static int PayPalTimeout
        {
            get { return int.Parse((ConfigurationManager.AppSettings["PayPalTimeout"] != null ? ConfigurationManager.AppSettings["PayPalTimeout"].ToString() : "-1")); }
        }

        public static string PayPalreturnURL
        {
            get { return (ConfigurationManager.AppSettings["PayPalreturnURL"] != null ? ConfigurationManager.AppSettings["PayPalreturnURL"].ToString() : ""); }
        }

        public static string PayPalcancelURL
        {
            get { return (ConfigurationManager.AppSettings["PayPalcancelURL"] != null ? ConfigurationManager.AppSettings["PayPalcancelURL"].ToString() : ""); }
        }
        #endregion
 }

Step 4- Create "NVPAPICaller" Class for all PayPal functions.
public class NVPAPICaller
{
    #region--Initialization--
    //Flag that determines the PayPal environment (live or sandbox)
    private bool bSandbox = AppSettings.IsSandbox;
    private const string CVV2 = "CVV2"; //AppSettings.CVV2;

    // Live strings.
    private string pEndPointURL = AppSettings.PaypalEndPointURL;
    private string host = AppSettings.Paypalhost;

    // Sandbox strings.
    private string pEndPointURL_SB = AppSettings.PaypalEndPointURL_SB;
    private string host_SB = AppSettings.Paypalhost_SB; //"www.sandbox.paypal.com";

    private const string SIGNATURE = "SIGNATURE";
    private const string PWD = "PWD";
    private const string ACCT = "ACCT";

    //Replace <Your API Username> with your API Username
    //Replace <Your API Password> with your API Password
    //Replace <Your Signature> with your Signature
    public string APIUsername = AppSettings.PayPalAPIUsername;
    private string APIPassword = AppSettings.PayPalAPIPassword;
    private string APISignature = AppSettings.PayPalAPISignature;
    private string Subject = "";
    private string BNCode = AppSettings.PayPalBNCode;


    //HttpWebRequest Timeout specified in milliseconds 
    private int Timeout = AppSettings.PayPalTimeout;
    private static readonly string[] SECURED_NVPS = new string[] { ACCT, CVV2, SIGNATURE, PWD };
    #endregion

    #region--Set Credencials--
    public void SetCredentials(string Userid, string Pwd, string Signature)
    {
        APIUsername = Userid;
        APIPassword = Pwd;
        APISignature = Signature;
    }
    #endregion

    #region--Short cut Express Checkout--
    public bool ShortcutExpressCheckout(string amt,string currency_code, ref string token, ref string retMsg)
    {
        if (bSandbox)
        {
            pEndPointURL = pEndPointURL_SB;
            host = host_SB;
        }

        string returnURL = AppSettings.PayPalreturnURL;
        string cancelURL = AppSettings.PayPalcancelURL;

        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "SetExpressCheckout";
        encoder["RETURNURL"] = returnURL;
        encoder["CANCELURL"] = cancelURL;
        encoder["BRANDNAME"] = "IDeal Feeds Sample Application";
        encoder["PAYMENTREQUEST_0_AMT"] = amt;
        encoder["PAYMENTREQUEST_0_ITEMAMT"] = amt;
        encoder["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
        encoder["PAYMENTREQUEST_0_CURRENCYCODE"] = currency_code;

        // Get the Shopping Cart Products
        //using (WingtipToys.Logic.ShoppingCartActions myCartOrders = new WingtipToys.Logic.ShoppingCartActions())
        //{
        //    List<CartItem> myOrderList = myCartOrders.GetCartItems();

        //    for (int i = 0; i < myOrderList.Count; i++)
        //    {
        //        encoder["L_PAYMENTREQUEST_0_NAME" + i] = myOrderList[i].Product.ProductName.ToString();
        //        encoder["L_PAYMENTREQUEST_0_AMT" + i] = myOrderList[i].Product.UnitPrice.ToString();
        //        encoder["L_PAYMENTREQUEST_0_QTY" + i] = myOrderList[i].Quantity.ToString();
        //    }
        //}

        encoder["L_PAYMENTREQUEST_0_NAME0"] = "IDeal Feed Signup";
        encoder["L_PAYMENTREQUEST_0_AMT0"] = amt;
        encoder["L_PAYMENTREQUEST_0_QTY0"] = "1";
        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);

        NVPCodec decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);

        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
            token = decoder["TOKEN"];
            string ECURL = "https://" + host + "/cgi-bin/webscr?cmd=_express-checkout" + "&token=" + token;
            retMsg = ECURL;
            return true;
        }
        else
        {
            retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
                "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
                "Desc2=" + decoder["L_LONGMESSAGE0"];
            return false;
        }
    }
    #endregion

    #region--Get Check out Details--
    public bool GetCheckoutDetails(string token, ref string PayerID, ref NVPCodec decoder, ref string retMsg)
    {
        if (bSandbox)
        {
            pEndPointURL = pEndPointURL_SB;
        }

        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "GetExpressCheckoutDetails";
        encoder["TOKEN"] = token;

        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);

        decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);

        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
            PayerID = decoder["PAYERID"];
            return true;
        }
        else
        {
            retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
                "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
                "Desc2=" + decoder["L_LONGMESSAGE0"];

            return false;
        }
    }
    #endregion

    #region--Do Checkout Payment--
    public bool DoCheckoutPayment(string finalPaymentAmount,string currency_code, string token, string PayerID, ref NVPCodec decoder, ref string retMsg)
    {
        if (bSandbox)
        {
            pEndPointURL = pEndPointURL_SB;
        }

        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "DoExpressCheckoutPayment";
        encoder["TOKEN"] = token;
        encoder["PAYERID"] = PayerID;
        encoder["PAYMENTREQUEST_0_AMT"] = finalPaymentAmount;
        encoder["PAYMENTREQUEST_0_CURRENCYCODE"] = currency_code;
        encoder["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";

        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);

        decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);

        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
            return true;
        }
        else
        {
            retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
                "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
                "Desc2=" + decoder["L_LONGMESSAGE0"];

            return false;
        }
    }
    #endregion

    #region--HttpCall--
    public string HttpCall(string NvpRequest)
    {
        string url = pEndPointURL;

        string strPost = NvpRequest + "&" + buildCredentialsNVPString();
        strPost = strPost + "&BUTTONSOURCE=" + HttpUtility.UrlEncode(BNCode);
        //No need of shipping
        strPost = strPost + "&NOSHIPPING="+HttpUtility.UrlEncode("1");
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        // Try using Tls11 if it doesnt works for you with Tls
        HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
        objRequest.Timeout = Timeout;
        objRequest.Method = "POST";
        objRequest.ContentLength = strPost.Length;

        try
        {
            using (StreamWriter myWriter = new StreamWriter(objRequest.GetRequestStream()))
            {
                myWriter.Write(strPost);
            }
        }
        catch (Exception)
        {
            // No logging for this tutorial.
        }

        //Retrieve the Response returned from the NVP API call to PayPal.
        HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
        string result;
        using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
        {
            result = sr.ReadToEnd();
        }

        return result;
    }
    #endregion

    #region--build Credentials NVP String--
    private string buildCredentialsNVPString()
    {
        NVPCodec codec = new NVPCodec();

        if (!IsEmpty(APIUsername))
            codec["USER"] = APIUsername;

        if (!IsEmpty(APIPassword))
            codec[PWD] = APIPassword;

        if (!IsEmpty(APISignature))
            codec[SIGNATURE] = APISignature;

        if (!IsEmpty(Subject))
            codec["SUBJECT"] = Subject;

        codec["VERSION"] = "88.0";

        return codec.Encode();
    }

    public static bool IsEmpty(string s)
    {
        return s == null || s.Trim() == string.Empty;
    }
    #endregion
}

public sealed class NVPCodec : NameValueCollection
{
    private const string AMPERSAND = "&";
    private const string EQUALS = "=";
    private static readonly char[] AMPERSAND_CHAR_ARRAY = AMPERSAND.ToCharArray();
    private static readonly char[] EQUALS_CHAR_ARRAY = EQUALS.ToCharArray();

    public string Encode()
    {
        StringBuilder sb = new StringBuilder();
        bool firstPair = true;
        foreach (string kv in AllKeys)
        {
            string name = HttpUtility.UrlEncode(kv);
            string value = HttpUtility.UrlEncode(this[kv]);
            if (!firstPair)
            {
                sb.Append(AMPERSAND);
            }
            sb.Append(name).Append(EQUALS).Append(value);
            firstPair = false;
        }
        return sb.ToString();
    }

    public void Decode(string nvpstring)
    {
        Clear();
        foreach (string nvp in nvpstring.Split(AMPERSAND_CHAR_ARRAY))
        {
            string[] tokens = nvp.Split(EQUALS_CHAR_ARRAY);
            if (tokens.Length >= 2)
            {
                string name = HttpUtility.UrlDecode(tokens[0]);
                string value = HttpUtility.UrlDecode(tokens[1]);
                Add(name, value);
            }
        }
    }

    public void Add(string name, string value, int index)
    {
        this.Add(GetArrayName(index, name), value);
    }

    public void Remove(string arrayName, int index)
    {
        this.Remove(GetArrayName(index, arrayName));
    }

    public string this[string name, int index]
    {
        get
        {
            return this[GetArrayName(index, name)];
        }
        set
        {
            this[GetArrayName(index, name)] = value;
        }
    }

    private static string GetArrayName(int index, string name)
    {
        if (index < 0)
        {
            throw new ArgumentOutOfRangeException("index", "index cannot be negative : " + index);
        }
        return name + index;
    }
}

Step 5- Create "Checkout" Folder

Step 6- Create following pages inside "Checkout" Folder
CheckoutCancel.aspx
CheckoutComplete.aspx
CheckoutError.aspx
CheckoutStart.aspx

Step 7- Create "CheckOutSummary.aspx" page
Add Image button for expess-checkout


                    <div id="paypalpay" style="display: none;">
                        <div class="form-group">
                            <div class="col-sm-offset-2 col-md-6">
                                <asp:ImageButton ID="btnCheckout" runat="server" ImageUrl="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif"
                                    Width="145" AlternateText="Check out with PayPal"
                                    BackColor="Transparent" BorderWidth="0" OnClick="btnCheckout_Click" />
                            </div>
                        </div>
                    </div>

Button click code
    protected void btnCheckout_Click(object sender, ImageClickEventArgs e)
    {        
            Session["payment_amt"] = "20";
            Session["currency_code"] = "USD"; 
            Response.Redirect("~/Checkout/CheckoutStart.aspx");       

    }

Step 8- Implement Other Pages


(i-) CheckoutStart.aspx (.cs page)
    protected void Page_Load(object sender, EventArgs e)
    {
        NVPAPICaller payPalCaller = new NVPAPICaller();
        string retMsg = "";
        string token = "";

        if ((Session["payment_amt"] != null) && (Session["currency_code"]!=null))
        {
            string amt = Session["payment_amt"].ToString();
            string currency_code= Session["currency_code"].ToString();
            bool ret = payPalCaller.ShortcutExpressCheckout(amt,currency_code, ref token, ref retMsg);
            if (ret)
            {
                Session["token"] = token;
                Response.Redirect(retMsg);
            }
            else
            {
                Response.Redirect("CheckoutError.aspx?" + retMsg);
            }
        }
        else
        {
            Response.Redirect("CheckoutError.aspx?ErrorCode=AmtMissing");
        }
    }

(ii-)CheckoutComplete.aspx page
 <div class="container main">
        <h1><span>Checkout Complete</span></h1>
        <div role="form" class="form-horizontal">
            <div class="form-group">
                <div class="col-md-2">
                    <label class="control-label">Payment Transaction ID:</label>
                </div>
                <div class="col-md-6">
                    <label class="control-label">
                        <asp:Label ID="TransactionId" CssClass="control-label" runat="server"></asp:Label>
                    </label>
                </div>
            </div>
        </div>
        <h3>Thank You!</h3>
        <div class="col-sm-2">
            <asp:LinkButton ID="lnkRedirectToDashBoard" CssClass="btn btn-primary btn-block" PostBackUrl="~/account/dashboard" runat="server">Go To DashBoard</asp:LinkButton>
        </div>
    </div>
.cs Page
 #region--Page Load--
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            VerifyPayment();
        }
    }
    #endregion
    
    #region--Verify Payment--
    public void VerifyPayment()
    {
        NVPAPICaller payPalCaller = new NVPAPICaller();
        string retMsg = "";
        string token = "";
        string PayerID = "";
        NVPCodec decoder = new NVPCodec();
        token = Session["token"].ToString();
        string currency_code = Session["currency_code"].ToString();
        bool ret = payPalCaller.GetCheckoutDetails(token, ref PayerID, ref decoder, ref retMsg);
        if (ret)
        {
            // Verify total payment amount as set on CheckoutStart.aspx.
            try
            {
                decimal paymentAmountOnCheckout = Convert.ToDecimal(Session["payment_amt"].ToString());
                decimal paymentAmoutFromPayPal = Convert.ToDecimal(decoder["AMT"].ToString());
                if (paymentAmountOnCheckout != paymentAmoutFromPayPal)
                {
                    Response.Redirect("CheckoutError.aspx?" + "Desc=Amount%20total%20mismatch.");
                }
            }
            catch (Exception)
            {
                Response.Redirect("CheckoutError.aspx?" + "Desc=Amount%20total%20mismatch.");
            }

        }
        string finalPaymentAmount = Session["payment_amt"].ToString();
        bool res = payPalCaller.DoCheckoutPayment(finalPaymentAmount, currency_code, token, PayerID, ref decoder, ref retMsg);
        if (res)
        {
            // Retrieve PayPal confirmation value.
            string PaymentConfirmation = decoder["PAYMENTINFO_0_TRANSACTIONID"].ToString();
            TransactionId.Text = PaymentConfirmation;
           
        }
        else
        {
            Response.Redirect("CheckoutError.aspx?" + retMsg);
        }
    }
    #endregion

(iii-) CheckoutError.aspx Page

<div id="Errorcode" class="text-danger">        
  Error Code:<%=Request.QueryString.Get("ErrorCode")%><br/>
  <%=Request.QueryString.Get("Desc")%><br/>
  <%=Request.QueryString.Get("Desc2")%>            
</div>

(iv-)CheckoutCancel.aspx
<div class="container main">
        <h1><span>Checkout Cancelled</span></h1>
        <div id="DivMsg" runat="server">
        </div>     
        <h3>Your payment has been canceled.</h3>
    </div>
That's it Initially CheckoutSummary.aspx page will execute & Session Variables are set for checkout execution.

   4 comments :

  1. This is good example, I wish you had uploaded Code as well as screenshot for the same. Very good example

    ReplyDelete
  2. Whats a subscription plans class for in the checkout summary cs file?

    ReplyDelete
  3. i am not getting SubscriptionPlans class anywhere in your code snippet.

    ReplyDelete
    Replies
    1. The SubscriptionPlans class is used for getting the product details. You can ignore that or you need to implement the logic for getting the product details.
      I have updated the above source code with dummy product details.

      Delete

  • Popular Posts
  • Comments