银联支付 Chinapay 在.net下的使用总结

一、 准备文件

文档资料

 

根据  客户提供文档《CHINAPAY商户控制台使用手册 》登陆 http://console.chinapay.com/newgms 需要客户提供 商户号,操作员号及密码)

下载

 

解压文件后得到如下文件

 

还需要2keyMerPrK.keyPgPubk.key)文件,分别是商户私匙和公匙,需要客户签订合同后银联才提供。

二、安装部署

1.    ChinaPay.dllCPNPC.dllnetpay.dll复制bin

2.    注册Chinapay.dllCPNPC.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;
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( 04),  " 12345 ", orderID.Substring( 4));  // 订单前四位+商家最后五位+订单后七位
             return orderid;
        }

         // 返回交易金额
          private  string getTransAmt( string count)
        {
             string moneyCount = count.ToString().Replace( " . """);
             return moneyCount.PadLeft( 12' 0 ');
        }
    }

 

5.    下面的需要解决的就是写四个页面(支付页,银行选择页面,后台接受处理页和用户支付成功后跳转页),银行选择页面,主要是自己定义图标,这里目的就是为了选择不同的网关来对应不同的银行.罗列出常用的银行。

   

后台接受页面
protected  void Page_Load( object sender, EventArgs e)
    {
        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; //1231 00001个单子,能看出当天的销售量 也就是说 每天售量最大值是99999,一般小商场足够用了。

 

 

 

你可能感兴趣的:(.net)