微信小程序支付功能 C# .NET开发

来源:互联网 发布:期刊投稿数据库要求 编辑:程序博客网 时间:2024/06/08 15:01

微信小程序支付功能的开发的时候坑比较多,不过对于钱的事谨慎也是好事。网上关于小程序支付的实例很多,但是大多多少有些问题,C#开发的更少。此篇文档的目的是讲开发过程中遇到的问题做一个备注,也方便其他开发的同学作为参考!


       1、首先建议把官方文档支付部分看上三遍,每个细节都不要放过,因为任何一个点和微信要求不符都会导致支付不成功。https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=3_1

      2、经过验证的微信支付功能,会需要一些商户号、支付秘钥等,不要搞混。

     3、经常遇到的是“签名错误”,请仔细看需要传送的xml参数及取值规则是否符合微信规则。微信有个验证工具可以验证发送的xml字段是否合法。


下面上代码:


web.config

    <add key="ConnectionString" value="server=127.0.0.1;database=;uid=sa;pwd="/>    <add key="ConnectionString2" value="server=127.0.0.1;database=codematic2;uid=sa;pwd=1"/>    <add key="appid" value=""/>//appid    <add key="secret" value=""/>//小程序秘钥    <add key="mch_id" value=""/>//商户号    <add key="key" value=""/>//支付秘钥    <add key="ip" value=""/>//服务器IP    <add key="PayResulturl" value=""/>//微信返回接收信息的url地址  </appSettings>
支付后台xiadan.ashx

<%@ WebHandler Language="C#" Class="xiadan" %>using System;using System.Web;using System.Net;using System.IO;using System.Configuration;using Maticsoft.Model;using Maticsoft.BLL;using System.Security.Cryptography;using System.Text;using System.Xml.Serialization;using System.Xml;using System.Collections.Generic;using System.Data;using System.Net.Security;using System.Security.Cryptography.X509Certificates;using System.Linq;using Newtonsoft.Json;public class xiadan : IHttpHandler{    public void ProcessRequest(HttpContext context)    {        context.Response.ContentType = "text/plain";        string openid = context.Request.Params["openid"];        string ordertime = context.Request.Params["ordertime"];        string appid = ConfigurationManager.AppSettings["appid"];        string secret = ConfigurationManager.AppSettings["secret"];        string key = ConfigurationManager.AppSettings["key"];        string mch_id = ConfigurationManager.AppSettings["mch_id"];        string ip = ConfigurationManager.AppSettings["ip"];        string PayResulturl = ConfigurationManager.AppSettings["PayResulturl"];        string roomid = context.Request.Params["roomid"];        string aa = "-押金";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。        string strcode = aa;        byte[] buffer = Encoding.UTF8.GetBytes(strcode);        string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);        string totalfee = context.Request.Params["totalfee"];        string output = "";        if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))        {            //OrderInfo order = new OrderInfo();            //order.appid = appid;            System.Random Random = new System.Random();            var dic = new Dictionary<string, string>{    {"appid", appid},    {"mch_id", mch_id},    {"nonce_str", GetRandomString(20)/*Random.Next().ToString()*/},    {"body",body},    {"out_trade_no",roomid + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Random.Next(999).ToString()},//商户自己的订单号码    {"total_fee",totalfee},    {"spbill_create_ip",ip},//服务器的IP地址    {"notify_url",PayResulturl},//异步通知的地址,不能带参数    {"trade_type","JSAPI" },    {"openid",openid}};      //加入签名            dic.Add("sign", GetSignString(dic));            var sb = new StringBuilder();            sb.Append("<xml>");            foreach (var d in dic)            {                sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");            }            sb.Append("</xml>");            var xml = new XmlDocument();            //  xml.LoadXml(GetPostString("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString()));            CookieCollection coo = new CookieCollection();            Encoding en = Encoding.GetEncoding("UTF-8");            HttpWebResponse response = CreatePostHttpResponse("https://api.mch.weixin.qq.com/pay/unifiedorder", sb.ToString(), en);            //打印返回值            Stream stream = response.GetResponseStream();   //获取响应的字符串流            StreamReader sr = new StreamReader(stream); //创建一个stream读取流            string html = sr.ReadToEnd();   //从头读到尾,放到字符串html                                            //Console.WriteLine(html);            xml.LoadXml(html);            //对请求返回值 进行处理            var root = xml.DocumentElement;            DataSet ds = new DataSet();            StringReader stram = new StringReader(html);            XmlTextReader reader = new XmlTextReader(stram);            ds.ReadXml(reader);            string return_code = ds.Tables[0].Rows[0]["return_code"].ToString();            if (return_code.ToUpper() == "SUCCESS")            {                //通信成功                string result_code = ds.Tables[0].Rows[0]["result_code"].ToString();//业务结果                if (result_code.ToUpper() == "SUCCESS")                {                    var res = new Dictionary<string, string>{    {"appId", appid},    {"timeStamp", GetTimeStamp()},    {"nonceStr", dic["nonce_str"]},    {"package",  "prepay_id="+ds.Tables[0].Rows[0]["prepay_id"].ToString()},    {"signType", "MD5"}};                    //在服务器上签名                    res.Add("paySign", GetSignString(res));                    // string signapp = res.ToString();                    string signapp = JsonConvert.SerializeObject(res);                    if ((context.Request.Params["openid"] != null) && (context.Request.Params["openid"] != ""))                    {                     //存储订单信息                    Maticsoft.Model.order_history oh = new Maticsoft.Model.order_history();                    //oh.shop_id =                    oh.room_id = Convert.ToInt32(roomid);                    oh.pay_price = Convert.ToDecimal(totalfee);                    oh.out_trade_no = dic["out_trade_no"];                    oh.order_timestart = Convert.ToDateTime(ordertime);                    oh.openid = openid;                    oh.creating_date = DateTime.Now;                    Maticsoft.BLL.order_history bll = new Maticsoft.BLL.order_history();                    bll.Add(oh);                }                context.Response.Write(signapp);            }        }    }    context.Response.Write(output);    }public bool IsReusable{    get    {        return false;    }}public string GetMd5Hash(String input){    if (input == null)    {        return null;    }    MD5 md5Hash = MD5.Create();    // 将输入字符串转换为字节数组并计算哈希数据      byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));    // 创建一个 Stringbuilder 来收集字节并创建字符串      StringBuilder sBuilder = new StringBuilder();    // 循环遍历哈希数据的每一个字节并格式化为十六进制字符串      for (int i = 0; i < data.Length; i++)    {        sBuilder.Append(data[i].ToString());    }    // 返回十六进制字符串      return sBuilder.ToString();}/// <summary>  /// 对象序列化成 XML String  /// </summary>  public static string XmlSerialize<T>(T obj){    string xmlString = string.Empty;    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));    using (MemoryStream ms = new MemoryStream())    {        xmlSerializer.Serialize(ms, obj);        xmlString = Encoding.UTF8.GetString(ms.ToArray());    }    return xmlString;}/// <summary>/// 从字符串里随机得到,规定个数的字符串./// </summary>/// <param name="allChar"></param>/// <param name="CodeCount"></param>/// <returns></returns>public static string GetRandomString(int CodeCount){    string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";    string[] allCharArray = allChar.Split(',');    string RandomCode = "";    int temp = -1;    Random rand = new Random();    for (int i = 0; i < CodeCount; i++)    {        if (temp != -1)        {            rand = new Random(temp * i * ((int)DateTime.Now.Ticks));        }        int t = rand.Next(allCharArray.Length - 1);        while (temp == t)        {            t = rand.Next(allCharArray.Length - 1);        }        temp = t;        RandomCode += allCharArray[t];    }    return RandomCode;}public static string GetWebClientIp(){    string userIP = "IP";    try    {        if (System.Web.HttpContext.Current == null    || System.Web.HttpContext.Current.Request == null    || System.Web.HttpContext.Current.Request.ServerVariables == null)            return "";        string CustomerIP = "";        //CDN加速后取到的IP           CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];        if (!string.IsNullOrEmpty(CustomerIP))        {            return CustomerIP;        }        CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];        if (!String.IsNullOrEmpty(CustomerIP))            return CustomerIP;        if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)        {            CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];            if (CustomerIP == null)                CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];        }        else        {            CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];        }        if (string.Compare(CustomerIP, "unknown", true) == 0)            return System.Web.HttpContext.Current.Request.UserHostAddress;        return CustomerIP;    }    catch { }    return userIP;}private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors){    return true; //总是接受   }public static HttpWebResponse CreatePostHttpResponse(string url, string datas, Encoding charset){    HttpWebRequest request = null;    //HTTPSQ请求    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);    request = WebRequest.Create(url) as HttpWebRequest;    request.ProtocolVersion = HttpVersion.Version10;    request.Method = "POST";    request.ContentType = "application/x-www-form-urlencoded";    //如果需要POST数据       //if (!(parameters == null || parameters.Count == 0))    //{    StringBuilder buffer = new StringBuilder();    //int i = 0;    //foreach (string key in parameters.Keys)    //{    //    if (i > 0)    //    {    //        buffer.AppendFormat("&{0}={1}", key, parameters[key]);    //    }    //    else    //    {    //        buffer.AppendFormat("{0}={1}", key, parameters[key]);    //    }    //    i++;    //}    buffer.AppendFormat(datas);    byte[] data = charset.GetBytes(buffer.ToString());    using (Stream stream = request.GetRequestStream())    {        stream.Write(data, 0, data.Length);    }    //}    return request.GetResponse() as HttpWebResponse;}public string GetSignString(Dictionary<string, string> dic){    string key = System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();//商户平台 API安全里面设置的KEY  32位长度                                                                                                //排序    dic = dic.OrderBy(d => d.Key).ToDictionary(d => d.Key, d => d.Value);    //连接字段    var sign = dic.Aggregate("", (current, d) => current + (d.Key + "=" + d.Value + "&"));    sign += "key=" + key;    //MD5    // sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper();    System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();    sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-", null);    return sign;}/// <summary>  /// 获取时间戳  /// </summary>  /// <returns></returns>  public static string GetTimeStamp(){    TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);    return Convert.ToInt64(ts.TotalSeconds).ToString();}}



      微信返回信息接收后台页面notify_url.ashx

<%@ WebHandler Language="C#" Class="notify_url" %>using System;using System.Web;using System.Collections.Generic;using System.Data;using System.IO;using System.Text;using System.Xml;using System.Net;public class notify_url : IHttpHandler{    public string return_result = "";    public void ProcessRequest(HttpContext context)    {        context.Response.ContentType = "text/plain";        context.Response.Write("Hello World");        String xmlData = getPostStr();//获取请求数据        if (xmlData == "")        {        }        else        {            var dic = new Dictionary<string, string>{    {"return_code", "SUCCESS"},    {"return_msg","OK"}};            var sb = new StringBuilder();            sb.Append("<xml>");            foreach (var d in dic)            {                sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");            }            sb.Append("</xml>");            //把数据重新返回给客户端            DataSet ds = new DataSet();            StringReader stram = new StringReader(xmlData);            XmlTextReader datareader = new XmlTextReader(stram);            ds.ReadXml(datareader);            if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS")            {                string wx_appid = "";//微信开放平台审核通过的应用APPID                string wx_mch_id = "";//微信支付分配的商户号                string wx_nonce_str = "";// 随机字符串,不长于32位                string wx_sign = "";//签名,详见签名算法                string wx_result_code = "";//SUCCESS/FAIL                string wx_return_code = "";                string wx_openid = "";//用户在商户appid下的唯一标识                string wx_is_subscribe = "";//用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效                string wx_trade_type = "";// APP                string wx_bank_type = "";// 银行类型,采用字符串类型的银行标识,银行类型见银行列表                string wx_fee_type = "";// 货币类型,符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型                string wx_transaction_id = "";//微信支付订单号                string wx_out_trade_no = "";//商户系统的订单号,与请求一致。                string wx_time_end = "";// 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则                int wx_total_fee = -1;// 订单总金额,单位为分                int wx_cash_fee = -1;//现金支付金额订单现金支付金额,详见支付金额                #region  数据解析                //列 是否存在                string signstr = "";//需要前面的字符串                                    //wx_appid                if (ds.Tables[0].Columns.Contains("appid"))                {                    wx_appid = ds.Tables[0].Rows[0]["appid"].ToString();                    if (!string.IsNullOrEmpty(wx_appid))                    {                        signstr += "appid=" + wx_appid;                    }                }                //wx_bank_type                if (ds.Tables[0].Columns.Contains("bank_type"))                {                    wx_bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString();                    if (!string.IsNullOrEmpty(wx_bank_type))                    {                        signstr += "&bank_type=" + wx_bank_type;                    }                }                //wx_cash_fee                if (ds.Tables[0].Columns.Contains("cash_fee"))                {                    wx_cash_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["cash_fee"].ToString());                    signstr += "&cash_fee=" + wx_cash_fee;                }                //wx_fee_type                if (ds.Tables[0].Columns.Contains("fee_type"))                {                    wx_fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString();                    if (!string.IsNullOrEmpty(wx_fee_type))                    {                        signstr += "&fee_type=" + wx_fee_type;                    }                }                //wx_is_subscribe                if (ds.Tables[0].Columns.Contains("is_subscribe"))                {                    wx_is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString();                    if (!string.IsNullOrEmpty(wx_is_subscribe))                    {                        signstr += "&is_subscribe=" + wx_is_subscribe;                    }                }                //wx_mch_id                if (ds.Tables[0].Columns.Contains("mch_id"))                {                    wx_mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString();                    if (!string.IsNullOrEmpty(wx_mch_id))                    {                        signstr += "&mch_id=" + wx_mch_id;                    }                }                //wx_nonce_str                if (ds.Tables[0].Columns.Contains("nonce_str"))                {                    wx_nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString();                    if (!string.IsNullOrEmpty(wx_nonce_str))                    {                        signstr += "&nonce_str=" + wx_nonce_str;                    }                }                //wx_openid                if (ds.Tables[0].Columns.Contains("openid"))                {                    wx_openid = ds.Tables[0].Rows[0]["openid"].ToString();                    if (!string.IsNullOrEmpty(wx_openid))                    {                        signstr += "&openid=" + wx_openid;                    }                }                //wx_out_trade_no                if (ds.Tables[0].Columns.Contains("out_trade_no"))                {                    wx_out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString();                    if (!string.IsNullOrEmpty(wx_out_trade_no))                    {                        signstr += "&out_trade_no=" + wx_out_trade_no;                    }                }                //wx_result_code                 if (ds.Tables[0].Columns.Contains("result_code"))                {                    wx_result_code = ds.Tables[0].Rows[0]["result_code"].ToString();                    if (!string.IsNullOrEmpty(wx_result_code))                    {                        signstr += "&result_code=" + wx_result_code;                    }                }                //wx_result_code                 if (ds.Tables[0].Columns.Contains("return_code"))                {                    wx_return_code = ds.Tables[0].Rows[0]["return_code"].ToString();                    if (!string.IsNullOrEmpty(wx_return_code))                    {                        signstr += "&return_code=" + wx_return_code;                    }                }                //wx_sign                 if (ds.Tables[0].Columns.Contains("sign"))                {                    wx_sign = ds.Tables[0].Rows[0]["sign"].ToString();                    //if (!string.IsNullOrEmpty(wx_sign))                    //{                    //    signstr += "&sign=" + wx_sign;                    //}                }                //wx_time_end                if (ds.Tables[0].Columns.Contains("time_end"))                {                    wx_time_end = ds.Tables[0].Rows[0]["time_end"].ToString();                    if (!string.IsNullOrEmpty(wx_time_end))                    {                        signstr += "&time_end=" + wx_time_end;                    }                }                //wx_total_fee                if (ds.Tables[0].Columns.Contains("total_fee"))                {                    wx_total_fee = Convert.ToInt32(ds.Tables[0].Rows[0]["total_fee"].ToString());                    signstr += "&total_fee=" + wx_total_fee;                }                //wx_trade_type                if (ds.Tables[0].Columns.Contains("trade_type"))                {                    wx_trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString();                    if (!string.IsNullOrEmpty(wx_trade_type))                    {                        signstr += "&trade_type=" + wx_trade_type;                    }                }                //wx_transaction_id                if (ds.Tables[0].Columns.Contains("transaction_id"))                {                    wx_transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString();                    if (!string.IsNullOrEmpty(wx_transaction_id))                    {                        signstr += "&transaction_id=" + wx_transaction_id;                    }                }                #endregion                //追加key 密钥                signstr += "&key=" + System.Web.Configuration.WebConfigurationManager.AppSettings["key"].ToString();                //签名正确                string orderStrwhere = "ordernumber='" + wx_out_trade_no + "'";                if (wx_sign == System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(signstr, "MD5").ToUpper())                {                    //签名正确   处理订单操作逻辑                }                else                {                    //追加备注信息                }            }            else            {                // 返回信息,如非空,为错误原因  签名失败 参数格式校验错误                string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString();            }            return_result = sb.ToString();        }    }    public bool IsReusable    {        get        {            return false;        }    }    //获得Post过来的数据    public string getPostStr()    {        Int32 intLen = Convert.ToInt32(System.Web.HttpContext.Current.Request.InputStream.Length);        byte[] b = new byte[intLen];        System.Web.HttpContext.Current.Request.InputStream.Read(b, 0, intLen);        return System.Text.Encoding.UTF8.GetString(b);    }}