ASP.Net项目中实现微信APP支付功能

最近挺忙的,没时间写东西。然后在弄微信APP支付,网上的搜索一趟,都比较凌乱,我也遇到一些坑,不过也算弄好了,记录分享一下。

1、准备各种调用接口需要的参数,配置app.config。

<!--AppID-->
<add key="AppID" value="" />
<!--AppSecret-->
<add key="AppSecret" value="" />
<!--商户号-->
<add key="MchID" value="" />
<!--APIKey-->
<add key="APIKey" value="" />

2、调用统一下单API,直接上代码了。

	/// <summary>
    /// Builds the request.
    /// </summary>
    /// <returns></returns>
    public static string BuildRequest()
    {
        var dicParam = CreateParam();

        var signString = CreateURLParamString(dicParam);
        var preString = signString + "&key=" + ConfigHelper.APIKey;
        var sign = Sign(preString, "utf-8").ToUpper();
        dicParam.Add("sign", sign);

        return BuildForm(dicParam);
    }    	

	/// <summary>
    /// Generates the out trade no.
    /// </summary>
    /// <returns></returns>
    private static string GenerateOutTradeNo()
    {
        var ran = new Random();
        return $"{ConfigHelper.MchID}{DateTime.Now:yyyyMMddHHmmss}{ran.Next(999)}";
    }

	/// <summary>
    /// Signs the specified prestr.
    /// </summary>
    /// <param name="prestr">The prestr.</param>
    /// <param name="_input_charset">The input charset.</param>
    /// <returns></returns>
    private static string Sign(string prestr, string _input_charset)
    {
        var sb = new StringBuilder(32);
        MD5 md5 = new MD5CryptoServiceProvider();
        var t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
        foreach (var t1 in t)
        {
            sb.Append(t1.ToString("x").PadLeft(2, '0'));
        }

        return sb.ToString();
    }

	/// <summary>
    /// Creates the parameter.
    /// </summary>
    /// <returns></returns>
    private static SortedDictionary<string, string> CreateParam()
    {
        const string amount = "1";
        double dubamount;
        double.TryParse(amount, out dubamount);
        var notify_url = ConfigHelper.WebSiteUrl + "/api/v1/testWeiXin"; //支付完成后的回调处理页面
        const string detail = "xxxx";

        var dic = new SortedDictionary<string, string>
        {
            {"appid", ConfigHelper.AppID},//账号ID
            {"mch_id", ConfigHelper.MchID},//商户号
            {"nonce_str", Guid.NewGuid().ToString().Replace("-", "")},//随机字符串
            {"body", detail}, //商品描述
            {"out_trade_no", GenerateOutTradeNo()},//商户订单号
            {"total_fee", (dubamount * 100).ToString(CultureInfo.InvariantCulture)},//总金额
            {"spbill_create_ip", GeneralHelper.GetIP()},//终端IP
            {"notify_url", notify_url},//通知地址
            {"trade_type", "APP"}//交易类型
        };

        return dic;
    }

	/// <summary>
    /// Creates the URL parameter string.
    /// </summary>
    /// <param name="dicArray">The dic array.</param>
    /// <returns></returns>
    private static string CreateURLParamString(SortedDictionary<string, string> dicArray)
    {
        var prestr = new StringBuilder();
        foreach (var temp in dicArray.OrderBy(o => o.Key))
        {
            prestr.Append(temp.Key + "=" + temp.Value + "&");
        }

        var nLen = prestr.Length;
        prestr.Remove(nLen - 1, 1);
        return prestr.ToString();
    }

	/// <summary>
    /// Builds the form.
    /// </summary>
    /// <param name="dicParam">The dic parameter.</param>
    /// <returns></returns>
    private static string BuildForm(SortedDictionary<string, string> dicParam)
    {
        var sbXML = new StringBuilder();
        sbXML.Append("<xml>");
        foreach (var temp in dicParam)
        {
            sbXML.Append("<" + temp.Key + ">" + temp.Value + "</" + temp.Key + ">");
        }

        sbXML.Append("</xml>");
        return sbXML.ToString();
    }

	/// <summary>
    /// Froms the XML.
    /// </summary>
    /// <param name="xml">The XML.</param>
    /// <returns></returns>
    /// <exception cref="Exception">将空的xml串转换为WxPayData不合法!</exception>
    public static SortedDictionary<string, string> FromXml(string xml)
    {
        var sortDic = new SortedDictionary<string, string>();
        if (string.IsNullOrEmpty(xml))
        {
            throw new Exception("将空的xml串转换为WxPayData不合法!");
        }

        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(xml);
        var xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
        var nodes = xmlNode.ChildNodes;
        foreach (XmlNode xn in nodes)
        {
            var xe = (XmlElement)xn;

            if (!sortDic.ContainsKey(xe.Name))
                sortDic.Add(xe.Name, xe.InnerText);
        }
        return sortDic;
    }

	/// <summary>
    /// Posts the specified URL.
    /// </summary>
    /// <param name="url">The URL.</param>
    /// <param name="content">The content.</param>
    /// <param name="contentType">Type of the content.</param>
    /// <returns></returns>
    /// <exception cref="Exception">POST请求错误" + e</exception>
    public static string Post(string url, string content, string contentType = "application/x-www-form-urlencoded")
    {
        string result;
        try
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
                var stringContent = new StringContent(content, Encoding.UTF8);
                var response = client.PostAsync(url, stringContent).Result;
                result = response.Content.ReadAsStringAsync().Result;
            }
        }
        catch (Exception e)
        {
            throw new Exception("POST请求错误" + e);
        }
        return result;
    }

3、生成预付订单,获取prepay_id。

	/// <summary>
    /// Gets the value from dic.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dic">The dic.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static T GetValueFromDic<T>(IDictionary<string, string> dic, string key)
    {
        string val;
        dic.TryGetValue(key, out val);

        var returnVal = default(T);
        if (val != null)
            returnVal = (T)Convert.ChangeType(val, typeof(T));

        return returnVal;
    }

	/// <summary>
    /// Builds the application pay.
    /// </summary>
    /// <param name="prepayid">The prepayid.</param>
    /// <returns></returns>
    public static string BuildAppPay(string prepayid)
    {
        var dicParam = CreateWapAndAppPayParam(prepayid);
        var signString = CreateURLParamString(dicParam);
        var preString = signString + "&key=" + ConfigHelper.APIKey;

        var sign = Sign(preString, "utf-8").ToUpper();
        dicParam.Add("sign", sign);

        return JsonConvert.SerializeObject(
            new
            {
                appid = dicParam["appid"],
                partnerid = dicParam["partnerid"],
                prepayid = dicParam["prepayid"],
                package = dicParam["package"],
                noncestr = dicParam["noncestr"],
                timestamp = dicParam["timestamp"],
                sign = dicParam["sign"]
            });
    }

	/// <summary>
    /// Creates the wap and application pay parameter.
    /// </summary>
    /// <param name="prepayId">The prepay identifier.</param>
    /// <returns></returns>
    private static SortedDictionary<string, string> CreateWapAndAppPayParam(string prepayId)
    {
        var dic = new SortedDictionary<string, string>
        {
            {"appid", ConfigHelper.AppID},//公众账号ID
            {"partnerid", ConfigHelper.MchID},//商户号
            {"prepayid", prepayId},//预支付交易会话ID
            {"package", "Sign=WXPay"},//扩展字段
            {"noncestr", Guid.NewGuid().ToString().Replace("-", "")},//随机字符串
            {
                "timestamp",
                (Convert.ToInt32((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds)).ToString()
            }//时间戳
        };

        return dic;
    }

	/// <summary>
    /// Validatons the query result.
    /// </summary>
    /// <param name="dic">The dic.</param>
    /// <returns></returns>
    public static bool ValidatonQueryResult(SortedDictionary<string, string> dic)
    {
        var result = false;

        if (dic.ContainsKey("return_code") && dic.ContainsKey("return_code"))
        {
            if (dic["return_code"] == "SUCCESS" && dic["result_code"] == "SUCCESS")
                result = true;
        }

        if (result) return true;

        var sb = new StringBuilder();
        foreach (var item in dic.Keys)
        {
            sb.Append(item + ":" + dic[item] + "|");
        }

        return false;
    }

4、调用获取支付信息,给到APP发起支付操作。

		var requestXml = WeiXinUtil.BuildRequest();
        var resultXml = WeiXinUtil.Post("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXml);

        var dic = WeiXinUtil.FromXml(resultXml);

        string returnCode;
        dic.TryGetValue("return_code", out returnCode);

        if (returnCode == "SUCCESS")
        {
            var prepay_id = WeiXinUtil.GetValueFromDic<string>(dic, "prepay_id");
            if (!string.IsNullOrEmpty(prepay_id))
            {
                var payInfo = JsonConvert.DeserializeObject<WeiXinUtil.WxPayModel>(WeiXinUtil.BuildAppPay(prepay_id));

                json.Add(new JProperty("appid", payInfo.appid));
                json.Add(new JProperty("partnerid", payInfo.partnerid));
                json.Add(new JProperty("prepayid", payInfo.prepayid));
                json.Add(new JProperty("package", payInfo.package));
                json.Add(new JProperty("noncestr", payInfo.noncestr));
                json.Add(new JProperty("timestamp", payInfo.timestamp));
                json.Add(new JProperty("sign", payInfo.sign));
                json.Add(new JProperty("code", 0));
                json.Add(new JProperty("msg", "成功"));
                return this.Jsonp(json.ToString());
            }
            else
            {
                json.Add(new JProperty("code", 40028));
                json.Add(new JProperty("msg", "支付错误:" + WeiXinUtil.GetValueFromDic<string>(dic, "err_code_des")));
                return this.Jsonp(json.ToString());
            }
        }
        else
        {
            return this.Jsonp(ApiException.OrderFailed());
        }

5、APP支付完成,获得回调信息,就OK了。

		var context = this.HttpContext;
        var request = context.Request;
        var verifyResult = false;
        var requestXml = WeiXinUtil.GetRequestXmlData(request);
        var dic = WeiXinUtil.FromXml(requestXml);
        var returnCode = WeiXinUtil.GetValueFromDic<string>(dic, "return_code");

        if (!string.IsNullOrEmpty(returnCode) && returnCode == "SUCCESS")//通讯成功
        {
            var result = WeiXinUtil.WePayNotifyValidation(dic);
            if (result)
            {
                var transactionid = WeiXinUtil.GetValueFromDic<string>(dic, "transaction_id");

                if (!string.IsNullOrEmpty(transactionid))
                {
                    var queryXml = WeiXinUtil.BuildQueryRequest(transactionid, dic);
                    var queryResult = WeiXinUtil.Post("https://api.mch.weixin.qq.com/pay/orderquery", queryXml);
                    var queryReturnDic = WeiXinUtil.FromXml(queryResult);

                    if (WeiXinUtil.ValidatonQueryResult(queryReturnDic))//查询成功
                    {
                        verifyResult = true;
                        var status = WeiXinUtil.GetValueFromDic<string>(dic, "result_code");

                        if (!string.IsNullOrEmpty(status) && status == "SUCCESS")
                        {
                            var order = new Order()
                            {
                                OrderNumber = WeiXinUtil.GetValueFromDic<string>(dic, "out_trade_no"),
                                TransactionId = transactionid,
                                ProductPrice = WeiXinUtil.GetValueFromDic<decimal>(dic, "total_fee") / 100,
                                TradeType = WeiXinUtil.GetValueFromDic<string>(dic, "trade_type"),
                                BankType = WeiXinUtil.GetValueFromDic<string>(dic, "bank_type"),
                                PayDate = DateTime.Parse(WeiXinUtil.GetValueFromDic<string>(dic, "time_end")),
                                StatusId = 1,
                                IsPresent = false,
                                AddDate = DateTime.Now,
                                IsDelete = false
                            };

                            CURD.Add(order, ConfigHelper.WriteDB);

                            WeiXinUtil.BuildReturnXml("OK", "成功");
                        }
                    }
                    else
                        WeiXinUtil.BuildReturnXml("FAIL", "订单查询失败");
                }
                else
                    WeiXinUtil.BuildReturnXml("FAIL", "支付结果中微信订单号不存在");
            }
            else
                WeiXinUtil.BuildReturnXml("FAIL", "签名失败");
        }
        else
        {
            string returnmsg;
            dic.TryGetValue("return_msg", out returnmsg);
            throw new Exception("异步通知错误:" + returnmsg);
        }

        return verifyResult;

	/// <summary>
    /// Gets the request XML data.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <returns></returns>
    public static string GetRequestXmlData(HttpRequestBase request)
    {
        var stream = request.InputStream;
        int count;
        var buffer = new byte[1024];
        var builder = new StringBuilder();
        while ((count = stream.Read(buffer, 0, 1024)) > 0)
        {
            builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
        }
        stream.Flush();
        stream.Close();

        return builder.ToString();
    }

    /// <summary>
    /// Wes the pay notify validation.
    /// </summary>
    /// <param name="dic">The dic.</param>
    /// <returns></returns>
    public static bool WePayNotifyValidation(SortedDictionary<string, string> dic)
    {
        var sign = GetValueFromDic<string>(dic, "sign");
        if (dic.ContainsKey("sign"))
        {
            dic.Remove("sign");
        }

        var tradeType = GetValueFromDic<string>(dic, "trade_type");
        var preString = CreateURLParamString(dic);

        if (string.IsNullOrEmpty(tradeType))
        {
            var preSignString = preString + "&key=" + ConfigHelper.APIKey;
            var signString = Sign(preSignString, "utf-8").ToUpper();
            return signString == sign;
        }
        else
            return false;
    }

	/// <summary>
    /// Builds the query request.
    /// </summary>
    /// <param name="transactionId">The transaction identifier.</param>
    /// <param name="dic">The dic.</param>
    /// <returns></returns>
    public static string BuildQueryRequest(string transactionId, SortedDictionary<string, string> dic)
    {
        var dicParam = CreateQueryParam(transactionId);
        var signString = CreateURLParamString(dicParam);
        var key = ConfigHelper.APIKey;
        var preString = signString + "&key=" + key;
        var sign = Sign(preString, "utf-8").ToUpper();
        dicParam.Add("sign", sign);

        return BuildForm(dicParam);
    }

    /// <summary>
    /// Creates the query parameter.
    /// </summary>
    /// <param name="transactionId">The transaction identifier.</param>
    /// <returns></returns>
    private static SortedDictionary<string, string> CreateQueryParam(string transactionId)
    {
        var dic = new SortedDictionary<string, string>
        {
            {"appid", ConfigHelper.AppID},//公众账号ID
            {"mch_id", ConfigHelper.MchID},//商户号
            {"nonce_str", Guid.NewGuid().ToString().Replace("-", "")},//随机字符串
            {"transaction_id", transactionId}//微信订单号
        };
        return dic;
    }

	/// <summary>
    /// Builds the return XML.
    /// </summary>
    /// <param name="code">The code.</param>
    /// <param name="returnMsg">The return MSG.</param>
    /// <returns></returns>
    public static string BuildReturnXml(string code, string returnMsg)
    {
        return
            $"<xml><return_code><![CDATA[[code]]]></return_code><return_msg><![CDATA[{returnMsg}]]></return_msg></xml>";
    }

6、总结:这个可以直接拿来用了,反反复复测试了很多遍,遇到的问题有关于钱,还有签名的问题,调试都解决了。继续解决问题,积累经验。

到此这篇关于ASP.Net项目中实现微信APP支付功能的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • .NET微信扫码支付接入(模式二-NATIVE)

    一.前言 经过两三天的琢磨总算完成了微信扫码支付功能,不得不感叹几句: 微信提供的DEMO不错,直接复制粘贴就可以跑起来了: 微信的配置平台我真是服了.公众平台.商户平台.开放平台,一个平台一套账户密码,大写的恶心        DEMO地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1 .NET版DEMO中的Lib文件夹是关键,直接复制到自己的代码里,或者打成dll随个人意愿. 二.正文 Step1:肯定是产生商户

  • .NET Core 实现微信小程序支付功能(统一下单)

    最近公司研发了几个电商小程序,还有一个核心的电商直播,只要是电商一般都会涉及到交易信息,离不开支付系统,这里我们统一实现小程序的支付流程(与服务号实现步骤一样). 开通小程序的支付能力 开通小程序支付功能比较简单,基本上按微信文档一步一步的申请就好,如图 以上三个步骤就申请完成 1.提交资料给微信 2.微信审核并签署协议 3.商户后台绑定同主体的APPID 商户后台绑定同一主体的APPID并授权 1.登录商户后台https://pay.weixin.qq.com,进入产品中心-APPID授权管理

  • 最详细的ASP.NET微信JS-SDK支付代码

    本文实例为大家分享了微信JS SDK支付的具体代码,供大家参考,具体内容如下 模型层实体类: public class JsEntities { /// <summary> /// 公众号id /// </summary> public string appId { get; set; } /// <summary> /// 时间戳 /// </summary> public string timeStamp { get; set; } /// <su

  • .NET Core之微信支付之公众号、H5支付详解

    前言 本篇主要记录微信支付中公众号及H5支付全过程. 准备篇 公众号或者服务号(并开通微信支付功能).商户平台中开通JSAPI支付.H5支付. 配置篇 公众号或者服务号中 -------开发-------开发者工具---------web开发者工具-------绑定为开发者 公众号或者服务号中 -------公众号设置--------功能设置   :填写业务域名.JS安全域名.网页授权域名 示例:pay.one.com 商户平台中--------产品中心-------开发配置------JSAP

  • 解析微信支付的实现方法(.NET版)

    前段时间做了网页版微信支付,遇到很多问题,不过最终还是解决了,现在在这里记录下开发流程以及说明,给其他人一些参考. 一.准备工作 首先肯定得先要开通微信支付功能,之前开通微信支付需要三万的押金的,现在不需要了,所以就做了这个功能. 要进行微信支付开发,需要在公众号后台和微信商户后台进行相关的设置. 1.开发目录配置 微信支付需要在公众号后台(微信支付=>开发配置)进行配置支付授权目录.这里授权目录需要是线上地址,也就是可以通过互联网访问到的地址,微信支付系统需要能够通过互联网访问到你的地址. 微

  • ASP.NET MVC 开发微信支付H5的实现示例(外置浏览器支付)

    H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付. 主要用于触屏版的手机浏览器请求微信支付的场景.可以方便的从外部浏览器唤起微信支付. 微信开放平台上的也只是简单的介绍了一下逻辑和常见问题,网上查看了很多,说的都不够具体 首先需要在微信商户平台里开通 H5支付 申请入口:登录商户平台-->产品中心-->我的产品-->支付产品-->H5支付 代码逻辑: 1.用户在商户侧完成下单,使用微信支付进行支付 2.

  • ASP.Net项目中实现微信APP支付功能

    最近挺忙的,没时间写东西.然后在弄微信APP支付,网上的搜索一趟,都比较凌乱,我也遇到一些坑,不过也算弄好了,记录分享一下. 1.准备各种调用接口需要的参数,配置app.config. <!--AppID--> <add key="AppID" value="" /> <!--AppSecret--> <add key="AppSecret" value="" /> <!-

  • Android开发微信APP支付功能的要点小结

    基本概念 包名值得是你APP的包,在创建工程时候设置的,需要在微信支付平台上面设置. 签名指的是你生成APK时候所用的签名文件的md5,去掉:全部小写,需要在微信支付平台上面设置. 调试阶段,签名文件可以使用调试用的debug.keystore,签名可以直接在eclipse上面查看,或者用工具查看 ,安装打开输入包名即可查看. 发布的时候一定需要在微信支付平台上面设置成发布用的签名值. 官方的Demo里面的内容并不是全是必须的,甚至只需要有libammsdk.jar就够了,AndroidMani

  • PHP实现的微信APP支付功能示例【基于TP5框架】

    本文实例讲述了PHP实现的微信APP支付功能.分享给大家供大家参考,具体如下: 1.进行支付请求 他给的DEMO 用的时候有时候会报错 1)我遇到的情况 把  WxPay.Api.php这个文件的 postXmlCurl 这个 方法里 // curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); // curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验 curl_setopt($ch,CURLOPT_SSL_VER

  • Spring Boot项目中集成微信支付v3

    1. 前言 最近忙的一批,难得今天有喘气的机会就赶紧把最近在开发中的一些成果分享出来.前几日分享了自己写的一个微信支付V3的开发包payment-spring-boot-starter,就忙里偷闲完善了一波.期间给微信支付提交了6个BUG,跟微信支付的产品沟通了好几天. 项目地址: https://github.com/NotFound403/payment-spring-boot 别忘记给个Star啊. 那么都完善了哪些内容呢?胖哥来一一介绍. 2. Maven 中央仓库 是的,不用再自行编译

  • springboot接入微信app支付的方法

    1.前戏 1.1请先完成微信APP支付接入商户服务中心 1.2详情请参考微信官方文档:https://open.weixin.qq.com/ 2.application.yml文件的配置如下 #微信支付配置 tenpayconfig: #商户APPID appId: asdfg12345 #商户号 mchId: 12345678 #商户的key(API密匙) key: qwertyuiop #API支付请求地址 payUrl: https://api.mch.weixin.qq.com/pay/

  • java服务端微信APP支付接口详解

    一.微信APP支付接入商户服务中心 [申请流程指引] (https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317780&token=84f23b4e9746c5963128711f225476cfd49ccf8c&lang=zh_CN) 二.开始开发 1.配置相关的配置信息 1.1.配置appid(Androi

  • java实现微信App支付服务端

    微信App支付服务端的实现方法,供大家参考,具体内容如下 引言 主要实现app支付统一下单.异步通知.调起支付接口.支付订单查询.申请退款.查询退款功能:封装了https对发起退款的证书校验.签名.xml解析等. 支付流程 具体支付流程参考"微信APP"文档,文档地址 APP支付:APP端点击下单--服务端生成订单,并调起"统一下单",返回app支付所需参数-–APP端"调起支付接口",发起支付--微信服务器端调用服务端回调地址-–服务端按照&q

  • vue项目中企业微信使用js-sdk时config和agentConfig配置方式详解

    1.如果只使用config配置的相关js接口 可采用如下方式引入 执行 npm weixin-sdk-js --save 局部引入 在vue页面中 import wx from 'weixin-sdk-js'; 全局引入 在vue 的main.js 页面中 引入后编写到vue原型链上,然后全局调用 import wx from "weixin-sdk-js"; Vue.prototype.$wx = wx; 2.如果要使用agentConfig配置的相关接口 一定不要执行npm命令引入

  • 微信APP支付Java代码

    本文实例为大家分享了java微信APP支付代码,供大家参考,具体内容如下 import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Random; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.htt

  • vue项目中,main.js,App.vue,index.html的调用方法

    如下所示: 1.main.js是我们的入口文件,主要作用是初始化vue实例,并引入所需要的插件 2.App.vue是我们的主组件,所有页面都是在App.vue下进行切换的.其实你也可以理解为所有的路由也是App.vue的子组件.所以我将router标示为App.vue的子组件. 1.index.html文件入口 2.src放置组件和入口文件 3.node_modules为依赖的模块 4.config中配置了路径端口值等 5.build中配置了webpack的基本配置.开发环境配置.生产环境配置等

随机推荐