ICICI Payment Gateway Integration in ASP.NET C#
Introduction
The purpose of this article is to show how payments processing can be organized to support reliability and security. The article is also aimed at providing you with an example of the development of a simple online payment, in order to demonstrate interaction with the First Data Payment Gateway system. You can use the code in your applications to organize interaction with this system and to process payments. The article is based on the experience of Drake Software Services and the official ICICI Payment Gateway documentation.
Payment Process
The payment process is very simple. A POST form is created with a set of hidden fields that contain information about storename(your merchant-id), currency, chargetotal(amount), language and a button to send the form. When the form is sent, the buyer goes to the First Data ICICI Merchant Services site and finishes the payment process.
Using the Code
A code of the simplest form in request.aspx
<form method="post" runat="server"> <div> <label>Name<span class="text-red">*</span> </label> <div> <asp:TextBox id="Name" runat="server" name="billing_name" type="text"/> </div> </div> <div> <label>Mobile No<span class="text-red">*</span> </label> <div> <asp:TextBox runat="server" ID="MobileNo" name="billing_tel" type="number"/> </div> </div> <div> <label>Email ID<span class="text-red">*</span></label> <div> <asp:TextBox ID="EmailID" name="billing_email" type="email" runat="server" /> </div> </div> <div> <label>Address <span class="text-red">*</span></label> <div> <asp:TextBox TextMode="multiline" runat="server" ID="Address" name="billing_address" Rows="2" /> </div> </div> <div> <label>Zip code <span class="text-red">*</span></label> <div> <asp:TextBox runat="server" ID="ZipCode" name="billing_zip"/> </div> </div> <div> <label>Country <span class="text-red">*</span></label> <div> <asp:TextBox runat="server" ID="Country" name="billing_city" type="text" /> </div> </div> <div> <label>State <span class="text-red">*</span></label> <div> <asp:TextBox runat="server" ID="State" name="billing_city" type="text" /> </div> </div> <div> <label>City <span class="text-red">*</span></label> <div> <asp:TextBox runat="server" ID="City" name="billing_city" type="text" /> </div> </div> <div> <label>Amount<span class="text-red">*</span> </label> <div> <asp:TextBox runat="server" ID="chargetotal" name="amount" type="number" /> </div> </div> <div> <label>Currency <span class="text-red">*</span> </label> <div> <asp:DropDownList runat="server" name="CurrencyId" ID="currencycode" > <asp:ListItem ></asp:ListItem> <asp:ListItem Value="896">GBP</asp:ListItem> <asp:ListItem Value="356">INR</asp:ListItem> </asp:DropDownList> </div> </div> <div> <div> <input ID="btnSend" runat="server" Text="Submit" onclick="btnSend_Click"> </div> </div> </form> <asp:Literal ID="ltrForm" runat="server" Mode="PassThrough"></asp:Literal> <asp:Literal ID="ltrScript" runat="server" Mode="PassThrough"></asp:Literal>
C# Code
Sending request to server in request.aspx.cs
protected void btnSend_Click(object sender, EventArgs e) { Session["name"] = Name.Text; Session["mobileno"] = MobileNo.Text; Session["emailid"] = EmailID.Text; Session["address"] = Address.Text; Session["zipcode"] = ZipCode.Text; Session["city"] = City.Text; Session["state"] = State.text; Session["country"] = Country.Text; Session["chargetotal"] = chargetotal.Text; Session["remarks"] = Remarks.Text; Session["currencycode"] = currencycode.SelectedValue; //values stored in session to save/show it later. string formCode = "<form id=\"{0}\" name=\"{0}\" method=\"post\" action=\"{1}\">" + "<input type=\"hidden\" name=\"txntype\" value=\"sale\">" + "<input type=\"hidden\" name=\"timezone\" value=\"IST\"/>" + "<input type=\"hidden\" name=\"txndatetime\" value=\"{2}\"/>" + "<input type=\"hidden\" name=\"hash\" value=\"{3}\"/>" + "<input type=\"hidden\" name=\"storename\" value=\"{4}\" />" + "<input type=\"hidden\" name=\"mode\" value=\"payonly\"/>" + "<input type=\"hidden\" name=\"currency\" value=\"{5}\" />" + "<input type=\"hidden\" name=\"chargetotal\" value=\"{6}\"/>" + "<input type=\"hidden\" name=\"language\" value=\"en_EN\"/>" + "<input type=\"hidden\" name=\"authenticateTransaction\" value=\"true\"/>" + "<input type=\"hidden\" name=\"responseFailURL\" value=\"http://192.168.xx.x:80/projectname/response_fail.aspx\"/>" + //need to change as per merchant ip/url "<input type=\"hidden\" name=\"responseSuccessURL\" value=\"http://192.168.xx.x:80/projectname/response_success.aspx\"/>" + //need to change as per merchant ip/url "</form>"; string formScript = "<script language=\"javascript\" type=\"text/javascript\">" + "document.getElementById('{0}').submit();" + "</script>"; string formName = "form1"; string formAction = "https://www4.ipg-online.com/connect/gateway/processing"; string storename = this.storename.Text; string txndatetime = DateTime.Now.ToString(@"yyyy\:MM\:dd-HH\:mm\:ss"); string chargetotal = this.chargetotal.Text; string sharedsecret = "your shared secret value" string currency = this.currency.SelectedValue.ToString(); string data = storename + txndatetime + chargetotal + currency + sharedsecret; string hash = calculateHashFromString(new StringBuilder(data), "SHA1"); ltrForm.Text = string.Format(formCode, formName, formAction, txndatetime, hash, storename, currency, chargetotal); ltrScript.Text = string.Format(formScript, formName); }
When the form is submitted, all the hidden set of hidden fields that contain information about storename(unique merchant-id), currency, chargetotal(amount),language, responseFailURL, responseSuccessURL are concatenated in a string formCode
. Here formAction
is where the user is redirected to the payment gateway to complete the transaction process, Where in storename you have to insert your unique merchant-id.
Similarly, In sharedsecret you have to enter your unique sharedsecret value which will be provided by the merchant. On form submission the literals i.e. ltrForm.Text
and ltrScript.Text
will send the encrypted request via using hash code to the server and user will be redirected to the https://www4.ipg-online.com/connect/gateway/processing.
Description of Parameters-
Parameter | Description |
---|---|
txntype | Indicates the type of transaction, such as sale or refund. |
timezone | It refers to the local time of a region or a country. |
txndatetime | Time and date of transaction. |
hash | A unique value of fixed size representing a large amount of data. |
storename | Your unique merchant-id. |
mode | Item identifier. |
currency | Payment currency. Eg- INR/CAD/USD. |
chargetotal | Order amount. |
responseFailURL | URL provided when transaction fails. |
responseSuccessURL | URL provided when transaction succeeds. |
sharedsecret | Unique value given with the storename/merchant-id. |
Above table lists the most frequently used parameters. See the Response in response.aspx.cs
for the full list of parameters.
Cryptographic hash function
Here function calculateHashFromString
uses cryptographic hash function to encrypt the data values. A cryptographic hash function has the property that it is computationally infeasible to find two distinct inputs that hash to the same value. Hash
functions are commonly used with digital signatures and for data integrity.
The hash is used as a unique value of fixed size representing a large amount of data. Hashes of two sets of data should match if the corresponding data also matches. Small changes to the data result in large unpredictable changes in the hash.
public static String calculateHashFromString(StringBuilder stringValue, String hashAlgorithmName) { HashAlgorithm hashAlgorithm = HashAlgorithm.Create(hashAlgorithmName.Length == 0 ? "SHA1" : hashAlgorithmName); StringBuilder sb = new StringBuilder(); byte[] stringValueBytes = Encoding.ASCII.GetBytes(stringValue.ToString()); int stringValueBytesLength = stringValueBytes.Length; for (int i = 0; i < stringValueBytesLength; i++) { sb.Append(forDigit((stringValueBytes[i] & 240) >> 4, 16)); sb.Append(forDigit((stringValueBytes[i] & 15), 16)); } stringValueBytes = Encoding.ASCII.GetBytes((new StringBuilder(sb.ToString()).ToString())); hashAlgorithm.TransformFinalBlock(stringValueBytes, 0, stringValueBytes.Length); byte[] hash = hashAlgorithm.Hash; int hashLength = hash.Length; return BitConverter.ToString(hash).Replace("-", "").ToLower(); } private static char forDigit(int digit, int radix) { int MIN_RADIX = 2, MAX_RADIX = 36; if ((digit >= radix) || (digit < 0)) { return 'public static String calculateHashFromString(StringBuilder stringValue, String hashAlgorithmName) { HashAlgorithm hashAlgorithm = HashAlgorithm.Create(hashAlgorithmName.Length == 0 ? "SHA1" : hashAlgorithmName); StringBuilder sb = new StringBuilder(); byte[] stringValueBytes = Encoding.ASCII.GetBytes(stringValue.ToString()); int stringValueBytesLength = stringValueBytes.Length; for (int i = 0; i < stringValueBytesLength; i++) { sb.Append(forDigit((stringValueBytes[i] & 240) >> 4, 16)); sb.Append(forDigit((stringValueBytes[i] & 15), 16)); } stringValueBytes = Encoding.ASCII.GetBytes((new StringBuilder(sb.ToString()).ToString())); hashAlgorithm.TransformFinalBlock(stringValueBytes, 0, stringValueBytes.Length); byte[] hash = hashAlgorithm.Hash; int hashLength = hash.Length; return BitConverter.ToString(hash).Replace("-", "").ToLower(); } private static char forDigit(int digit, int radix) { int MIN_RADIX = 2, MAX_RADIX = 36; if ((digit >= radix) || (digit < 0)) { return '\0'; } if ((radix < MIN_RADIX) || (radix > MAX_RADIX)) { return '\0'; } if (digit < 10) { return (char)('0' + digit); } return (char)('a' - 10 + digit); }'; } if ((radix < MIN_RADIX) || (radix > MAX_RADIX)) { return 'public static String calculateHashFromString(StringBuilder stringValue, String hashAlgorithmName) { HashAlgorithm hashAlgorithm = HashAlgorithm.Create(hashAlgorithmName.Length == 0 ? "SHA1" : hashAlgorithmName); StringBuilder sb = new StringBuilder(); byte[] stringValueBytes = Encoding.ASCII.GetBytes(stringValue.ToString()); int stringValueBytesLength = stringValueBytes.Length; for (int i = 0; i < stringValueBytesLength; i++) { sb.Append(forDigit((stringValueBytes[i] & 240) >> 4, 16)); sb.Append(forDigit((stringValueBytes[i] & 15), 16)); } stringValueBytes = Encoding.ASCII.GetBytes((new StringBuilder(sb.ToString()).ToString())); hashAlgorithm.TransformFinalBlock(stringValueBytes, 0, stringValueBytes.Length); byte[] hash = hashAlgorithm.Hash; int hashLength = hash.Length; return BitConverter.ToString(hash).Replace("-", "").ToLower(); } private static char forDigit(int digit, int radix) { int MIN_RADIX = 2, MAX_RADIX = 36; if ((digit >= radix) || (digit < 0)) { return '\0'; } if ((radix < MIN_RADIX) || (radix > MAX_RADIX)) { return '\0'; } if (digit < 10) { return (char)('0' + digit); } return (char)('a' - 10 + digit); }'; } if (digit < 10) { return (char)('0' + digit); } return (char)('a' - 10 + digit); }
Reponse From Server
To store/show information about responses to payment requests, we use the reponse.aspx.cs
file having the following structure:
protected void Page_Load(object sender, EventArgs e)
{
try
{
ResponseModel obj = new ResponseModel();
obj.tId = Request.Form["ipgTransactionId"];
obj.approvalCode = Request.Form["approval_code"];
obj.txndateprocessed = Request.Form["txndate_processed"];
obj.timezone = Request.Form["timezone"];
obj.responsehash = Request.Form["response_hash"];
obj.failrc = Request.Form["fail_rc"];
obj.orderId = Request.Form["oid"];
obj.date = Request.Form["tdate"];
obj.installmentsinterest = Request.Form["installments_interest"];
obj.cccountry = Request.Form["cccountry"];
obj.ccbrand = Request.Form["ccbrand"];
sId.Text = obj.status = Request.Form["status"];
obj.name = billing_name.Text = Session["name"].ToString();
obj.tel = billing_tel.Text = Session["mobileno"].ToString();
obj.email = billing_email.Text = Session["emailid"].ToString();
obj.address = billing_address.Text = Session["address"].ToString();
billing_zip.Text = Session["zipcode"].ToString();
obj.zip = billing_zip.Text;
obj.city = billing_city.Text = Session["city"].ToString();
obj.state = billing_state.Text = Session["state"].ToString();
obj.country = billing_country.Text = Session["country"].ToString();
amount.Text = Session["chargetotal"].ToString();
obj.amnt = Convert.ToDouble(amount.Text);
if (Request.Form["currency"] == "356")
{
currencycode.Text = "INR";
}
if (Request.Form["currency"] == "896")
{
currencycode.Text = "GBP";
}
obj.cur = currencycode.Text;
Db(obj); //Saving values in database by passing ReponseModel
class } catch { } }
Where…
ipgTransactionId
is a unique transaction identifierapproval_code
is boolean for payment approvaltxndate_processed
is the date and time when transaction is performedtimezone
is the payment amountresponse_hash
is the hash codeoid
is the order idtdate
is the transaction dateinstallments_interest
is the interest in installments if there are anyname
is the buyer’s namemobileno
is the buyer’s numberemailid
is buyer’s email addressaddress
is buyer’s addresszipcode
is buyer’s area zip codecity
is the buyer’s citystate
is the buyer’s state/li>country
is the buyer’s countrycurrency
is the buyer’s currencychargetotal
is the payment amountstatus
is the transaction succeeded or failed
To get reponse from the server, Request.Form["variable"]
is used. It gets a collection of form variables. The Form property is populated when the HTTP request Content-Type value is either “application/x-www-form-urlencoded” or “multipart/form-data”.
Saving the Response in DB Using SQLite
The reponse we got from the server is in the form of model class & it is saved with SQLite
database . Generally Models in asp.net are easy to use if we clear with information like where we want to display data or save input data from various domain models then always use model class.
public void Db(ResponseModel obj) { try { string localCon = "Data Source=D:\\localdirectory\\localfolder\\databasename.sqlite;Version=3;"; string serverCon = "Data Source=C:\\Inetpub\\vhosts\\domainname\\serverfolder\\databasename.sqlite;Version=3;"; SQLiteConnection m_dbConnection = new SQLiteConnection(serverCon); m_dbConnection.Open(); string sql = "select * from ResponseDB"; SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection); command.ExecuteNonQuery(); sql = "insert into ResponseDB (Amount, TransactionId, OrderId, Status, Name, Country, State, City, Address, TransactionDate, ApprovalCode, TransactionDateProcessed, TimeZone, ResponseHash, FailRc, InstallmentIntererst, Currency, Zip, Telephone, Email, CCCountry, CCBrand) values(" + obj.amnt + ",'" + obj.tId + "','" + obj.orderId + "','" + obj.status + "','" + obj.name + "','" + obj.country + "','" + obj.state + "','" + obj.city + "','" + obj.address + "','" + obj.date + "','" + obj.approvalCode + "','" + obj.txndateprocessed + "','" + obj.timezone + "','" + obj.responsehash + "','" + obj.failrc + "','" + obj.installmentsinterest + "','" + obj.cur + "','" + obj.zip + "','" + obj.tel + "','" + obj.email + "','" + obj.cccountry + "','" + obj.ccbrand + "')"; command = new SQLiteCommand(sql, m_dbConnection); command.ExecuteNonQuery(); m_dbConnection.Close(); } catch { } }
Here, we have two connections both for the local and server. To test it in locally we can use the localCon
for testing purposes and similarly we can use the server connection i.e. serverCon
when the project is live.
Response Model Class
public class ResponseModel { public string tId { get; set; } public string orderId { get; set; } public double amnt { get; set; } public string status { get; set; } public string name { get; set; } public string country { get; set; } public string state { get; set; } public string city { get; set; } public string address { get; set; } public string date { get; set; } public string cur { get; set; } public string zip { get; set; } public string tel { get; set; } public string email { get; set; } public string approvalCode { get; set; } public string timezone { get; set; } public string responsehash { get; set; } public string failrc { get; set; } public string txndateprocessed { get; set; } public string cccountry { get; set; } public string installmentsinterest { get; set; } public string txndatetime { get; set; } public string fail_reason { get; set; } public string ccbrand { get; set; } }
Client-End Code
You can show the response values in the reponse.aspx
<form runat="server" class="donation-form"> <div> <label>Name</label> <div> <asp:TextBox ID="billing_name" ReadOnly="true" runat="server" data-val="true" name="billing_name" type="text" /> </div> </div> <div> <label>Mobile No</label> <div> <asp:TextBox ReadOnly="true" runat="server" data-val="true" ID="billing_tel" name="billing_tel" type="number" value="" /> </div> </div> <div> <label>Email ID</label> <div> <asp:TextBox ReadOnly="true" ID="billing_email" name="billing_email" type="email" value="" runat="server" /> </div> </div> <div> <label>Address</label> <div> <asp:TextBox ReadOnly="true" TextMode="multiline" runat="server" cols="20" ID="billing_address" name="billing_address" Rows="2" /> </div> </div> <div> <label>Zip code</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="billing_zip" name="billing_zip" /> </div> </div> <div> <label>Country</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="billing_country" name="billing_country" type="text" /> </div> </div> <div> <label>State</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="billing_state" name="billing_state" type="text" /> </div> </div> <div> <label>City</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="billing_city" name="billing_city" type="text" value="" /> </div> </div> <div> <label>Donation</label> <div> <asp:TextBox disable="true" ReadOnly="true" runat="server" ID="DonationId" name="DonationId"> </asp:TextBox> </div> </div> <div> <label>Amount</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="amount" name="amount" type="number" /> </div> </div> <div> <label>Currency</label> <div> <asp:TextBox disable="true" ReadOnly="true" runat="server" ID="currencycode" name="currencyCode"> </asp:TextBox> </div> </div> <div> <label>Remarks </label> <div> <asp:TextBox ReadOnly="true" runat="server" TextMode="multiline" cols="20" ID="billing_notes" name="billing_notes" Rows="2" /> </div> </div> <div> <label>Status</label> <div> <asp:TextBox ReadOnly="true" runat="server" ID="sId" /> </div> </div> </form>
Use of Source Code
To use the code supplied with the article, you need to have .NET Framework 4.0 or higher installed on your system. You also need to have a real or FirstData ICICI Merchant Services account. No additional requirements should be needed to open the FirstData account.