The C# sample at the IPN website, is a little bit outdated, since paypal currently supports international character sets (great!) so if a chinese customer would enter his name in Chinese for instance :), it still would be kept ok. So to not corrupt the characters, we have to stick the same format as paypal sends us. This would be simple if the page would be a web service form, it is not, so we have to wrap the POST request and do the encoding all yourselves.
using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Net;
using System.ComponentModel;
using System.Data;
using System.Web;
using CSession;
namespace pp
{
/// <summary>
/// Summary description for ipn.
/// </summary>
public partial class ipn : System.Web.UI.Page
{
private bool isTesting;
// this page runs as LCID 1033 english
// and is tested on codepage 65001. you must –enable- the codepage
// on your paypal preferences!
// note that the shopping basket, is based on ISP Session from
// http://www.nieropwebconsult.nl/asp_session_manager.htm
// it integrates with classic asp as well as .NET
protected void Page_Load(object sender, System.EventArgs e)
{
NameValueCollection rq = Request.Form;
//Response.BufferOutput = false;
string test_ipn = rq["test_ipn"];
isTesting = test_ipn != null && test_ipn == "1"? true: false;
// Create the request back
// instead of pp_url you could read https://www.paypal.com/cgi-bin/webscr
HttpWebRequest req = (HttpWebRequest) WebRequest.Create(
System.Configuration.ConfigurationSettings.AppSettings["pp_url"]);
string version = rq["notify_version"]; // ' 2.1 currently
// Set values for the request back
req.Method = "POST";
string notifyCmd = "cmd=_notify-validate";
req.ContentType = "application/x-www-form-urlencoded";
// the charset will be utf-8 if set as preference on paypal!
Encoding enc = System.Text.Encoding.GetEncoding(rq["charset"]);
StreamWriter tw = new StreamWriter(new MemoryStream());
int keyCount = rq.Count;
// here goes our first command
tw.Write(notifyCmd);
//tricky part. If you do Request.Form.ToString() the & and the = is encoded as well!
for (int xx = 0; xx < keyCount; xx++)
{
tw.Write('&');
tw.Write(HttpUtility.UrlEncodeToBytes(rq.GetKey(xx), enc));
tw.Write('=');
tw.Write(HttpUtility.UrlEncodeToBytes(rq.Get(xx), enc));
}
int contLen = (int)tw.BaseStream.Position;
req.ContentLength = contLen;
// Write the request back IPN strings in binary form
// do not use a TextWriter since that would cause
// encoding on encoding which obviously will fail
byte[] temp = new byte[contLen];
tw.BaseStream.Position = 0;
tw.BaseStream.Read(temp, 0, contLen);
Stream stOut = req.GetRequestStream();
stOut.Write(temp, 0, contLen);
stOut.Flush();
// Do the request to PayPal and get the response
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream(), enc);
string strResponse = stIn.ReadToEnd();
stIn.Close();
string Item_number, Payment_status, Txn_id, sessionId;
Item_number = rq["item_number"];
sessionId = rq["invoice"];
Txn_id = rq["txn_id"];
db dbl = new db();
dbl.sqlConn.Open();
DataSet1.tLicenseRow lic = dbl.dataSet11.tLicense.NewtLicenseRow();
lic.CtryISO2Code = rq["address_country_code"];
lic.email = rq["payer_email"];
//TODO: lic should be fullfilled
lic.sessionID = new Guid(sessionId).ToByteArray();
lic.transactionID = Guid.NewGuid();
lic.salesBlob = rq.ToString().Replace("&", "\r\n");
lic.saleDate = DateTime.Now;
lic.total_value = decimal.Parse(rq["mc_gross"]);
lic.tax_value = decimal.Parse(rq["tax"]);
lic.salesBlobType = 1;
lic.total_fee = decimal.Parse(rq["mc_fee"]);
Payment_status = rq["payment_status"];
lic.Payment_status = Payment_status;
lic.downloadComplete = 0;
// Create the IpnTransaction
basket bsk = null;
bool validSession = false;
if (sessionId != null && sessionId.Length == 32)
{
bsk = new basket(sessionId);
validSession = true;
}
// Confirm whether the IPN was VERIFIED or INVALID. If INVALID, just ignore the IPN
if (strResponse == "VERIFIED")
{
if (validSession)
{
bsk.Session["Payment_status"] = 1;
bsk.setPurchaseAuthorized(lic.transactionID);
msg.Text = "valid";
Response.AppendToLog("valid session");
}
else
{
Response.AppendToLog("invalid session");
msg.Text = "invalid";
}
}
else
{
if (validSession)
{
Response.AppendToLog("invalid transaction, valid session");
msg.Text = "invalid";
bsk.Session["payment_status"] = 0;
}
}
dbl.dataSet11.tLicense.AddtLicenseRow(lic);
dbl.tLicense.Update(dbl.dataSet11.tLicense);
dbl.sqlConn.Close();
dbl.Dispose();
if (bsk != null) bsk.Dispose();
}
}
}