Asp.net Core 微信小程序支付

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

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

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

图片[1]-Asp.net Core 微信小程序支付-八度分享

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

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

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

关于统一下单

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

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

图片[2]-Asp.net Core 微信小程序支付-八度分享

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

图片[3]-Asp.net Core 微信小程序支付-八度分享

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

微信支付回调也是

图片[4]-Asp.net Core 微信小程序支付-八度分享

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

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

图片[5]-Asp.net 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
 
    }

 

© 版权声明
THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
H的头像-八度分享

昵称

取消
昵称表情代码图片