C# 微信h5支付
阅读原文时间:2023年07月09日阅读:4

相关文档  https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1

需要准备 公众号ID、商户号、商家私钥

1、登录微信商户平台申请开通h5支付功能

2、在产品中心-开发配置添加域名配置

static string _pre_order_url = "https://api.mch.weixin.qq.com";//请求域名

      static string _appid = "";//公众账号ID
      static string _mch_id = "";//商户号
      static string _partnerKey = "";//商家私钥

     #region 微信支付
public static void WeChatIndex()
{
#region 下单
var _attach = "支付测试";
var _body = "H5支付测试";
var _nonce_str = CreateNonce_str();
var _notify_url = "https://www.baidu.com";
var _out_trade_no = Guid.NewGuid().ToString("N");
var _spbill_create_ip = GetWebClientIp()
var _total_fee = 0.01;//元为单位
var _trade_type = "MWEB";
var _scene_info = $@"{{""h5_info"": {{""type"":""Wap"",""wap_url"": ""{_notify_url}"",""wap_name"": ""{_body}""}}}}";
var _time_start = DateTime.Now.ToString("yyyyMMddHHmmss");
var _time_expire = DateTime.Now.AddHours().ToString("yyyyMMddHHmmss");

        var pre\_order\_httpResult = UnifiedOrder(\_appid, \_attach, \_body, \_mch\_id, \_nonce\_str, \_notify\_url, \_out\_trade\_no, \_spbill\_create\_ip, \_total\_fee,  
            \_trade\_type, \_scene\_info, \_time\_start, \_time\_expire);  
        var pre\_order\_resultStr = XElement.Parse(pre\_order\_httpResult);  
        var pre\_order\_result\_code = pre\_order\_resultStr.Element("return\_code").Value;  
        var pre\_order\_result\_msg = pre\_order\_resultStr.Element("return\_msg").Value;  
        if (pre\_order\_result\_code == "SUCCESS")  
        {  
            var pre\_order\_result\_mweb\_url = pre\_order\_resultStr.Element("return\_msg").Value;  
        }  
        #endregion

        #region 查询订单

        #endregion

        Console.ReadKey();  
    }

    /// <summary>  
    /// 下单  
    /// </summary>  
    /// <param name="appid">公众账号ID</param>  
    /// <param name="attach">附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据</param>  
    /// <param name="body">String(32) 商品描述 商品或支付单简要描</param>  
    /// <param name="mch\_id">商户号</param>  
    /// <param name="nonce\_str">随机字符串</param>  
    /// <param name="notify\_url">接收微信支付异步通知回调地址,不可带参,与下面的Notify对应,开发者可自定义其他url地址 </param>  
    /// <param name="out\_trade\_no">商户系统内部的订单号,32个字符内、可包含字母</param>  
    /// <param name="spbill\_create\_ip">终端ip</param>  
    /// <param name="total\_fee">收钱总额  分为单位 前台传过来后需要处理成分</param>  
    /// <param name="trade\_type">交易类型H5支付的交易类型为MWEB</param>  
    /// <param name="scene\_info">场景信息 WAP网站应用{"h5\_info": {"type":"Wap","wap\_url": "https://pay.qq.com","wap\_name": "腾讯充值"}}</param>  
    /// <param name="time\_start">交易起始时间</param>  
    /// <param name="time\_expire">交易结束时间</param>  
    /// <returns></returns>  
    static string UnifiedOrder(string appid,string attach,string body,string mch\_id,string nonce\_str,string notify\_url,string out\_trade\_no,  
        string spbill\_create\_ip,double total\_fee,string trade\_type,string scene\_info,string time\_start,string time\_expire)  
    {  
        var stringADict = new Dictionary<string, string>();  
        stringADict.Add("appid", appid);  
        stringADict.Add("attach", attach);  
        stringADict.Add("body", body);  
        stringADict.Add("mch\_id", mch\_id);  
        stringADict.Add("nonce\_str", nonce\_str);  
        stringADict.Add("notify\_url", notify\_url);  
        stringADict.Add("out\_trade\_no", out\_trade\_no);  
        stringADict.Add("spbill\_create\_ip", spbill\_create\_ip);  
        stringADict.Add("total\_fee", Math.Round(Convert.ToDecimal(total\_fee) \* , ).ToString());//元转分  
        stringADict.Add("trade\_type", trade\_type);  
        stringADict.Add("scene\_info", scene\_info);  
        stringADict.Add("time\_start", time\_start);  
        stringADict.Add("time\_expire", time\_expire);  
        var sign = Sign(stringADict, \_partnerKey);//生成签名字符串  

        //组合xml内容  
        StringBuilder strBuilder = new StringBuilder();  
        strBuilder.Append("<xml>");  
        strBuilder.Append($"<appid>{appid}</appid>");//公众号id  
        strBuilder.Append($"<attach>{attach}</attach>");//附加数据  
        strBuilder.Append($"<body>{body}</body>");//商品描述  
        strBuilder.Append($"<mch\_id>{mch\_id}</mch\_id>");//商户号  
        strBuilder.Append($"<nonce\_str>{nonce\_str}</nonce\_str>");//随机字符串  
        strBuilder.Append($"<notify\_url>{notify\_url}</notify\_url>");//接收微信支付异步通知回调地址,不可带参,与下面的Notify对应,开发者可自定义其他url地址  
        strBuilder.Append($"<out\_trade\_no>{out\_trade\_no}</out\_trade\_no>");//商户系统内部的订单号,32个字符内、可包含字母  
        strBuilder.Append($"<spbill\_create\_ip>{spbill\_create\_ip}</spbill\_create\_ip>");//终端ip  
        strBuilder.Append($"<total\_fee>{Math.Round(Convert.ToDecimal(total\_fee) \* 100, 0).ToString()}</total\_fee>");//收钱总额  分为单位 前台传过来后需要处理成分  
        strBuilder.Append($"<trade\_type>{trade\_type}</trade\_type>");//交易类型H5支付的交易类型为MWEB  
        strBuilder.Append($"<scene\_info>{scene\_info}</scene\_info>");  
        strBuilder.Append($"<time\_start>{time\_start}</time\_start>");//交易起始时间  
        strBuilder.Append($"<time\_expire>{time\_expire}</time\_expire>");//交易结束时间  
        strBuilder.Append($"<sign>{sign}</sign>");  
        strBuilder.Append("</xml>");

        //var url = \_pre\_order\_url + "/sandboxnew/pay/unifiedorder";//沙箱  
        var url = \_pre\_order\_url + "/pay/unifiedorder";  
        var pre\_order\_httpResult = HttpPostRequestXml(url, strBuilder);  
        return pre\_order\_httpResult;  
    }

    /// <summary>  
    /// 查询订单  
    /// </summary>  
    /// <param name="appid">公众账号ID</param>  
    /// <param name="mch\_id">商户号</param>  
    /// <param name="out\_trade\_no">商户系统内部的订单号或微信的订单号</param>  
    /// <param name="nonce\_str">随机字符串</param>  
    /// <returns></returns>  
    static string Orderquery(string appid,string mch\_id,string out\_trade\_no,string nonce\_str)  
    {  
        var stringADict = new Dictionary<string, string>();  
        stringADict.Add("appid", appid);  
        stringADict.Add("mch\_id", mch\_id);  
        stringADict.Add("out\_trade\_no", out\_trade\_no);  
        stringADict.Add("nonce\_str", nonce\_str);  
        var sign = Sign(stringADict, \_partnerKey);//生成签名字符串  

        //组合xml内容  
        StringBuilder strBuilder = new StringBuilder();  
        strBuilder.Append("<xml>");  
        strBuilder.Append($"<appid>{appid}</appid>");  
        strBuilder.Append($"<mch\_id>{mch\_id}</mch\_id>");  
        strBuilder.Append($"<out\_trade\_no>{out\_trade\_no}</out\_trade\_no>");  
        strBuilder.Append($"<nonce\_str>{nonce\_str}</nonce\_str>");  
        strBuilder.Append($"<sign>{sign}</sign>");  
        strBuilder.Append("</xml>");

        var url = \_pre\_order\_url + "/pay/orderquery";  
        var pre\_order\_httpResult = HttpPostRequestXml(url, strBuilder);  
        return pre\_order\_httpResult;  
    }

    /// <summary>  
    /// 发送post xml文件请求  
    /// </summary>  
    /// <param name="Url"></param>  
    /// <param name="strBuilder"></param>  
    /// <returns></returns>  
    static string HttpPostRequestXml(string Url,StringBuilder strBuilder)  
    {  
        string result = string.Empty;  
        string data = strBuilder.ToString();  
        //进行utf-8编码  
        var encoding = Encoding.GetEncoding("utf-8");  
        byte\[\] buffer = encoding.GetBytes(data);  
        //根据webURL创建HttpWebRequest对象  
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);  
        request.Method = "post";  
        //request.Headers.Add("charset:utf-8");  
        request.ContentLength = buffer.Length;  
        request.ContentType = "text/xml";

        StreamWriter myWriter = null;  
        try  
        {  
            myWriter = new StreamWriter(request.GetRequestStream());  
            myWriter.Write(data);  
        }  
        catch (Exception e)  
        {  
            Console.WriteLine(e.Message);  
        }  
        finally  
        {  
            myWriter.Close();  
        }  
        //读取服务器返回的信息  
        HttpWebResponse objResponse = (HttpWebResponse)request.GetResponse();  
        using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))  
        {  
            result = sr.ReadToEnd();  
        }  
        return result;  
    }

    private static string\[\] strs = new string\[\]  
                             {  
                              "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",  
                              "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"  
                             };

    /// <summary>  
    /// 创建随机字符串  
    /// </summary>  
    /// <returns></returns>  
    public static string CreateNonce\_str()  
    {  
        Random r = new Random();  
        var sb = new StringBuilder();  
        var length = strs.Length;  
        for (int i = ; i < ; i++)  
        {  
            sb.Append(strs\[r.Next(length - )\]);  
        }  
        return sb.ToString();  
    }

    /// <summary>  
    /// 获取终端IP地址  
    /// </summary>  
    /// <returns></returns>  
    public static string GetWebClientIp()  
    {  
        string userIP = "";  
        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 simone 090805  
            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) == )  
                return System.Web.HttpContext.Current.Request.UserHostAddress;  
            return CustomerIP;  
        }  
        catch { }  
        return userIP;  
    }

    /// <summary>  
    /// 生成签名  
    /// 签名在线验证工具:  
    /// http://mch.weixin.qq.com/wiki/tools/signverify/  
    /// </summary>  
    /// <param name="stringADict">参与签名生成的参数列表</param>  
    /// <param name="partnerKey">商家私钥</param>  
    /// <returns></returns>  
    public static string Sign(IDictionary<string, string> stringADict, string partnerKey)  
    {  
        var sb = new StringBuilder();  
        foreach (var sA in stringADict.OrderBy(x => x.Key))//参数名ASCII码从小到大排序(字典序);  
        {  
            if (string.IsNullOrEmpty(sA.Value)) continue;//参数的值为空不参与签名;  
            if (string.Compare(sA.Key, "sign", true) == ) continue;    // 参数中为签名的项,不参加计算  
            sb.Append(sA.Key).Append("=").Append(sA.Value).Append("&");  
        }  
        var string1 = sb.ToString();  
        string1 = string1.Remove(string1.Length - , );  
        sb.Append("key=").Append(partnerKey);//在stringA最后拼接上key=(API密钥的值)得到stringSignTemp字符串  
        var stringSignTemp = sb.ToString();  
        var sign = MD5Encrypt(stringSignTemp, "UTF-8").ToUpper();//对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。  
        return sign;  
    }

    /// <summary>  
    /// 用MD5加密字符串  
    /// </summary>  
    /// <param name="password">待加密的字符串</param>  
    /// <returns></returns>  
    public static string MD5Encrypt(string password, string encoding)  
    {  
        MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();  
        byte\[\] hashedDataBytes;  
        hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding(encoding).GetBytes(password));  
        StringBuilder tmp = new StringBuilder();  
        foreach (byte i in hashedDataBytes)  
        {  
            tmp.Append(i.ToString("x2"));  
        }  
        return tmp.ToString();  
    }  
    #endregion

    /// <summary>  
    /// 微信支付异步回调(修改请参考相关文档)  
    /// </summary>  
    /// <returns></returns>  
    public ActionResult WechatpayAsynchronousReception()  
    {  
        StreamReader reader = new StreamReader(Request.InputStream);  
        string xmlData = reader.ReadToEnd();  
        new LogEntity().SetLogMessage("xmlData:" + xmlData);  
        var xmlDataStr = XElement.Parse(xmlData);  
        StringBuilder strBuilder = new StringBuilder();//组合xml内容

        string return\_code = "";//返回状态码  
        string appid = "";//公众账号ID  
        string mch\_id = "";//商户号  
        string nonce\_str = "";//随机字符串  
        string result\_code = "";//业务结果  
        string transaction\_id = "";//微信支付订单号  
        string out\_trade\_no = "";//商户订单号

        return\_code = xmlDataStr.Element("return\_code").Value;  
        if (return\_code == "SUCCESS")  
        {  
            appid = xmlDataStr.Element("appid").Value;  
            mch\_id = xmlDataStr.Element("mch\_id").Value;  
            nonce\_str = xmlDataStr.Element("nonce\_str").Value;  
            result\_code = xmlDataStr.Element("result\_code").Value;  
            transaction\_id = xmlDataStr.Element("transaction\_id").Value;  
            out\_trade\_no = xmlDataStr.Element("out\_trade\_no").Value;  
            var msgStr = $@"WechatpayAsynchronousReception:  out\_trade\_no={out\_trade\_no},trade\_no={transaction\_id},trade\_status={result\_code},DateTimeNow={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}";  
            new LogEntity().SetLogMessage(msgStr);

            var model = new PaymentRecordModel();  
            model.Out\_trade\_no = out\_trade\_no;  
            model.Trade\_no = transaction\_id;  
            model.State = result\_code == "SUCCESS" ? 1 : 2;  
            var facade = new TrainingFacade();  
            var result = new ReturnInfoDTO();  
            result = facade.OpreationPaymentRecord(model);  
            if (result.IsSuccess && model.State == 1)  
            {  
                return Json(new { return\_code = "SUCCESS", return\_msg = "OK" }, "text/xml", Encoding.UTF8);  
            }  
        }  
        return Json(new { return\_code = "FAIL", return\_msg = "NO" }, "text/xml", Encoding.UTF8);  
    }

需要注意的是你要测支付必须在你配置的域名下才能正常跳转支付页面,否则就会“商家参数格式有误,请联系商家解决”或“商家存在未配置参数,请联系商家解决”