POST as form using C# to Pay Provider

The Remote Post Form class

I have used the code for the jigar site and added my own goodies, so all credit to him. Sorry about the flast formating but is the only way I could get a neatish post


using System;
using System.Collections.Generic;
using System.Web;

using System.Security.Cryptography;
/// <summary>
/// Remotely handle and Post form from http://www.jigar.net/articles/viewhtmlcontent78.aspx%20
/// </summary>
public class RemotePost
{
private System.Collections.Specialized.NameValueCollection Inputs
= new System.Collections.Specialized.NameValueCollection();
public string Url;
public string Method;
public string FormName;

public RemotePost(string pURL)
{
//
// TODO: Add constructor logic here
//
Url = pURL;
Method = "post";
FormName = "frmRemotePost";
}
 
public void Add(string name, string value)
{
Inputs.Add(name, value);
}

public void Post()
{
System.Web.HttpContext.Current.Response.Clear();

System.Web.HttpContext.Current.Response.Write("<html><head>");
System.Web.HttpContext.Current.Response.Write(string.Format("</head><body onload=\"document.{0}.submit()\">", FormName));
System.Web.HttpContext.Current.Response.Write(string.Format("<form name=\"{0}\" method=\"{1}\" action=\"{2}\" >",
FormName, Method, Url))
;
for (int i = 0; i < Inputs.Keys.Count; i++)
{
System.Web.HttpContext.Current.Response.Write(string.Format("<input name=\"{0}\" type=\"hidden\" value=\"{1}\">", Inputs.Keys[i], Inputs[Inputs.Keys[i]]));
}
System.Web.HttpContext.Current.Response.Write("</form>");
System.Web.HttpContext.Current.Response.Write("</body></html>");
System.Web.HttpContext.Current.Response.End();
}
/// <summary>
/// Calculates the md5 signautre using the items from start to pEnd (optional)
/// </summary>
/// <param name="pStart">From which field to start, 1 is first</param>
/// <param name="pEnd">(Optional) to what field</param>
/// <returns>MD5 string</returns>
public string CalcMD5Signature(int pStart)
{
if (Inputs.Keys.Count == 0)
return "";
else
return CalcMD5Signature(pStart, Inputs.Keys.Count);
}
public string CalcMD5Signature(int pStart, int pEnd)
{
if (Inputs.Keys.Count == 0)
return "";
else
{
// start calculating the standard string
string strKeys = String.Format("{0}={1}", Inputs.Keys[pStart], Inputs[Inputs.Keys[pStart]]);

if (pEnd > Inputs.Keys.Count) pEnd = Inputs.Keys.Count;

for (int i = pStart; i < pEnd; i++) {
if (Inputs[Inputs.Keys[i]].Length > 0) //only if it is not blank add
strKeys += String.Format("&{0}={1}", Inputs.Keys[i], Inputs[Inputs.Keys[i]]);
}
// now calc MD5
Byte[] bOriginal;
Byte[] bEncoded;
MD5 md5Signature = new System.Security.Cryptography.MD5CryptoServiceProvider();
string strHex;

// Now convert it to MD5
bOriginal = System.Text.ASCIIEncoding.Default.GetBytes(strKeys);
bEncoded = md5Signature.ComputeHash(bOriginal);

//Convert encoded bytes back to a 'readable' string
strHex = BitConverter.ToString(bEncoded); // converst string adds "-" betwen each byte
strHex = strHex.Replace("-", ""); //PayFast does not want the dashes the tostring adds

// this does not seem to work with PayFast for some reason
return strHex.ToLower(); // payfast needs the string in lower case
}

}
}

PayFast Class

This class is used by the PayNow button on your form, to send payment through
/// <summary>
/// class used to access and use the payfast services, used php sample as a guide
/// </summary>
public class PayFast
{

// Messages that PayFast may send
// Error
const string PF_ERR_AMOUNT_MISMATCH = "PF: Amount mismatch";
const string PF_ERR_BAD_SOURCE_IP = "PF: Bad source IP address";
const string PF_ERR_CONNECT_FAILED = "PF: Failed to connect to PayFast";
const string PF_ERR_BAD_ACCESS = "PF: Bad access of page";
const string PF_ERR_INVALID_SIGNATURE = "PF: Security signature mismatch";
const string PF_ERR_CURL_ERROR = "PF: An error occurred executing cURL";
const string PF_ERR_INVALID_DATA = "PF: The data received is invalid";
const string PF_ERR_UKNOWN = "PF: Unknown error occurred";
//General
const string PF_MSG_OK = "PF: Payment was successful";
const string PF_MSG_FAILED = "PF: Payment has failed";

/* Pay fast Constants - for get Value */
//-- Based on http://www.payfast.co.za/c/std/website-payments-variables
//-- Receiver Details --
public const int PF_GET_MERCHANT_ID = 1;
public const int PF_GET_MERCHANT_KEY = 2;
public const int PF_GET_RETURN_URL = 3;
public const int PF_GET_CANCEL_URL = 4;
public const int PF_GET_NOTIFY_URL = 5;

//-- Payer Details
public const int PF_GET_NAME_FIRST = 6;
public const int PF_GET_NAME_LAST = 7;
public const int PF_GET_EMAIL_ADDRESS = 8;

//-- Transaction Details
public const int PF_GET_M_PAYMENT_ID = 9;
public const int PF_GET_AMOUNT = 10;
public const int PF_GET_ITEM_NAME = 11;
public const int PF_GET_ITEM_DESCRIPTION = 12;

//-- Transaction Options
public const int PF_GET_EMAIL_CONFIRMATION = 13;
public const int PF_GET_CONFIRMATION_ADDRESS = 14;

//-- Security
public const int PF_GET_SIGNATURE = 15;

//-- Constants for values of above - strings used since they are passt in the input form
#if PAYFAST_TEST
const string PF_HOST = "https://sandbox.payfast.co.za/eng/process/"; //-- public means ew can use it to manuall control buttons
const string PF_USERNAME = "sbtm01@payfast.co.za";
const string PF_MERCHANT_ID = "10000100";
const string PF_MERCHANT_KEY = "46f0cd694581a";

// PDT Key: 0a1e2e10-03a7-4928-af8a-fbdfdfe31d43

#else
const string PF_HOST = "https://www.payfast.co.za/eng/process";
const string PF_USERNAME = "warrenm@Widget.co.za";
const string PF_MERCHANT_ID = "10000100"; //-- replace these with your
const string PF_MERCHANT_KEY = "46f0cd694581a "; //--replace these with yours

#endif

//-- constants that are used all the time regardless of mode
const string PF_RETURN_URL = "http://www.widget.co.za/Pages/forms/PaymentDone.aspx";
const string PF_CANCEL_URL = "http://www.widget.co.za/Pages/forms/PaymentCancelled.aspx";
const string PF_NOTIFY_URL = "http://www.widget.co.za/Pages/forms/PaymentNotify.aspx";

const string PF_EMAIL_CONFIRMATION = "1";
const string PF_CONFIRMATION_ADDRESS = "order@widget.co.za";

//-- Now class variables that are accessable to the outside world
public string PostResult = "";
public string PostURL = PF_HOST;

//-- Now class variables that are used internally
//-- class variables, set and used
//-- Payer Vairables
string NameFirst = ""; //-- Bob
string NameLast = ""; //-- Smith
string EmailAddress = "" ; //-value="bob.smith@example.com

//-- Transaction varaibles
string MPaymentId = ""; //-- Unique payment ID on the merchant's system
string Amount = ""; //-- The amount which the payer must pay
string ItemName = "WidgetOrder"; //--    The name of the item being charged for - 100 char    
string ItemDescription = "Widget Related Goods"; //-- The description of the item being charged for. - 255 char

//-- Security
string Signature = ""; //-- A security signature of the transmitted data taking the form of an MD5 hash of the submitted variables.

public PayFast()
    {
        //
        // any items we need to initialize go here
        //
    }

/// <summary>
/// Split a FullName into a first and last name, assuming that the first word is a first name
/// </summary>
/// <param name="pFullName">The full name string</param>
/// <param name="pFirstName">The first name string variable to be returned</param>
/// <param name="pLastName">The last name string variable to be returned</param>
public virtual void SplitFullName(string pFullName, out string pFirstName, out string pLastName)
{
int iSpace = pFullName.IndexOf(" ");

if(iSpace > 0)
{
//-- firsname lastnames
pFirstName = pFullName.Substring(0, iSpace).Trim();
pLastName = pFullName.Substring(iSpace + 1).Trim();
}
else
{
//-- did they enter last, first?
iSpace = pFullName.IndexOf(",");
if(iSpace > 0)
{
pLastName = pFullName.Substring(iSpace + 1).Trim();
pFirstName = pFullName.Substring(0, iSpace).Trim();
}
else
{
//-- looks like they sent only one name
pFirstName = pFullName.Trim();
pLastName = "";
}
}

}

/// <summary>
/// Set the payer details using FullName which is split for you, and email address
/// </summary>
/// <param name="pFullName">Full Name, i.e. first last</param>
/// <param name="pEmailAdress">email address of payer</param>
public virtual void SetPayerDetails (string pFullName, string pEmailAdress)
{

string strFirstName = "";
string strLastName = "";

//-- split the last name into first and last names
SplitFullName(pFullName, out strFirstName, out strLastName);

//-- now set the vars
SetPayerDetails(strFirstName, strLastName, pEmailAdress);
}

/// <summary>
/// Set the payer complete details with first name, last name and email address
/// </summary>
/// <param name="pNameFirst">Payers First Name</param>
/// <param name="pNameList">Payers Last Name</param>
/// <param name="pEmailAddress">Payers Email Address</param>
public virtual void SetPayerDetails (string pNameFirst, string pNameLast, string pEmailAddress)
{
NameFirst = pNameFirst;
NameLast = pNameLast;
EmailAddress = pEmailAddress;
}

/// <summary>
/// Set the transaciton details for the payfast transaction
/// </summary>
/// <param name="pPaymentId">Unique payment ID on the merchant's system</param>
/// <param name="pAmount">The amount which the payer must pay</param>
/// <param name="pItemBame">The name of the item being charged for - 100 char</param>
/// <param name="pItemDescription">The description of the item being charged for. - 255 char</param>
public virtual void SetTransactionDetails(string pPaymentId, string pAmount, string pItemName, string pItemDescription)
{
//-- set the local variables
MPaymentId = pPaymentId; //-- the order id can be used to cross reference so must be the same
Amount = pAmount.Replace(",",""); // strip any thousand seperator
ItemName = pItemName;
ItemDescription = pItemDescription;
}
/// <summary>
/// Can be called from the input form using in line script so returned string of the value requested, or
/// Directly from your own class, like it is in this class
/// </summary>
/// <param name="pGetType">PF_ item as per the items require on the form</param>
/// <returns>string of requested data</returns>
public virtual string GetPFItem(int pGetPFType)
{
switch (pGetPFType) {

case PF_GET_MERCHANT_ID:
return PF_MERCHANT_ID;

case PF_GET_MERCHANT_KEY:
return PF_MERCHANT_KEY;

case PF_GET_RETURN_URL:
return PF_RETURN_URL;

case PF_GET_CANCEL_URL:
return PF_CANCEL_URL;

case PF_GET_NOTIFY_URL:
return PF_NOTIFY_URL;

//-- Payer Details
case PF_GET_NAME_FIRST:
return NameFirst;

case PF_GET_NAME_LAST :
return NameLast;

case PF_GET_EMAIL_ADDRESS:
return EmailAddress;

//-- Transaction Details
case PF_GET_M_PAYMENT_ID:
return MPaymentId;

case PF_GET_AMOUNT:
return Amount;

case PF_GET_ITEM_NAME:
return ItemName;

case PF_GET_ITEM_DESCRIPTION:
return ItemDescription;

case PF_GET_EMAIL_CONFIRMATION:
return PF_EMAIL_CONFIRMATION;

case PF_GET_CONFIRMATION_ADDRESS:
return PF_CONFIRMATION_ADDRESS;

case PF_GET_SIGNATURE:
string sSignature; //name_first=John&name_last=Doe&email_address=.
// MD5 stuff
Byte[] bOriginal;
Byte[] bEncoded;
MD5 md5Signature = new System.Security.Cryptography.MD5CryptoServiceProvider();
string sHex;

sSignature = "name_first=" + NameFirst;
if (NameLast.Length > 0)
sSignature = sSignature + "&name_last=" + NameLast;

sSignature += "&email_address=" + EmailAddress
+ "&m_payment_id=" + MPaymentId
+ "&amount=" + Amount
+ "&item_name=" + ItemName
+ "&item_description=" + ItemDescription
+ "&email_confirmation=" + PF_EMAIL_CONFIRMATION
+ "&confirmation_address=" + PF_CONFIRMATION_ADDRESS;

sSignature = sSignature.ToLower();
// Now convert it to MD5
bOriginal = System.Text.ASCIIEncoding.Default.GetBytes(sSignature);
bEncoded = md5Signature.ComputeHash(bOriginal);

//Convert encoded bytes back to a 'readable' string
sHex = BitConverter.ToString(bEncoded); // converst string adds "-" betwen each byte
sHex = sHex.Replace("-", ""); //PayFast does not want the dashes the tostring adds

// crap thing does not work if I do not put blank
// return sHex.ToLower(); // payfast needs the string in lower case

return ""; //-- could not get the signature to work as doc says

default:
return "err-incorrect PF value passed";

} //-- end switch
}
/// <returns>true if success</returns>
public bool PostToRemote()
{ return PostToRemote("", "", "", "", ""); }
public bool PostToRemote(string pCustomStr1)
{ return PostToRemote(pCustomStr1, "","", "", ""); }
public bool PostToRemote(string pCustomStr1, string pCustomStr2)
{ return PostToRemote(pCustomStr1, pCustomStr2, "", "", ""); }
public bool PostToRemote(string pCustomStr1, string pCustomStr2, string pCustomStr3)
{ return PostToRemote(pCustomStr1, pCustomStr2, pCustomStr3,"",""); }
public bool PostToRemote(string pCustomStr1, string pCustomStr2, string pCustomStr3, string pCustomStr4)
{ return PostToRemote(pCustomStr1, pCustomStr2, pCustomStr3, pCustomStr4,""); }
public bool PostToRemote(string pCustomStr1, string pCustomStr2, string pCustomStr3, string pCustomStr4, string pCustomStr5)
{
try
{
RemotePost PayFastPost = new RemotePost(PF_HOST);

// Receiver Details
PayFastPost.Add("merchant_id",GetPFItem(PF_GET_MERCHANT_ID));
PayFastPost.Add("merchant_key",GetPFItem(PF_GET_MERCHANT_KEY));
PayFastPost.Add("return_url",GetPFItem(PF_GET_RETURN_URL));
PayFastPost.Add("cancel_url",GetPFItem(PF_GET_CANCEL_URL));
PayFastPost.Add("notify_url",GetPFItem(PF_GET_NOTIFY_URL));
// Payer Details
PayFastPost.Add("name_first",GetPFItem(PF_GET_NAME_FIRST));
PayFastPost.Add("name_last", GetPFItem(PF_GET_NAME_LAST));
PayFastPost.Add("email_address",GetPFItem(PF_GET_EMAIL_ADDRESS));
// Transaction Details
PayFastPost.Add("m_payment_id",GetPFItem(PF_GET_M_PAYMENT_ID));
PayFastPost.Add("amount", GetPFItem(PF_GET_AMOUNT));
PayFastPost.Add("item_name", GetPFItem(PF_GET_ITEM_NAME));
PayFastPost.Add("item_description", GetPFItem(PF_GET_ITEM_DESCRIPTION));
if (pCustomStr1 != "")
PayFastPost.Add("custom_str1", pCustomStr1);
if (pCustomStr2 != "")
PayFastPost.Add("custom_str2", pCustomStr2);
if (pCustomStr3 != "")
PayFastPost.Add("custom_str3", pCustomStr3);
if (pCustomStr4 != "")
PayFastPost.Add("custom_str5", pCustomStr3);
if (pCustomStr5 != "")
PayFastPost.Add("custom_str5", pCustomStr3);
// have not handled int
// Transaction Options
PayFastPost.Add("email_confirmation", GetPFItem(PF_GET_EMAIL_CONFIRMATION));
PayFastPost.Add("confirmation_address", GetPFItem(PF_GET_CONFIRMATION_ADDRESS));
//PayFastPost.Add("signature", PayFastPost.CalcMD5Signature(0)); // 5 should be the name, but this does not work?
PayFastPost.Add("signature", GetPFItem(PF_GET_SIGNATURE));
PayFastPost.Post();
PostResult = "form posted";
return true; //-- if we got here all is okay
}
catch (Exception ex)
{
PostResult = "err: " + ex.Source + ", " + ex.Message;
return false;
}
}
}

Usage

Here I post the data to PayFast, store a cookie and a session variable just in case one gets lost, I use them in the Pay%% files
The Quick cookie class simple saves or retrieves a cook with error handling and expiry


protected void btnPayNow_Click(object sender, EventArgs e)
{
PayFast myPayFast = new PayFast();


myPayFast.SetPayerDetails(ltrlFullName.Text, ltrlEmail.Text);
myPayFast.SetTransactionDetails(ltrlOrderID.Text, ltrlTotal.Text, ltrlItem.Text, ltrlOrderID.Text);

// set the session variable for use by the cancellation, done and processed URL's to be called
// by the PayFast server later
Session.Add("OrderID", ltrlOrderID.Text);
QuickCookie QuaffeeCookie = new QuickCookie();
QuaffeeCookie.SetCookie("LastOrderID", ltrlOrderID.Text, 50);
// at the moment the form is submitted no click handleing now
if (myPayFast.PostToRemote(ltrlOrderID.Text))
ltrlPayFastErr.Text = "Posted:" + myPayFast.PostResult; // transfer to the constructed URL
else
ltrlPayFastErr.Text = "Error posting: " + myPayFast.PostResult;
}
}


 
 Hope this helps good luck to all

Comments

Popular Posts