C#(ASP.NET)微信支付(jsapi)实现

前段时间,公司webapp项目需要用到微信支付  研究了一下JSAPI 没什么问题 记录分享一下
首先说一下微信支付流程:(此处流程不包括被扫和扫码支付)
第一步:通过scope=snsapi_userinfo获取微信code令牌,如果你是公众号打开,直接取Request[“code”]的值,在微信导航菜单配置点击地址,如(https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://www.xxx.com/api.aspx&response_type=code&scope=snsapi_userinfo&state=s1#wechat_redirect),然后在api.aspx文件中获取code即可,如果不是做的公众号微信支付,可以使用地址跳转获取授权,如跳转到该地址授权(https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://www.xxx.com/api.aspx?tid=&response_type=code&scope=snsapi_userinfo&state=s1&connect_redirect=1#wechat_redirect)
第二步:得到code令牌之后,然后根据code获取access授权,以下代码就是获取授权,得到里面的openid

public class WxModelAccessToken
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }
        public string refresh_token { get; set; }
        public string openid { get; set; }
        public string scope { get; set; }
    }
public WxModelAccessToken GetAccessToken(string code)
        {
            WxModelAccessToken obj = null;
            string url =
            string.Format(
                "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code",
                WxConfig.appId, WxConfig.appsecret, code);
            string returnStr = HttpUtil.Send("", url);
            obj = JsonConvert.DeserializeObject(returnStr);
            return obj;
        }

第三步:根据参数与上面的openid构造表单,向微信请求创建订单,创建成功后,生成sign,构造JSAPI支付页面,看代码

        public decimal tenpay = 1;  //人民币 分
        public string mchid = WxConfig.mchid; //mchid
        public string appId = WxConfig.appId; //appid
        public string appsecret = WxConfig.appsecret; //appsecret
        public string appkey = WxConfig.appkey; //paysignkey(非appkey 在微信商户平台设置 (md5)111111111111) 
        public string timeStamp = ""; //时间戳 
        public string nonceStr = ""; //随机字符串 
        public string notify_url = ""; //支付完成后的回调处理页面,*替换成notify_url.asp所在路径
        public string prepayId = "";     //预支付ID
        public string sign = "";     //为了获取预支付ID的签名
        public string paySign = "";  //进行支付需要的签名
        public string package = "";  //进行支付需要的包
        public string shopname = "";//商品名称
        public string shopdesc = "";//商品简介
        public string sp_billno = "";//订单号
        public int orderNum = 1;//数量

Page_Load:
//设置异步回调地址,必须要有异步处理,否则有可能无法正常接受结果
notify_url = "http://" + Request.Url.Host + "/PayCenter/m/notify_url.aspx";
 //当前时间 yyyyMMdd
            string date = DateTime.Now.ToString("yyyyMMdd");

            //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
            sp_billno = date + DateTime.Now.ToString("HHmmss") + TenpayUtil.BuildRandomStr(4);
 //创建支付应答对象
            var packageReqHandler = new RequestHandler(Context);
            //初始化
            packageReqHandler.init();

            timeStamp = TenpayUtil.getTimestamp();
            nonceStr = TenpayUtil.getNoncestr();

            //设置package订单参数

            packageReqHandler.setParameter("body", "商品简介"); //商品信息 127字符
            packageReqHandler.setParameter("appid", appId);
            packageReqHandler.setParameter("mch_id", mchid);
            packageReqHandler.setParameter("nonce_str", nonceStr.ToLower());
            packageReqHandler.setParameter("notify_url", notify_url);
            packageReqHandler.setParameter("openid", openID);
            packageReqHandler.setParameter("out_trade_no", sp_billno); //商家订单号
            packageReqHandler.setParameter("spbill_create_ip", Page.Request.UserHostAddress); //用户的公网ip,不是商户服务器IP
            packageReqHandler.setParameter("total_fee", tenpay.ToString()); //商品金额,以分为单位(money * 100).ToString()
            packageReqHandler.setParameter("trade_type", "JSAPI");

            //获取package包
            sign = packageReqHandler.CreateMd5Sign("key", appkey);
            packageReqHandler.setParameter("sign", sign);

            string data = packageReqHandler.parseXML();

            string prepayXml = HttpUtil.Send(data, "https://api.mch.weixin.qq.com/pay/unifiedorder");
            //获取预支付ID
            var xdoc = new XmlDocument();
            xdoc.LoadXml(prepayXml);
            XmlNode xn = xdoc.SelectSingleNode("xml");
            XmlNodeList xnl = xn.ChildNodes;
            if (xnl.Count > 7)
            {
                prepayId = xnl[7].InnerText;
                package = string.Format("prepay_id={0}", prepayId);
                //WriteFile(Server.MapPath("") + "\\Log.txt", package);
            }

            //设置支付参数
            var paySignReqHandler = new RequestHandler(Context);
            paySignReqHandler.setParameter("appId", appId);
            paySignReqHandler.setParameter("timeStamp", timeStamp);
            paySignReqHandler.setParameter("nonceStr", nonceStr);
            paySignReqHandler.setParameter("package", package);
            paySignReqHandler.setParameter("signType", "MD5");
            paySign = paySignReqHandler.CreateMd5Sign("key", appkey);

页面代码:

商品支付
    		

订单名称:<%=shopname %>
订单编号:<%=sp_billno %>
付款金额:<%=tenpay/100 %>元

第四步:准备好同步和异步接受处理文件
同步:

 public class WxPayModelResult
    {
        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 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_state { get; set; }
        public string device_info { 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 int total_fee { get; set; }
        public int coupon_fee { get; set; }
        public string fee_type { 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; }
    }

 if (!IsPostBack)
            {
                //查询订单是否真正支付成功
                //创建支付应答对象
                var packageReqHandler = new RequestHandler(Context);
                //初始化
                packageReqHandler.init();

                packageReqHandler.setParameter("appid", WxConfig.appId);
                packageReqHandler.setParameter("mch_id", WxConfig.mchid);
                packageReqHandler.setParameter("out_trade_no", Request["orderNo"]);
                packageReqHandler.setParameter("transaction_id", "");
                packageReqHandler.setParameter("nonce_str", TenpayUtil.getNoncestr());
                //获取package包
                string sign = packageReqHandler.CreateMd5Sign("key", WxConfig.appkey);
                packageReqHandler.setParameter("sign", sign);
                string data = packageReqHandler.parseXML();
                string prepayXml = HttpUtil.Send(data, "https://api.mch.weixin.qq.com/pay/orderquery");
                var xdoc = new XmlDocument();
                xdoc.LoadXml(prepayXml);
                XmlNode xn = xdoc.SelectSingleNode("xml");
                XmlNodeList xnl = xn.ChildNodes;
                if (xnl.Count == 19)
                {
                    //Request["orderNo"] 订单号
                    if (xnl[0].InnerText == "SUCCESS" && xnl[6].InnerText == "SUCCESS" && xnl[17].InnerText == "SUCCESS")
                    {

                        //根据类型 转成功页面
                        msg = "支付成功";
                    }
                    else
                    {

                    }
                }
                else
                {
                    Response.Redirect("/");
                }
            }

异步:

if (!IsPostBack)
            {
                StreamReader reader = new StreamReader(Request.InputStream);
                String xmlData = reader.ReadToEnd();
                var xdoc = new XmlDocument();
                xdoc.LoadXml(xmlData);
                XmlNode xn = xdoc.SelectSingleNode("xml");
                XmlNodeList xnl = xn.ChildNodes;

                if (xnl.Count == 16)
                {
                    var packageReqHandler = new RequestHandler(Context);
                    packageReqHandler.init();
                    packageReqHandler.setParameter("appid", xnl[0].InnerText);
                    packageReqHandler.setParameter("bank_type", xnl[1].InnerText);
                    packageReqHandler.setParameter("cash_fee", xnl[2].InnerText);
                    packageReqHandler.setParameter("fee_type", xnl[3].InnerText);
                    packageReqHandler.setParameter("is_subscribe", xnl[4].InnerText);
                    packageReqHandler.setParameter("mch_id", xnl[5].InnerText);
                    packageReqHandler.setParameter("nonce_str", xnl[6].InnerText);
                    packageReqHandler.setParameter("openid", xnl[7].InnerText);
                    packageReqHandler.setParameter("out_trade_no", xnl[8].InnerText);
                    packageReqHandler.setParameter("result_code", xnl[9].InnerText);
                    packageReqHandler.setParameter("return_code", xnl[10].InnerText);

                    packageReqHandler.setParameter("time_end", xnl[12].InnerText);
                    packageReqHandler.setParameter("total_fee", xnl[13].InnerText);
                    packageReqHandler.setParameter("trade_type", "JSAPI");
                    packageReqHandler.setParameter("transaction_id", xnl[15].InnerText);
                    string sign = packageReqHandler.CreateMd5Sign("key", WxConfig.appkey);
                    if (sign == xnl[11].InnerText)
                    {
                        //xnl[8].InnerText 订单号
                        if (xnl[9].InnerText == "SUCCESS" && xnl[10].InnerText == "SUCCESS")
                        {
                            if (userorder != null && userorder.OrderState == 0)
                            {
                                //输出该字符告诉微信已接受处理
                                string xmlStr = "<return_code>

下面文件是程序用到的DLL 封装的一些方法
20150902041833

在红色文件中 可以修改配置参数 然后引用到项目中 按照上面的步骤是没问题的 还有一个要注意的是 在你创建订单的同时需要给程序数据量存储一个订单,然后在同步和异步里面都要根据该订单号去处理并且要避免订单重复成功!
图中文件下载地址:WeiXinPay