微信支付完成后会有一个支付回调页面,处理支付完成后的事件,V3支付回调的数据形式为XML格式。
1、定义一个WxResponseHandlerV3类,处理一般构造函数,用于解析XML对象;
//xmlMap private Hashtable xmlMap;
//解析回传参数,将带有指定键和值的元素添加到 System.Collections.Hashtable 中。 public WxResponseHandlerV3(HttpContext _httpContext) { xmlMap = new Hashtable(); this.httpContext = _httpContext; Stream stream = this.httpContext.Request.InputStream; if (stream.Length > 0) { XmlDocument xmlDoc = new XmlDocument(); StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8); string strInputStream = sr.ReadToEnd(); Tools.PublicConfig.log_Append("stream length:" + stream.Length.ToString() + "this.httpContext.Request.InputStream string: " + strInputStream, "Pay/Pay_WxV3", DateTime.Now.ToString("yyyyMMdd") + ".log"); xmlDoc.LoadXml(strInputStream); XmlNode root = xmlDoc.SelectSingleNode("xml"); XmlNodeList xnl = root.ChildNodes; foreach (XmlNode xnf in xnl) { xmlMap.Add(xnf.Name, xnf.InnerText); } } if (stream != null) { stream.Close(); } }
2、验签处理
/** V3支付返回notify签名:按参数名称a-z排序,遇到空值的参数不参加签名。 //全部是 xmlMap 参数 * @return boolean */ public virtual Boolean isNotifySign() { StringBuilder sb = new StringBuilder(); ArrayList akeys = new ArrayList(xmlMap.Keys); akeys.Sort(); foreach (string k in akeys) { string v = (string)getXmlMap(k); if (null != v && "".CompareTo(v) != 0 && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0) { sb.Append(k + "=" + v + "&"); } } sb.Append("key=" + this.getPayKey()); string sign = Wxpay.MD5Util.MD5(sb.ToString()).ToUpper(); //debug信息 return getXmlMap("sign").ToUpper().Equals(sign); } /** 获取xmlMap值 */ public string getXmlMap(string parameter) { string s = (string)xmlMap[parameter]; return (null == s) ? "" : s; } /// <summary> /// 设置V3 支付密钥 /// </summary> /// <param name="key"></param> public void setPayKey(string key) { this.paykey = key; } /** 获取V3支付密钥 */ public string getPayKey() { return this.paykey; }
MD5加密方法
/// <summary> /// 获得MD5加密字符串 /// </summary> /// <param name="s">源字符串</param> /// <returns>目标字符串</returns> public static String MD5(String s) { char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; try { byte[] btInput = System.Text.Encoding.UTF8.GetBytes(s); // 获得MD5摘要算法的 MessageDigest 对象 MD5 mdInst = System.Security.Cryptography.MD5.Create(); // 使用指定的字节更新摘要 mdInst.ComputeHash(btInput); // 获得密文 byte[] md = mdInst.Hash; // 把密文转换成十六进制的字符串形式 int j = md.Length; char[] str = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[(int)(((byte)byte0) >> 4) & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new string(str); } catch { // Console.Error.WriteLine(e.StackTrace); return null; } }
3、添加回调页面
public ActionResult WxApplyPayNotify() { Response.ContentType = "text/xml"; Response.ContentEncoding = System.Text.Encoding.UTF8; Response.CacheControl = "no-cache"; bool MyBusiness = false; try { if (Request.InputStream.Length > 0) { Wxpay.WxResponseHandlerV3 res = new Wxpay.WxResponseHandlerV3(System.Web.HttpContext.Current); res.setPayKey("sdjhfksdjhfksdjfhkkjhsdkfjh");//支付秘钥 bool notifySign = res.isNotifySign();//验签 if (notifySign) { //分期支付的out_trade_no是分期订单支付请求的requestNo string requestNo = res.getXmlMap("out_trade_no"); //财付通订单号 String transaction_id = res.getXmlMap("transaction_id"); //金额,以分为单位 String total_fee = res.getXmlMap("total_fee"); // 是否关注公众账号is_subscribe 是String(1) 用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效 string is_subscribe = res.getXmlMap("is_subscribe"); //判断签名及结果 if ("SUCCESS".Equals(result_code.ToUpper())) { //支付成功,处理其他事物。。。 } else { //支付失败处理。。。 MyBusiness = true; } if (MyBusiness) { Response.Write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"); } else { Response.Write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[My Business error]]></return_msg></xml>"); } } else { Response.Write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名验证失败]]></return_msg></xml>"); } } } catch (Exception ex) { //系统异常 } return View(); }