Asp.net Core 微信小程序支付

最近要做一个微信小程序支付的功能 在网上找了一下 .net Core做微信支付的博客 和 demo 几乎没有 

自己研究了好几天 参考了 很多 大牛的博客 勉强做出来了  因为参数都没有 比如 opid 小程序域名 所以只是简单的测了一下 模拟了微信支付的回调请求 后续等项目上线 会回来填坑的 

第一次看小程序支付的api文档 看得我一脸懵逼 现在简单说一下吧 先上一个官方图 

小程序支付的流程是这样的 首先 用户下单 然后后台生成订单 调用统一支付api(注意这并不是支付 只是算一个预下单 通知下微信 我要掏钱了 你给我几个参数)  然后 统一下单API回返回给你五个参数 把五个参数和签名返回给前端 由前端来下单 

然后用户确认支付之后 会有一个微信的异步回调

(此处调用统一下单需要用的opid 在微信登录那一块 不做赘述) 

关于统一下单

构造下单参数  -- 调用API接口 -- 处理返回结果 -- 返回给前端

首先 构造统一下单的所需要的参数

然后发送Http请求  接收返回的结果

然后将五个参数返回给前台。

 微信支付回调也是

拿到微信返回的支付数据 解析数据 处理业务

这里需要注意 core 的接收方式

ok 这里先总结一下 等到测试完 没问题 回来填坑 并附上完整代码

 

附: 完整代码

 public class WeChatPayHelper
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        public PayRequesEntity Unifiedorder(string openid, string totalfee, string orderNo)
        {
            //var PayUrl = AppSetting.Load().WechatPayStrings.FirstOrDefault().UnifiedorderURL;
            //获取统一下单参数
            var param = GetUnifiedOrderParam(openid, orderNo, totalfee);
            _logger.Info(() => "微信支付统一下单 发送参数为 "+param+"");
            //统一下单后拿到的xml结果
            var payResXML = HttpMethods.Post(AppSetting.Load().WechatPayStrings.FirstOrDefault().UnifiedorderURL, param);
            _logger.Info(() => "微信支付统一下单 返回参数为 " + payResXML + "");
            var payRes = XDocument.Parse(payResXML);
            var root = payRes.Element("xml");
            var res = GetPayRequestParam(root);
            _logger.Info(() => "微信支付统一下单 参数实体为 " + JsonConvert.SerializeObject(res) + "");
            return res;
        }


        /// <summary>
        /// 取统一下单的请求参数
        /// </summary>
        /// <param name="openid"></param>
        /// <returns></returns>
        private string GetUnifiedOrderParam(string openid,string orderNo, string totalfee)
        {
            string appid = AppSetting.Load().WechatStrings.FirstOrDefault().APPID;
            string secret = AppSetting.Load().WechatStrings.FirstOrDefault().SECRET;
            string mch_id = AppSetting.Load().WechatPayStrings.FirstOrDefault().Mch_ID;
            string ip = AppSetting.Load().Configurations.FirstOrDefault().IP;
            string PayResulturl = AppSetting.Load().WechatPayStrings.FirstOrDefault().PayResulturl;

            string strcode = "益谦文化小程序-微信支付购买";////商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
            byte[] buffer = Encoding.UTF8.GetBytes(strcode);
            string body = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            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",orderNo},//商户自己的订单号码
                    {"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>");
            return sb.ToString();
        }


        /// <summary>
        /// 获取返回给小程序的支付参数
        /// </summary>
        /// <param name="root"></param>
        /// <param name="appid"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private PayRequesEntity GetPayRequestParam(XElement root)
        {           
            string appid = AppSetting.Load().WechatStrings.FirstOrDefault().APPID;
            //当return_code 和result_code都为SUCCESS时才有我们要的prepay_id
            if (root.Element("return_code").Value == "SUCCESS" && root.Element("result_code").Value == "SUCCESS")
            {
                var res = new Dictionary<string, string>
                {
                    {"appId", appid},
                    {"timeStamp", Convert.ToInt64((DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString()},
                    {"nonceStr", GetRandomString(20)},
                    {"package",  "prepay_id=" + root.Element("prepay_id").Value},
                    {"signType", "MD5"}
                };
                //在服务器上签名
                res.Add("paySign", GetSignString(res));

                var payEntity = new PayRequesEntity
                {
                    package = res["package"],
                    nonceStr = res["nonceStr"],
                    paySign = res["paySign"],
                    signType = res["signType"],
                    timeStamp = res["timeStamp"]
                };
                return payEntity;
            }

            return new PayRequesEntity();
        }


        /// <summary>
        /// 从字符串里随机得到,规定个数的字符串.
        /// </summary>
        /// <param name="allChar"></param>
        /// <param name="CodeCount"></param>
        /// <returns></returns>
        private 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;
        }


        private string GetSignString(Dictionary<string, string> dic)
        {
            string key = AppSetting.Load().WechatPayStrings.FirstOrDefault().WxPayKey;//商户平台 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;
            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
            sign = BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(sign))).Replace("-", null);
            return sign;
        }



        private static Object PostUnifiedOrder(string payUrl, string para)
        {
            string result = string.Empty;
            try
            {
                HttpClient client = new HttpClient();
                HttpContent httpContent = new StringContent(para);
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                httpContent.Headers.ContentType.CharSet = "utf-8";
                HttpResponseMessage hrm = client.PostAsync(payUrl, httpContent).Result;
                return hrm;
            }
            catch (Exception e)
            {
                result = e.Message;
            }
            return result;
        }
}

 

public class PayRequesEntity
    {
        /// <summary>
        /// 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
        /// </summary>
        public string timeStamp { get; set; }

        /// <summary>
        /// 随机字符串,长度为32个字符以下。
        /// </summary>
        public string nonceStr { get; set; }

        /// <summary>
        /// 统一下单接口返回的 prepay_id 参数值
        /// </summary>
        public string package { get; set; }

        /// <summary>
        /// 签名算法
        /// </summary>
        public string signType { get; set; }

        /// <summary>
        /// 签名
        /// </summary>
        public string paySign { get; set; }
    }

 

 

 

附: HttpMethods 操作

/// <summary>
    ///     Http方法
    /// </summary>
    public class HttpMethods
    {
        /// <summary>
        /// 创建HttpClient
        /// </summary>
        /// <returns></returns>
        public static HttpClient CreateHttpClient(string url, IDictionary<string, string> cookies = null)
        {
            HttpClient httpclient;
            HttpClientHandler handler = new HttpClientHandler();
            var uri = new Uri(url);
            if (cookies != null)
            {
                foreach (var key in cookies.Keys)
                {
                    string one = key + "=" + cookies[key];
                    handler.CookieContainer.SetCookies(uri, one);
                }
            }
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
                httpclient = new HttpClient(handler);
            }
            else
            {
                httpclient = new HttpClient(handler);
            }
            return httpclient;
        }
        #region 同步请求

        /// <summary>
        /// post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="jsonData">请求参数</param>
        /// <returns></returns>
        public static string Post(string url, string jsonData)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new StringContent(jsonData);
            postData.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
            Task<string> result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
            return result.Result;
        }

        /// <summary>
        /// post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="req">请求参数</param>
        /// <returns></returns>
        public static string Post(string url, byte[] req)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new ByteArrayContent(req);
            Task<string> result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
            return result.Result;
        }
        /// <summary>
        ///     post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="pairs">请求参数</param>
        /// <returns></returns>
        public static string Post(string url, Dictionary<string, string> pairs)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new FormUrlEncodedContent(pairs);
            var result = httpClient.PostAsync(url, postData).Result.Content.ReadAsStringAsync();
            return result.Result;

        }
        /// <summary>
        /// get 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public static string Get(string url)
        {
            HttpClient httpClient = CreateHttpClient(url);
            Task<string> result = httpClient.GetAsync(url).Result.Content.ReadAsStringAsync();
            return result.Result;
        }

        #endregion

        #region 异步请求
        /// <summary>
        ///     post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="jsonData">请求参数</param>
        /// <returns></returns>
        public static Task<HttpResponseMessage> PostAsync(string url, string jsonData)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new StringContent(jsonData);
            postData.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
            var result = httpClient.PostAsync(url, postData);
            return result;
        }
        /// <summary>
        ///     post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="req">请求参数</param>
        /// <returns></returns>
        public static Task<HttpResponseMessage> PostAsync(string url, byte[] req)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new ByteArrayContent(req);
            var result = httpClient.PostAsync(url, postData);
            return result;
        }
        /// <summary>
        ///     post 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="pairs">请求参数</param>
        /// <returns></returns>
        public static Task<HttpResponseMessage> PostAsync(string url, Dictionary<string, string> pairs)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var postData = new FormUrlEncodedContent(pairs);
            var result = httpClient.PostAsync(url, postData);
            return result;
        }

        /// <summary>
        ///     get 请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public static Task<HttpResponseMessage> GetAsync(string url)
        {
            HttpClient httpClient = CreateHttpClient(url);
            var result = httpClient.GetAsync(url);
            return result;
        }
        #endregion

    }

  

 

posted @ 2019-08-28 11:57  Felix-Zhang  阅读(2823)  评论(8编辑  收藏  举报