• .NET微信扫码支付模式二API接口开发测试


    主要实现微信扫码支付,官网的SDKdemo 就不要使用 一直不能调试通过的,还是自己按照API接口文档一步一步来实现,吐槽下微信一点责任感都木有,能不能demo搞个正常的吗,不要坑惨了一大群码农们有点社会责任感吧 还是多学学你的Alibaba 直接上干货

    具体文档接口都直接参考文档说明干

    具体代码一步一步呈上

    Index.aspx 显示二维码页面:

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <meta http-equiv="content-type" content="text/html;image/gif;charset=utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1" /> 
        <title>微信支付样例-扫码支付</title>
    </head>
    <body>
        
        <div style="margin-left: 10px;color:#00CD00;font-size:30px;font-weight: bolder;">扫码支付模式二</div><br/>
        <asp:Image ID="Image2" runat="server" style="200px;height:200px;"/>
        
    </body>
     </html>
    protected void Page_Load(object sender, EventArgs e)
        {
            //支付金额
            string PayPrice = Request.GetString("payprice").ToString("filtersql");
            //支付单号
            string Payorder = Request.GetString("payorder").ToString("filtersql");
            //公众号jsapi支付 H5支付传参数
            string Openid = Request.GetString("openid").ToString("filtersql");
            //扫码支付 模式二
            string productId = Request.GetString("productId").ToString("filtersql");
            
                     WechatPayHelper wxpay = new WechatPayHelper();
                
                int total_fee = (Convert.ToInt32(decimal.Parse("0.01") * 100)); 
                          //扫码支付模式二 Native   Pay  trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义
    主要参数依次是 订单号 金额 openid 公众号 产品productid
    string return_response = wxpay.GetUnifiedOrderResultNative("2017100882002", total_fee, "财政专费", "oC88888JeOjjkgvlWf6p999Jgu4", "456888888"); //将url生成二维码图片 Image2.ImageUrl = "http://localhost:1200/NotivePayAPI/MakeQRCode.aspx?data=" + HttpUtility.UrlEncode(return_response);
    public class WechatPayHelper
    {
        private string RequestUrl = "";
    private string key = ""; private string appid = "";//应用ID private string mch_id = "";//商户号 private string nonce_str = "";//随机字符串 private string sign = "";//签名 // private string body = "";//商品描述 // private string out_trade_no = "";//商户订单号 private string spbill_create_ip = "";//终端IP private string notify_url = "";//通知地址 private string trade_type = "";//交易类型 private string pay_url = ""; //字符编码格式 目前支持 utf-8 private string input_charset = "utf-8"; //签名方式 private string sign_type = "MD5"; public WechatPayHelper() { HttpContext Context = System.Web.HttpContext.Current; DataTable dt = null; //native 扫码支付配置 读取配置文件XML string strXML = "Wechat_Pay_Native.xml"; ////////////////////////////////////////////////// object objValue = Common.DataCache.GetCache(strXML); if (objValue == null) { dt = GetConfigXml("//Config//PayConfig/" + strXML); Common.DataCache.SetCache(strXML, dt); } else { dt = (DataTable)objValue; } if (dt != null) { appid = dt.Rows[0]["appid"].ToString(); mch_id = dt.Rows[0]["mch_id"].ToString(); notify_url = dt.Rows[0]["notify_url"].ToString(); pay_url = dt.Rows[0]["pay_url"].ToString(); spbill_create_ip = GetUserIp(); nonce_str=StrRodamNo(16); trade_type = dt.Rows[0]["trade_type"].ToString(); key = dt.Rows[0]["key"].ToString(); } } /// <summary> /// 生成直接支付url 调用统一下单,获得下单结果 扫码支付模式二 支付url有效期为2小时, /// </summary> /// <param name="out_trade_no"></param> /// <param name="total_fee"></param> /// <param name="body"></param> /// <returns></returns> public string GetUnifiedOrderResultNative(string out_trade_no, int total_fee, string body, string openid, string productId) { //请求业务参数详细 StringBuilder sb = new StringBuilder(); sb.AppendFormat("<xml><appid>{0}</appid><mch_id>{1}</mch_id> <body>{2}</body><nonce_str>{3}</nonce_str>", appid, mch_id, body, nonce_str); sb.AppendFormat("<out_trade_no>{0}</out_trade_no><total_fee>{1}</total_fee> <spbill_create_ip>{2}</spbill_create_ip><trade_type>{3}</trade_type>", out_trade_no, total_fee.ToString(), spbill_create_ip, trade_type); sb.AppendFormat("<notify_url>{0}</notify_url>", notify_url); sb.AppendFormat("<openid>{0}</openid>", openid); sb.AppendFormat("<product_id>{0}</product_id>", productId); //把请求参数打包成数组 Dictionary<string, string> softdic = new Dictionary<string, string>(); softdic.Add("appid", appid); softdic.Add("mch_id", mch_id); softdic.Add("nonce_str", nonce_str); softdic.Add("body", body); softdic.Add("out_trade_no", out_trade_no); softdic.Add("total_fee", total_fee.ToString()); softdic.Add("spbill_create_ip", spbill_create_ip); softdic.Add("trade_type", trade_type); softdic.Add("notify_url", notify_url); softdic.Add("openid", openid); softdic.Add("product_id", productId); //请求参数体 string strRequest = ""; //加密签名 string strSign = MakeSignData(softdic, ref strRequest); strRequest += "&sign=" + strSign; //打包xml sb.AppendFormat("<sign>{0}</sign></xml>", strSign); //发送请求 string strResponse = RequestWechatpay(sb.ToString()); //URLDECODE返回的信息 Encoding code = Encoding.GetEncoding(input_charset); strResponse = HttpUtility.UrlDecode(strResponse, code); string ResponseURL = ReadXmlNode(strResponse);//获得统一下单接口返回的二维码链接code_url return ResponseURL; } /// <summary> /// 签名原始串 /// </summary> /// <param name="dicParm">所有非空参数</param> /// <param name="strQueryString">请求串</param> /// <returns>签名串</returns> public string MakeSignData(Dictionary<string, string> dicParm, ref string strQueryString) { //先排序 Dictionary<string, string> dicSort = dicParm.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value); StringBuilder sb = new StringBuilder(); //再转换成URL字符串 foreach (KeyValuePair<string, string> kvParm in dicSort) { if (null != kvParm.Value && "".CompareTo(kvParm.Value) != 0 && "sign".CompareTo(kvParm.Key) != 0 && "key".CompareTo(kvParm.Key) != 0 && "sign_type".CompareTo(kvParm.Key) != 0) { if (sb.Length > 0) { sb.Append("&"); strQueryString += "&"; } sb.Append(kvParm.Key + "=" + HttpUtility.UrlDecode(kvParm.Value)); strQueryString += kvParm.Key + "=" + HttpUtility.UrlEncode(kvParm.Value); } } //再和key拼装成字符串 sb.Append("&key=" + key); //再进行MD5加密转成大写 return MD5Create(sb.ToString(), input_charset).ToUpper(); } public static string MD5Create(string str, string charset) { string retStr; MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider(); //创建md5对象 byte[] inputBye; byte[] outputBye; //使用GB2312编码方式把字符串转化为字节数组. try { inputBye = Encoding.GetEncoding(charset).GetBytes(str); } catch (Exception ex) { inputBye = Encoding.GetEncoding("GB2312").GetBytes(str); } outputBye = m5.ComputeHash(inputBye); retStr = System.BitConverter.ToString(outputBye); retStr = retStr.Replace("-", ""); return retStr; } /// <summary> ///把请求参数信息打包发送请求微信支付地址 /// </summary> /// <param name="strRequestData">请求参数字符串(QueryString)</param> /// <returns></returns> private string RequestWechatpay(string strRequestData) { Encoding code = Encoding.GetEncoding(input_charset); //把数组转换成流中所需字节数组类型 byte[] bytesRequestData = code.GetBytes(strRequestData); //请求远程HTTP string strResult = ""; try { //设置HttpWebRequest基本信息 HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(pay_url); myReq.Method = "post"; myReq.ContentType = "text/xml"; //填充POST数据 myReq.ContentLength = bytesRequestData.Length; Stream requestStream = myReq.GetRequestStream(); requestStream.Write(bytesRequestData, 0, bytesRequestData.Length); requestStream.Close(); //发送POST数据请求服务器 HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse(); Stream myStream = HttpWResp.GetResponseStream(); //获取服务器返回信息 StreamReader reader = new StreamReader(myStream, code); StringBuilder responseData = new StringBuilder(); String line; while ((line = reader.ReadLine()) != null) { responseData.Append(line); } //释放 myStream.Close(); strResult = responseData.ToString(); } catch (Exception exp) { strResult = "报错:" + exp.Message; } return strResult; } /// <summary> /// 获得客户端的IP /// </summary> /// <returns>当前页面客户端的IP</returns> public static string GetUserIp() { string userHostAddress = HttpContext.Current.Request.UserHostAddress; if (string.IsNullOrEmpty(userHostAddress)) { userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } //最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要) if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress)) { return userHostAddress; } return "127.0.0.1"; } /// <summary> /// 检查IP地址格式 /// </summary> /// <param name="ip"></param> /// <returns></returns> public static bool IsIP(string ip) { return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?)$"); } /// <summary> /// 生成随机字母与数字 /// </summary> /// <param name="IntStr">生成长度</param> /// <returns></returns> public static string StrRodamNo(int Length) { return StrRodam(Length, false); } /// <summary> /// 生成随机字母与数字 /// </summary> /// <param name="Length">生成长度</param> /// <param name="Sleep">是否要在生成前将当前线程阻止以避免重复</param> /// <returns></returns> public static string StrRodam(int Length, bool Sleep) { if (Sleep) System.Threading.Thread.Sleep(3); char[] Pattern = new char[] { '0', '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 result = ""; int n = Pattern.Length; System.Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); for (int i = 0; i < Length; i++) { int rnd = random.Next(0, n); result += Pattern[rnd]; } return result; } #region 读取xml中的指定节点的值 /// <summary> /// 读取xml中的指定节点的值 /// </summary> private string ReadXmlNode(string filename) { string result = "调用微信服务异常"; XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.LoadXml(filename); XmlNode root = xmlDoc.SelectSingleNode("xml"); if (root != null) result = (root.SelectSingleNode("code_url")).InnerText; } catch (Exception e) { Common.Utils.WriteLogFile("ReadXmlNode:" + e.Message,""); } return result; } #endregion }

     MakeQRCode.aspx.cs   主要生成二维码 要引用 ThoughtWorks.QRCode.dll

    protected void Page_Load(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(Request.QueryString["data"]))
            {
                string str = Request.QueryString["data"];
    
                //初始化二维码生成工具
                QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
                qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
                qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
                qrCodeEncoder.QRCodeVersion = 0;
                qrCodeEncoder.QRCodeScale = 4;
    
                //将字符串生成二维码图片
                Bitmap image = qrCodeEncoder.Encode(str, Encoding.Default);
    
                //保存为PNG到内存流  
                MemoryStream ms = new MemoryStream();
                image.Save(ms, ImageFormat.Png);
    
                //输出二维码图片
                Response.BinaryWrite(ms.GetBuffer());
                Response.End();
            }
        }

     微信扫码支付异步通知结果处理

    WXNativeNotifyPage.aspx.cs

    /// <summary>
        /// 微信扫码支付异步通知结果处理 主要负责接收微信支付后台发送过来的数据,对数据进行签名验证
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //微信的API写法
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //接收从微信后台POST过来的数据
            //System.IO.Stream s = Page.Request.InputStream;
            //int count = 0;
            //byte[] buffer = new byte[1024];
            //StringBuilder builder = new StringBuilder();
            //while ((count = s.Read(buffer, 0, 1024)) > 0)
            //{
            //    builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            //}
            //s.Flush();
            //s.Close();
            //s.Dispose();
            //SZRPP.Common.Utils.WriteLogFile("接收post来的数据", "Receive data from WeChat : " + builder.ToString());
            //Dictionary<string, string> dicParam = GetInfoFromXml(builder.ToString());
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //接收从微信后台POST过来的数据
            StreamReader reader = new StreamReader(Request.InputStream);
            String xmlData = reader.ReadToEnd();
            Utils.WriteLog("接收post来的微信异步回调:" + xmlData, "微信异步回调");
            //序列化xml //转换数据格式并验证签名
            Dictionary<string, string> dicParam = GetInfoFromXml(xmlData);
            string data = "";
    
            try
            {
                //当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
                if (dicParam.ContainsKey("return_code") && dicParam["return_code"] == "SUCCESS")
                {
                    
                    WechatPayHelper wcHelper = new WechatPayHelper();
                    string strRequestData = "";
                    //对返回的参数信息进行签名
                    string strSign = wcHelper.MakeSignData(dicParam, ref strRequestData);
                    //判断返回签名是否正确
                    if (strSign == dicParam["sign"])
                    {
                        //判断业务结果
                        if ("SUCCESS" == dicParam["result_code"])
                        {
                            //////检查openid和product_id是否返回
                            if (string.IsNullOrEmpty(dicParam["openid"]) || string.IsNullOrEmpty(dicParam["product_id"]))
                            {
                                data = "<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[产品ID不存在回调数据异常]]></return_msg></xml>";
                                Response.Write(data);
                            }
    
                            //判断业务是否处理过  应该有通知日志表  先暂通过缴费表做判断
                            string out_trade_no = dicParam["out_trade_no"];//订单编号
                            
                            if (out_trade_no != null)
                            {  //自己的订单逻辑处理了 比较金额是否一致
                                OrderPay pay = payBll.Query(out_trade_no,"");
    
                                if (pay!= null)
                                {
                                    //商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。
                                    if (pay.PayPrice.Equals(decimal.Parse(dicParam["total_fee"])/100))
                                    {
                                        data = "<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[金额不一致回调数据异常]]></return_msg></xml>";
                                        Response.Write(data);
                                    }
                                    if (pay.PayStatus == 1)
                                    {
                                        //已经支付 视为处理过 直接返回
                                        data = "<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>";
                                        Response.Write(data);
                                    }
                                    else
                                    {  //收到确认后,更新订单的状态
                                        //修改支付状态
                                        if (payBll.UpdatePayStatus(out_trade_no, "1",1) > 0)
                                        {
                                           data = "<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>";
                                            Response.Write(data);
                                        }
                                    }
                                }
                                else
                                {
                                    data = "<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[系统调用超时]]></return_msg></xml>";
                                    Response.Write(data);
                                }
                            }
                        }
                        else
                        {
                            //错误信息
                            string error = dicParam["err_code"] + ":" + dicParam["err_code_des"];
                            data = "<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[系统调用超时]]></return_msg></xml>";
                            Response.Write(data);
                        }
                    }
                    else
                    {
                        data="<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[系统超时]]></return_msg></xml>";
                        Response.Write(data);
                    }
                }
    
            }
            catch (Exception ex)
            {
                Utils.WriteLog("微信异步回调异常:" + ex.Message, "异常日志");
                data = "<xml><return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[系统调用超时]]></return_msg></xml>";
                Response.Write(data);
            }
        }
        /// <summary>
        /// 把XML数据转换为Sorted<string, string>集合
        /// </summary>
        /// <param name="strxml"></param>
        /// <returns></returns>
        public Dictionary<string, string> GetInfoFromXml(string xmlstring)
        {
            Dictionary<string, string> sParams = new Dictionary<string, string>();
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xmlstring);
                XmlElement root = doc.DocumentElement;
                int len = root.ChildNodes.Count;
                for (int i = 0; i < len; i++)
                {
                    string name = root.ChildNodes[i].Name;
                    if (!sParams.ContainsKey(name))
                    {
                        sParams.Add(name.Trim(), root.ChildNodes[i].InnerText.Trim());
                    }
                }
            }
            catch (Exception ex)
            {
                
            }
            return sParams;
        }
      

    微信商户信息配置xml文件

    Wechat_Pay_Native.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <data>
      <!--接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数-->
      <notify_url>http://8.20.7.8:300/PayNotifyPage/PayNotify/WXNativeNotifyPage.aspx</notify_url>
      <pay_url>https://api.mch.weixin.qq.com/pay/unifiedorder</pay_url>
      <!--微信开放平台审核通过的应用APPID-->
      <appid>wxf88888888888</appid>
      <!--微信支付分配的商户号-->
      <mch_id>14666666662</mch_id>
      <key>16gfhhg5655jjh55ff8ff88gd</key>
      <subject>财政专费</subject>
      <trade_type>NATIVE</trade_type>
    </data>

     至此就可以完成扫码支付了

     有图有真相

    生成二维码显示

    微信扫一扫 结果

  • 相关阅读:
    SVN使用之分支、合并
    eq相等 ,ne、neq不相等 EL表达式
    PLSQL:plsql中文乱码,显示问号
    mysql中实现行号,oracle中的rowid
    安装完QQ必须要删除掉的几个恐怖文件
    关于table的一些兼容性问题
    Javascript事件绑定的几种方式
    jQuery中的一些正则匹配表达式
    将java类的泛型集合转换成json对象
    python登录豆瓣,发帖
  • 原文地址:https://www.cnblogs.com/Warmsunshine/p/8031874.html
Copyright © 2020-2023  润新知