一、 准備文件
文檔資料

根據 客戶提供文檔《CHINAPAY商戶控制台使用手冊 》登陸 http://console.chinapay.com/newgms (需要客戶提供 商戶號,操作員號及密碼)
下載

解壓文件后得到如下文件

還需要2個key(MerPrK.key和PgPubk.key)文件,分別是商戶私匙和公匙,需要客戶簽訂合同后銀聯才提供。
二、安裝部署
1. 將ChinaPay.dll、CPNPC.dll及netpay.dll復制bin下
2. 注冊Chinapay.dll和CPNPC.dll(指令regsvr32 )
例如 regsvr32 F:\工作\MySolution\Web\bin\Chinapay.dll
regsvr32 F:\工作\MySolution\Web\bin\CPNPC.dll
3. Com類型信息轉換為.NET元數據, 需要vs命令提示 工具下運行
tlbimp F:\工作\MySolution\Web\bin\Chinapay.dll /out: F:\工作\MySolution\Web\bin\ ChinaPay_loaf.dll
站點增加引用ChinaPay_loaf.dll 使用的時候引用using ChinaPay_loaf 即可
4. 寫一個類Chinapay.cs放在App_Code下 用於 用戶簽名 和驗證,不理解簽名和驗證的看《附3商戶技術開發手冊.doc》數字簽名,
Chinapay.cs
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using ChinaPay_loaf ;
using System.Web.UI;
/// <summary>
/// Chinapay 的摘要說明
/// </summary>
public class Chinapay
{
string strUrl =HttpContext.Current.Request.PhysicalApplicationPath; // 獲取網站根目錄物理路徑
public Chinapay()
{
}
/// <summary>
/// 訂單簽名函數sign
/// </summary>
/// <param name="MerId"> 商戶號,長度為15個字節的數字串,由ChinaPay或清算銀行分配 </param>
/// <param name="OrdId"> 訂單號,長度為16個字節的數字串,由用戶系統/網站生成,失敗的訂單號允許重復支付 </param>
/// <param name="TransAmt"> 交易金額,長度為12個字節的數字串,例如:數字串"000000001234"表示12.34元 </param>
/// <param name="CuryId"> 貨幣代碼, 長度為3個字節的數字串,目前只支持人民幣,取值為"156" </param>
/// <param name="TransDate"> 交易日期,長度為8個字節的數字串,表示格式為:YYYYMMDD </param>
/// <param name="TransType"> 交易類型,長度為4個字節的數字串,取值范圍為:"0001"和"0002", 其中"0001"表示消費交易,"0002"表示退貨交易 </param>
/// <returns> string CheckValue[256] 即NetPayClient根據上述輸入參數生成的商戶數字簽名,長度為256字節的字符串 </returns>
public string getSign( string MerId, string OrdId, string TransAmt, string CuryId, string TransDate, string TransType)
{
NetPayClientClass npc = new NetPayClientClass(); // 實例NetPay簽名
string temp = strUrl + " key\\MerPrK.key ";
npc.setMerKeyFile(strUrl + " \\App_Data\\MerPrK.key ");
string strChkValue = ""; // chinapay返回的商戶數字簽名
strChkValue = npc.sign(MerId, OrdId, TransAmt, CuryId, TransDate, TransType);
return strChkValue.Trim();
}
/// <summary>
/// 對一段字符進行簽名 signData
/// </summary>
/// <param name="MerId"> 商戶號,長度為15個字節的數字串,由ChinaPay分配 </param>
/// <param name="SignMsg"> 用於要簽名的字符串 </param>
/// <returns> String CheckValue[256]即NetPayClient根據上述輸入參數生成的商戶數字簽名,長度為256字節的字符串 </returns>
public string signData( string MerId, string SignMsg)
{
NetPayClientClass npc = new NetPayClientClass(); // 實例NetPay簽名
npc.setMerKeyFile(strUrl + " App_Data\\MerPrK.key ");
string strChkValueData = "";
strChkValueData = npc.signData(MerId, SignMsg);
return strChkValueData.Trim();
}
/// <summary>
/// 驗證交易應答函數check
/// </summary>
/// <param name="MerId"> 商戶號,長度為15個字節的數字串,由ChinaPay分配 </param>
/// <param name="OrdId"> 訂單號,長度為16個字節的數字串,由商戶系統生成,失敗的訂單號允許重復支付 </param>
/// <param name="TransAmt"> 交易金額,長度為12個字節的數字串,例如:數字串"000000001234"表示12.34元 </param>
/// <param name="CuryId"> 貨幣代碼, 長度為3個字節的數字串,目前只支持人民幣,取值為"156" </param>
/// <param name="TransDate"> 交易日期,長度為8個字節的數字串,表示格式為: YYYYMMDD </param>
/// <param name="TransType"> 交易類型,長度為4個字節的數字串,取值范圍為:"0001"和"0002", 其中"0001"表示消費交易,"0002"表示退貨交易 </param>
/// <param name="OrderStatus"> 交易狀態,長度為4個字節的數字串。詳見交易狀態碼說明 </param>
/// <param name="CheckValue"> 校驗值,即ChinaPay對交易應答的數字簽名,長度為256字節的字符串 </param>
/// <returns> true 表示成功,即該交易應答為ChinaPay所發送,商戶根據“交易狀態”進行后續處理;否則表示失敗,即無效應答,商戶可忽略該應答 </returns>
public bool getCheck( string MerId, string OrdId, string TransAmt, string CuryId, string TransDate, string TransType, string OrderStatus, string CheckValue)
{
NetPayClientClass npc = new NetPayClientClass(); // 實例NetPay簽名
npc.setPubKeyFile(strUrl + " App_Data\\PgPubk.key ");
string strFlag = "";
bool bolFlag = false;
strFlag = npc.check(MerId, OrdId, TransAmt, CuryId, TransDate, TransType, OrderStatus, CheckValue); // ChkValue 為ChinaPay返回給商戶的域段內容
if (strFlag == " 0 ") // “0”表示驗簽成功
bolFlag = true;
return bolFlag;
}
/// <summary>
/// 對一段字符串進行簽名驗證 checkData
/// </summary>
/// <param name="PlainData"> 用於數字簽名的字符串 </param>
/// <param name="CheckValue"> 校驗值,要驗證的字符串的數字簽名,長度為256字節的字符串 </param>
/// <returns> true 表示驗證通過成功;否則表示失敗 </returns>
public bool checkData( string PlainData, string CheckValue)
{
NetPayClientClass npc = new NetPayClientClass(); // 實例NetPay簽名
npc.setPubKeyFile(strUrl + " App_Data\\PgPubk.key ");
string strFlagData = "";
bool bolFlagData = false;
strFlagData = npc.checkData(PlainData, CheckValue);
if (strFlagData == " true ")
bolFlagData = true;
return bolFlagData;
}
//
// 支付函數
/// <summary>
/// 支付函數
/// </summary>
/// <param name="OrderID"> 程序 訂單編號 </param>
/// <param name="TransAmt"> 交易錢數 </param>
/// <param name="proName"> 產品名稱 可選 </param>
public void GoToPay( string OrderID, string TransAmt, string proName, string gateid)
{
Chinapay cpy = new Chinapay();
// 獲取傳遞給銀聯chinapay的各個參數-----------------------------------------------
// string cpyUrl = " http://payment-test.chinapay.com/pay/TransGet "; // 測試地址,測試的時候用這個地址,應用到網站時用下面那個地址
string cpyUrl = " http://payment.chinapay.com/pay/TransGet ";
string cpyMerId = " 808080580112345 "; // ChinaPay統一分配給商戶的商戶號,15位長度,必填
string cpyOrdId = getOrderID(OrderID); // 商戶提交給ChinaPay的交易訂單號,訂單號的第五至第九位必須是商戶號的最后五位,即“12345”;16位長度,必填
string cpyTransAmt = getTransAmt(TransAmt); // 訂單交易金額,12位長度,左補0,必填,單位為分,000000000001 表示 12.34 元
string cpyCuryId = " 156 "; // 訂單交易幣種,3位長度,固定為人民幣156,必填
string cpyTransDate = DateTime.Now.ToString( " yyyyMMdd "); // 訂單交易日期,8位長度,必填,格式yyyyMMdd
string cpyTransType = " 0001 "; // 交易類型,4位長度,必填,0001表示消費交易,0002表示退貨交易
string cpyVersion = " 20040916 "; // 支付接入版本號,808080開頭的商戶用此版本,必填,另一版本為"20070129"
string cpyBgRetUrl = " http://test003.abc.cc/Chinapay_Bgreturn.aspx "; // 后台交易接收URL,為后台接受應答地址,用於商戶記錄交易信息和處理,對於使用者是不可見的,長度不要超過80個字節,必填
string cpyPageRetUrl = " http://test003.abc.cc/Chinapay_Pgreturn.aspx "; // 頁面交易接收URL,為頁面接受應答地址,用於引導使用者返回支付后的商戶網站頁面,長度不要超過80個字節,必填
string cpyGateId = gateid; // 支付網關號,可選,參看銀聯網關類型,如填寫GateId(支付網關號),則消費者將直接進入支付頁面,否則進入網關選擇頁面,可登陸商戶管理平台 查看各個銀行的網管號
string cpyPriv1 = proName; // 商戶私有域,長度不要超過60個字節,商戶通過此字段向Chinapay發送的信息,Chinapay依原樣填充返回給商戶
string strChkValue = ""; // 256字節長的ASCII碼,此次交易所提交的關鍵數據的數字簽名,必填
strChkValue = cpy.getSign(cpyMerId, cpyOrdId, cpyTransAmt, cpyCuryId, cpyTransDate, cpyTransType);
if (strChkValue != "")
{
HttpContext.Current.Response.Write( " <form name='chinapayForm' method='post' action=' " + cpyUrl + " '> "); // 支付地址
HttpContext.Current.Response.Write( " <input type='hidden' name='MerId' value=' " + cpyMerId + " ' /> "); // 商戶號
HttpContext.Current.Response.Write( " <input type='hidden' name='OrdId' value=' " + cpyOrdId + " ' /> "); // 訂單號
HttpContext.Current.Response.Write( " <input type='hidden' name='TransAmt' value=' " + cpyTransAmt + " ' /> "); // 支付金額
HttpContext.Current.Response.Write( " <input type='hidden' name='CuryId' value=' " + cpyCuryId + " ' /> "); // 交易幣種
HttpContext.Current.Response.Write( " <input type='hidden' name='TransDate' value=' " + cpyTransDate + " ' /> "); // 交易日期
HttpContext.Current.Response.Write( " <input type='hidden' name='TransType' value=' " + cpyTransType + " ' /> "); // 交易類型
HttpContext.Current.Response.Write( " <input type='hidden' name='Version' value=' " + cpyVersion + " ' /> "); // 支付接入版本號
HttpContext.Current.Response.Write( " <input type='hidden' name='BgRetUrl' value=' " + cpyBgRetUrl + " ' /> "); // 后台接受應答地址
HttpContext.Current.Response.Write( " <input type='hidden' name='PageRetUrl' value=' " + cpyPageRetUrl + " ' /> "); // 為頁面接受應答地址
HttpContext.Current.Response.Write( " <input type='hidden' name='GateId' value=' " + cpyGateId + " ' /> "); // 支付網關號
HttpContext.Current.Response.Write( " <input type='hidden' name='Priv1' value=' " + cpyPriv1 + " ' /> "); // 商戶私有域,這里將訂單自增編號放進去了
HttpContext.Current.Response.Write( " <input type='hidden' name='ChkValue' value=' " + strChkValue + " ' /> "); // 此次交易所提交的關鍵數據的數字簽名
HttpContext.Current.Response.Write( " <script> ");
HttpContext.Current.Response.Write( " document.chinapayForm.submit(); ");
HttpContext.Current.Response.Write( " </script></form> ");
}
}
// 訂單號
private string getOrderID( string orderID)
{
// 程序中的訂單號 案例12022800001
string orderid = string.Format( " {0}{1}{2} ", orderID.Substring( 0, 4), " 12345 ", orderID.Substring( 4)); // 訂單前四位+商家最后五位+訂單后七位
return orderid;
}
// 返回交易金額
private string getTransAmt( string count)
{
string moneyCount = count.ToString().Replace( " . ", "");
return moneyCount.PadLeft( 12, ' 0 ');
}
}
5. 下面的需要解決的就是寫四個頁面(支付頁,銀行選擇頁面,后台接受處理頁和用戶支付成功后跳轉頁),銀行選擇頁面,主要是自己定義圖標,這里目的就是為了選擇不同的網關來對應不同的銀行.羅列出常用的銀行。
后台接受頁面
{
Chinapay cpy = new Chinapay();
string TransDate = "",MerId = "",OrdId = "",TransType = "",TransAmt = "",CuryId = "",ChkValue = "",OrderStatus = "",GateId = "",Priv1 = "";
bool bolCheck= false;
TransDate = Request[ " transdate "].Trim(); // 交易日期
MerId = Request[ " merid "].Trim(); // 商家號
OrdId = Request[ " orderno "].Trim(); // 訂單號
TransType = Request[ " transtype "].Trim(); // 交易類型
TransAmt = Request[ " amount "].Trim(); // 交易貨幣值
CuryId = Request[ " currencycode "].Trim(); // 交易幣種
ChkValue = Request[ " checkvalue "].Trim();
OrderStatus = Request[ " status "].Trim(); // 訂單狀態
GateId = Request[ " GateId "].Trim(); // 支付網關號
Priv1 = Request[ " Priv1 "].Trim(); // 商戶私有域
/// 檢驗是否是銀聯chinapay返回的交易數據
bolCheck = cpy.getCheck(MerId,OrdId,TransAmt,CuryId,TransDate,TransType,OrderStatus,ChkValue);
if (bolCheck){
if (OrderStatus == " 1001 ") // 交易成功
{
string myOrderID = OrdId.Replace( " 12345 ", string.Empty); // 移除商戶號后正好是我系統的訂單號
// 更新訂單表
OrderDetailBLL bll = new OrderDetailBLL();
bll.UpdateStateAll(myOrderID); // 訂單號
}
}
}
三、需要注意的地方
1. 后台接受頁面驗證簽名后還要判斷下訂單狀態 只有1001狀態才是成功交易,退款其他 要看文檔
2. 商戶提交給ChinaPay的交易訂單號,訂單號的第五至第九位必須是商戶號的最后五位(04版的,現在07版不用這樣做了),即“12345”;16位長度
例如商家號是: 8080805801123456 則提交的訂單號必須如下形式
例如 2012123450000000 ;
這里你要看着 怎么處理比較好,根據這個訂單號 能對應上,你網站里面的訂單號
我的訂單號生成規則是
訂單號=年數后2位+月數2位+天2位+五位自增數(不夠補0);
例如 :12030100001; //12年3月1號 第00001個單子,能看出當天的銷售量 也就是說 每天售量最大值是99999,一般小商場足夠用了。
