zoukankan      html  css  js  c++  java
  • MVC 微信支付

    微信支付方式有好几种,俺研究了跟自己需要的两种,即:JS API网页支付和Native原生支付,这两个名词实在是有目的难懂。JS API网页支付:我的理解是在微信浏览器里面可以调用微信支付控件的支付方式;Native 原生支付则是在其他浏览器里面通过扫描二维码进行支付的方式。相关技术文档和术语有很多是地球人比较难理解的,需要试验,我把我的试验成功贴一下。

    第一步,首先在公众账号配置微信支付,如下图,并把微信号添加到测试白名单。建议测试目录里面的文字全部小写,腾讯居然要求网址的大小写也要匹配。

    image

    第二步,统一下单。就是在微信支付服务后台生成预支付交易单,返回正确的预支付交易标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.Script.Serialization;
    using Zmm.Wx.HttpUtility;
    
    namespace Zmm.Wx.MP.TenPay
    {
        public class UnifierOrderResult
        {
            public string return_code { get; set; }
            public string return_msg { get; set; }
            public string appid { get; set; }
            public string mch_id { get; set; }
            public string device_info { get; set; }
            public string nonce_str { get; set; }
            public string sign { get; set; }
            public string result_code { get; set; }
            public string err_code { get; set; }
            public string err_code_des { get; set; }
            public string trade_type { get; set; }
            public string prepay_id { get; set; }
            public string code_url { get; set; }
    
            public override string ToString()
            {
                List<string> items = new List<string>();
                var props = this.GetType().GetProperties();
                foreach (var prop in props)
                {
                    var val = prop.GetValue(this);
                    if (val != null && !string.IsNullOrEmpty(val.ToString()))
                        items.Add(prop.Name + "=" + val);
                }
                return string.Join(";", items);
            }
            class RequirePara
            {
                public string appid { get; set; }
                public string mch_id { get; set; }
                public string nonce_str { get; set; }
                public string body { get; set; }
                public string detail { get; set; }
                public string attach { get; set; }
                public string out_trade_no { get; set; }
                public int total_fee { get; set; }
                public string spbill_create_ip { get; set; }
                public string notify_url { get; set; }
                public string trade_type { get; set; }
                public string product_id { get; set; }
                public string openid { get; set; }
                public string GetXml()
                {
                    List<string> items = new List<string>();
                    var props = this.GetType().GetProperties();
                    foreach (var prop in props)
                    {
                        var val = prop.GetValue(this);
                        if (val != null && !string.IsNullOrEmpty(val.ToString()))
                            items.Add(prop.Name + "=" + val);
                    }
                    items.Sort();
                    StringBuilder sb = new StringBuilder();
                    foreach (var item in items)
                        sb.Append(item + "&");
                    sb.Append("key=keyvalue");  
                    string sign = MD5Util.GetMD5(sb.ToString()).ToUpper();
                    return string.Format("<xml>{0}<sign>{1}</sign></xml>", ToXml(), sign);
                }
    
                string ToXml()
                {
                    List<string> items = new List<string>();
                    var props = this.GetType().GetProperties();
                    foreach (var prop in props)
                    {
                        var val = prop.GetValue(this);
                        if (val != null && !string.IsNullOrEmpty(val.ToString()))
                            items.Add(string.Format("<{0}>{1}</{0}>", prop.Name, val));
                    }
                    items.Sort();
                    return string.Join("", items);
    
                }
    
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="body">商品描述</param>
            /// <param name="detail">商品详情</param>
            /// <param name="attach">附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据</param>
            /// <param name="out_trade_no">商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号</param>
            /// <param name="total_fee">订单总金额,只能为整数,单位为分</param>
            /// <param name="spbill_create_ip">APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。</param>
            /// <param name="notify_url">接收微信支付异步通知回调地址</param>
            /// <param name="trade_type">交易类型,取值如下:JSAPI,NATIVE,APP,WAP</param>
            /// <param name="product_id">trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。  </param>
            /// <param name="openid">trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。</param>
            /// <returns></returns>
            public static UnifierOrderResult Get(string body, string detail, string attach, string out_trade_no, int total_fee, string spbill_create_ip, string notify_url, string trade_type, string product_id, string openid)
            {
    
                const string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    
                RequirePara para = new RequirePara()
                {
                    appid = "appid",
                    mch_id = "partnerid",
                    nonce_str = DateTime.Now.Ticks.ToString(),
                    body = body,
                    detail = detail,
                    attach = attach,
                    out_trade_no = out_trade_no,
                    total_fee = total_fee,
                    spbill_create_ip = spbill_create_ip,
                    notify_url = notify_url,
                    trade_type = trade_type,
                    product_id = product_id,
                    openid = openid
                };
    
    
    
                string retval = HttpUtility.RequestUtility.HttpPost(url, para.GetXml());
                UnifierOrderResult ret = new UnifierOrderResult();
                ret.FillEntityWithXml(retval);
                return ret;
            }
        }
    
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Zmm.Wx.MP.TenPay
    {
        public class TenpayData
        {
            const string appId = "appid";
            public string nonceStr { get; set; }
            public string package { get; set; }
            const string signType = "MD5";
            public string timeStamp { get; set; }
            public string paySign { get; set; }
    
            public void Execute(string prepay_id)
            {
                nonceStr = DateTime.Now.Ticks.ToString();
                package = "prepay_id=" + prepay_id;
                
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString();
    
                var str = string.Format("appId={0}&nonceStr={1}&package={2}&signType={3}&timeStamp={4}&key=154f138bf4407a9c07ac7240a2b7135f", appId, nonceStr, package, signType, timeStamp);
                
                 
                paySign = MD5Util.GetMD5(str);
    
    
            }
    
    
        }
    }
    
    using System;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Zmm.Wx.MP.TenPay
    {
        /// <summary>
        /// MD5Util 的摘要说明。
        /// </summary>
        public class MD5Util
        {
            public MD5Util()
            {
                //
                // TODO: 在此处添加构造函数逻辑
                //
            }
    
            /** 获取大写的MD5签名结果 */
            public static string GetMD5(string encypStr)
            {
                string retStr;
                MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();
    
                //创建md5对象
                byte[] inputBye;
                byte[] outputBye;
    
                //使用GB2312编码方式把字符串转化为字节数组.
                try
                {
                    inputBye = Encoding.UTF8.GetBytes(encypStr);
                }
                catch 
                {
                    inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
                }
                outputBye = m5.ComputeHash(inputBye);
    
                retStr = System.BitConverter.ToString(outputBye);
                retStr = retStr.Replace("-", "").ToUpper();
                return retStr;
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Zmm.Wx.MP.TenPay
    {
        public class OrderResult
        {
            //Help:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_7
            /// <summary>
            /// 返回状态码 SUCCESS/FAIL 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 
            /// </summary>
            public string return_code { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string return_msg { get; set; }
            public string appid { get; set; }
            public string mch_id { get; set; }
            public string device_info { get; set; }
            public string nonce_str { get; set; }
            public string sign { get; set; }
            public string result_code { get; set; }
            public string err_code { get; set; }
            public string err_code_des { get; set; }
            public string openid { get; set; }
            public string is_subscribe { get; set; }
            public string trade_type { get; set; }
            public string bank_type { get; set; }
            public string CMC { get; set; }
            public string total_fee { get; set; }
            public string fee_type { get; set; }
            public string cash_fee { get; set; }
            public string cash_fee_type { get; set; }
            public string coupon_fee { get; set; }
            public string coupon_count { get; set; }
            //public string coupon_batch_id_$n {get;set;}
            //public string coupon_id_$n {get;set;}
            //public string coupon_fee_$n {get;set;}
            public string transaction_id { get; set; }
            public string out_trade_no { get; set; }
            public string attach { get; set; }
            public string time_end { get; set; }
    
            public override string ToString()
            {
                List<string> items = new List<string>();
                var props = this.GetType().GetProperties();
                foreach (var prop in props)
                {
                    var val = prop.GetValue(this);
                    if (val != null && !string.IsNullOrEmpty(val.ToString()))
                        items.Add(prop.Name + "=" + val);
                }
                return string.Join(";", items);
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Linq;
    
    namespace Zmm.Wx.MP.TenPay
    {
        public static class XmlToClass
        {
            public static void FillEntityWithXml<T>(this T entity, string xml) where T : /*MessageBase*/ class, new()
            {
    
                XElement xe = XElement.Parse(xml);
                entity.FillEntityWithXml(xe);
    
            }
            public static void FillEntityWithXml<T>(this T entity, XElement xe) where T : /*MessageBase*/ class, new()
            {
                entity = entity ?? new T();
    
                var props = entity.GetType().GetProperties();
                foreach (var prop in props)
                {
                    var propName = prop.Name;
                    if (xe.Element(propName) != null)
                    {
                        prop.SetValue(entity, xe.Element(propName).Value);
                    }
                }
    
            }
        }
    }
    

    Action如下:

    public ActionResult Pay()
          {
              var ret = Zmm.Wx.MP.TenPay.UnifierOrderResult.Get("衢州旅游特惠卡", "DetailTest", "AttachTest", DateTime.Now.Ticks + "1", 1, "218.244.138.166", "http://www.xuduovip.com/wzf/home/notify", "JSAPI", "Id1", "oLcmxt0gWL5nhdsgPAYB2iBM-IMs");

              if (ret.return_code == "FAIL")
              {
                  return Content(ret.return_msg);
              }
              if (ret.result_code == "FAIL")
              {
                  return Content(ret.err_code + "," + ret.err_code_des);
              }

              Zmm.Wx.MP.TenPay.TenpayData data = new Wx.MP.TenPay.TenpayData();
              data.Execute(ret.prepay_id);
              return View(data);

          }

          public ActionResult Notify()
          {

              XElement xe = XElement.Load(Request.InputStream);
              OrderResult ret = new Wx.MP.TenPay.OrderResult();
              ret.FillEntityWithXml(xe);
              Zmm.BLL.AppLogService.Info("Notify:" + ret);

              return Content(@"<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
          }

    view 如下:

    @model Zmm.Wx.MP.TenPay.TenpayData
    @{
        ViewBag.Title = "Pay";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }

    <h2>Pay</h2>

    <script language="javascript" type="text/javascript">
        function onBridgeReady() {
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                    "appId": "appid",     //公众号名称,由商户传入
                    "timeStamp": "@Model.timeStamp",         //时间戳,自1970年以来的秒数
                    "nonceStr": "@Model.nonceStr", //随机串
                    "package": "@Model.package",
                    "signType": "MD5",         //微信签名方式:
                    "paySign": "@Model.paySign"  //微信签名
                },
                function (res) {
                    alert("callback:" + res.err_msg);
                    if (res.err_msg == "get_brand_wcpay_request:ok") { }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
                }
            );
        }
        if (typeof WeixinJSBridge == "undefined") {
            if (document.addEventListener) {
                document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
            } else if (document.attachEvent) {
                document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
                document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
            }
        } else {
            onBridgeReady();
        }

    </script>

    jsapi方式测试成功,主要打开微信网页的时候一定要全部小写。

    native方式:

    action:

    var ret = Zmm.Wx.MP.TenPay.UnifierOrderResult.Get("衢州旅游特惠卡", "DetailTest", "AttachTest", DateTime.Now.Ticks + "1", 20000, "218.244.138.166", "http://www.xuduovip.com/wzf/home/notify", "NATIVE", "Id1", "oLcmxt0gWL5nhdsgPAYB2iBM-IMs");
              ViewBag.Code = Zmm.Common.QRCode.Create(ret.code_url);
              return View();

    view:

    @{
        ViewBag.Title = "测试网页";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }

    <h2>公众号Native支付测试网页</h2>
    <div class="WCPay">
        <a href="@Url.Action("Pay", new {showwxpaytitle=1})">点击提交可体验微信支付</a>
        <img src="@ViewBag.Code" />
    </div>

    二维码生成类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using ZXing;
    using ZXing.QrCode;
    using System.Drawing;
    using System.IO;
    namespace Zmm.Common
    {
        public class QRCode
        {
            public static string Create(string s)
            {
                var options = new QrCodeEncodingOptions
                  {
                      DisableECI = true,
                      CharacterSet = "UTF-8",
                      Width = 300,
                      Height = 300
                  };
                var writer = new BarcodeWriter();
                writer.Format = BarcodeFormat.QR_CODE;
                writer.Options = options;


                var image = writer.Write(s);

                MemoryStream ms = new MemoryStream(); //新建内存流
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                return "data:image/jpeg;base64," + Convert.ToBase64String(ms.GetBuffer());
            }
        }
    }

    native测试成功。

    乱写,凑合着看。写文档确实比较麻烦,也理解腾讯的那些兄弟了。

  • 相关阅读:
    路由器远程登陆的方式
    路由器上的DNS服务器构建
    路由器配置维护技巧---管道的应用
    【转】常见面试问题
    英文面试决胜关键
    12个有趣的c语言面试题
    16道嵌入式C语言面试题(经典)
    LCD 调试总结
    关于uboot的一些优化
    linux驱动开发的经典书籍
  • 原文地址:https://www.cnblogs.com/catzhou/p/4444516.html
Copyright © 2011-2022 走看看