Skip to main content

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 from this blog

Bitcoin / Cryptocurrency – what is it and how can I benefit

What is it I started investigating Bitcoin when it was worth just over $1000 a bitcoin. I was interested in what it was and how it worked. A lot of people are saying we missed the boat, but I believe that everyone should at least try put a little money in now, or at least use a faucet (see below) to make a little micro-currency. You can read a Wiki article about bitcoin and its history etc. But what you need to know is that it is a currency, that is independent of country. No one really knows who invented the concept of a cryptocurrency since the person who published the paper used a nom de plume. All new cryptocurrencies work more or less the same way as Bitcoin. So as I explain below I interchange these terms. Bitcoin is the original cryptocurrency. How Bitcoin works The currency releases a coin based on a mathematical formula. There will never be more than 21 million bitcoins (other cryptocurrencies do not work like this). Each bitcoin can have divided into one hundred mil

Migrating QuickBooks to Sage One Cloud accounting - Part 1 Exporting the data

Some notes Sage means sage one online accounts, wherever we say Sage we mean Sage one. The QuickBooks we used was version 2012 Professional. But most of the information is similar. What you need > You need the templates from Sage and the data from QuickBooks, see below for how to do these. Get Import Templates from Sage To get the templates for the items go to help.accounting.sageone.co.za/en_za/accounting/from-your-previous-accounting-system.html Although you can construct the templates from the information in this post you can download samples of the templates need. Below are the links they provide: Use the following downloads which are referenced in the guide: General Ledger Accounts Import Template Customer Import Template Customer Outstanding Invoices Import Template Supplier Import Template Supplier Outstanding Invoices Import Template Item Import Template   Another useful page that is hard to find on their system is: help.accounting.sageone.co.za/en_za/ac

Mindfullness Meditation and Depression - in a pod cast

Over the last 3 years I have found that meditation has really assisted me, in resolving the depression I have had. I have planned to write about my experience for a while, and hopefully will get around to doing that. However today having listen to the latest podcast by Dan Harris on 10% happier, so many things just clicked in to place, so I want to share it. To understand what is covered in the podcast I would recommend you understand what mindfulness meditation is, and what the default mode network in the brain is (see links below). Listen to the pod cast - but here are some extracts (which I do not have permission to publish - and will remove if asked). Link to podcast: tumello.com/listen/H11a5NYJf; or itunes.apple.com/us/podcast/10-happier-with-dan-harris/id1087147821 Chuck Raison, a psychiatrist and a professor of psychiatry at the University of Wisconsin-Madison School of Medicine and Public Health, and Vlad Maletic, a clinical professor of neuropsychiatry and behavior sc