Asp.net Core 微信小程序支付

摘要:
最近,我在互联网上发现了微信小程序支付的功能。几天来,NetCore自己很少研究微信支付博客和演示,参考了很多Daniel的博客,因为没有参数,比如opid小程序域名,所以很不情愿地制作了它们,所以它只是简单地测试和模拟了微信支付的回调请求,随后的项目将在上线时回来填补漏洞。第一次看到小程序支付的API文档时,我惊呆了。现在让我们谈谈它。首先,我用一个官方图像小程序支付。流程如下:首先,用户下订单,然后后台生成订单,并调用统一支付api(注意

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

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

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

Asp.net Core 微信小程序支付第1张

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

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

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

关于统一下单

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

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

Asp.net Core 微信小程序支付第2张

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

Asp.net Core 微信小程序支付第3张

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

微信支付回调也是

Asp.net Core 微信小程序支付第4张

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

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

Asp.net Core 微信小程序支付第5张

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

附:完整代码

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

        public PayRequesEntity Unifiedorder(string openid, string totalfee, stringorderNo)
        {
            //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) + "");
            returnres;
        }


        /// <summary>
        ///取统一下单的请求参数
        /// </summary>
        /// <param name="openid"></param>
        /// <returns></returns>
        private string GetUnifiedOrderParam(string openid,string orderNo, stringtotalfee)
        {
            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 = newSystem.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 = newStringBuilder();
            sb.Append("<xml>");
            foreach (var d indic)
            {
                sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">");
            }
            sb.Append("</xml>");
            returnsb.ToString();
        }


        /// <summary>
        ///获取返回给小程序的支付参数
        /// </summary>
        /// <param name="root"></param>
        /// <param name="appid"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        privatePayRequesEntity 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 = newPayRequesEntity
                {
                    package = res["package"],
                    nonceStr = res["nonceStr"],
                    paySign = res["paySign"],
                    signType = res["signType"],
                    timeStamp = res["timeStamp"]
                };
                returnpayEntity;
            }

            return newPayRequesEntity();
        }


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

            returnRandomCode;
        }


        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);
            returnsign;
        }



        private static Object PostUnifiedOrder(string payUrl, stringpara)
        {
            string result = string.Empty;
            try{
                HttpClient client = newHttpClient();
                HttpContent httpContent = newStringContent(para);
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                httpContent.Headers.ContentType.CharSet = "utf-8";
                HttpResponseMessage hrm =client.PostAsync(payUrl, httpContent).Result;
                returnhrm;
            }
            catch(Exception e)
            {
                result =e.Message;
            }
            returnresult;
        }
}
public classPayRequesEntity
    {
        /// <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

    }

免责声明:文章转载自《Asp.net Core 微信小程序支付》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Golang之sqlite数据库支付宝同步请求检查appid,以及公钥,私钥是否正确下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【转】 如何利用C#代码来进行操作AD

要用代码访问 Active Directory域服务,需引用System.DirectoryServices命名空间,该命名空间包含两个组件类,DirectoryEntry和 DirectorySearcher。DirectoryEntry类可封装 ActiveDirectory域服务层次结构中的节点或对象,使用此类绑定到对象、读取属性和更新特性;使用Di...

java栈、堆

一。栈、堆几个小概念 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。) 3. 堆:存放所有new出来的对象。 4. 静态域 :存放静态成员(static定义的) 5. 常量池 :...

Redis设置过期时间

一般添加值之后,不设置过期时间的话,ttl某个键会显示-1,表示此时并没有设置过期时间 当设置了过期时间之后,则会显示剩余过期秒数 设置过期时间的做法 #region 设置过期时间 //设置多少秒 client.Set<string>("name",...

前端http请求和常见的几个请求技术做具体的讲解

对于前端来说,请求是前端日常工作必备的,通过请求才能与后端进行数据交互,尤其在现在前后端分离的开发模式下,请求显得就更加重要。因此,对于前端开发者来说,掌握请求就很重要。下面将从http请求和常见的几个请求技术做具体的讲解 一、XMLHttpRequest         XMLHttpRequest一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效...

Django【第2篇】:Django之反向解析

Django框架之第二篇 一、知识点回顾 1、MTV模型   model:模型,和数据库相关的   template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中)。   views:视图函数 另加urls:url路径与视图函数的映射关系,,可以不是一一对应的。 2、相关的一些命令   创建一个Django项目:dja...

JAVAWEB应用模块(一)登录模块

java后台代码(MD5加密+token验证): import com.smart.ssai.admin.domain.User; import com.smart.ssai.admin.service.UserService; import com.smart.ssai.VO.Response; import com.smart.ssai.common....