ASP.NET MVC 微信公众号支付
1、首先到官网下载微信API。
2、解压后将cert、lib两个文件夹复制到项目更目录下。
3、微信公众号支付
控制器代码
1 /// <summary> 2 /// 生成订单及JSAPI提交参数 3 /// </summary> 4 /// <param name="tmpModel"></param> 5 /// <returns></returns> 6 public ActionResult GenerateOrder(string orderno) 7 { 8 //string wxEditAddrParam; 9 10 JsApiPay jsapipay = new JsApiPay(); 11 try 12 { 13 GetOpenidAndAccessToken(); 14 jsapipay.openid = Session["openid"].ToString(); 15 jsapipay.access_token = Session["access_token"].ToString(); 16 Log.Info(this.GetType().ToString(),"openid:"+jsapipay.openid+",access_token:"+jsapipay.access_token); 17 //wxEditAddrParam = GetEditAddressParameters(); 18 //ViewBag.wxEditAddrParam = wxEditAddrParam; 19 ViewBag.openid = jsapipay.openid; 20 } 21 catch (Exception) 22 { 23 throw; 24 } 25 return View(); 26 } 27 28 /** 29 * 30 * 网页授权获取用户基本信息的全部过程 31 * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html 32 * 第一步:利用url跳转获取code 33 * 第二步:利用code去获取openid和access_token 34 * 35 */ 36 private void GetOpenidAndAccessToken() 37 { 38 if (!string.IsNullOrEmpty(Request.QueryString["code"])) 39 { 40 string code = Request.QueryString["code"]; 41 GetOpenidAndAccessTokenFromCode(code); 42 } 43 else 44 { 45 string host = Request.Url.Host; 46 string path = Request.Url.PathAndQuery; 47 string redirect_uri = HttpUtility.UrlEncode("http://" + host + path); 48 //string redirect_uri = HttpUtility.UrlEncode("http://gzh.lmx.ren"); 49 WxPayData data = new WxPayData(); 50 data.SetValue("appid", PublicConst.Wx_appid); 51 data.SetValue("redirect_uri", redirect_uri); 52 data.SetValue("response_type", "code"); 53 data.SetValue("scope", "snsapi_base"); 54 data.SetValue("state", "STATE" + "#wechat_redirect"); 55 string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl(); 56 Response.Redirect(url); 57 } 58 } 59 60 public void GetOpenidAndAccessTokenFromCode(string code) 61 { 62 try 63 { 64 WxPayData data = new WxPayData(); 65 data.SetValue("appid", WxPayConfig.APPID); 66 data.SetValue("secret", WxPayConfig.APPSECRET); 67 data.SetValue("code", code); 68 data.SetValue("grant_type", "authorization_code"); 69 string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl(); 70 71 //请求url以获取数据 72 string result = HttpService.Get(url); 73 74 //Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result); 75 76 //保存access_token,用于收货地址获取 77 JsonData jd = JsonMapper.ToObject(result); 78 79 Session["access_token"] = (string)jd["access_token"]; 80 Session["openid"] = (string)jd["openid"]; 81 } 82 catch (Exception ex) 83 { 84 throw new WxPayException(ex.ToString()); 85 } 86 } 87 88 public string GetEditAddressParameters() 89 { 90 string parameter = ""; 91 try 92 { 93 string host = Request.Url.Host; 94 string path = Request.Path; 95 string queryString = Request.Url.Query; 96 //这个地方要注意,参与签名的是网页授权获取用户信息时微信后台回传的完整url 97 string url = "http://" + host + path + queryString; 98 99 //构造需要用SHA1算法加密的数据 100 WxPayData signData = new WxPayData(); 101 signData.SetValue("appid", WxPayConfig.APPID); 102 signData.SetValue("url", url); 103 signData.SetValue("timestamp", WxPayApi.GenerateTimeStamp()); 104 signData.SetValue("noncestr", WxPayApi.GenerateNonceStr()); 105 signData.SetValue("accesstoken", Session["access_token"]); 106 string param = signData.ToUrl(); 107 108 Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : " + param); 109 //SHA1加密 110 string addrSign = FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1"); 111 Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : " + addrSign); 112 113 //获取收货地址js函数入口参数 114 WxPayData afterData = new WxPayData(); 115 afterData.SetValue("appId", WxPayConfig.APPID); 116 afterData.SetValue("scope", "jsapi_address"); 117 afterData.SetValue("signType", "sha1"); 118 afterData.SetValue("addrSign", addrSign); 119 afterData.SetValue("timeStamp", signData.GetValue("timestamp")); 120 afterData.SetValue("nonceStr", signData.GetValue("noncestr")); 121 122 //转为json格式 123 parameter = afterData.ToJson(); 124 Log.Debug(this.GetType().ToString(), "Get EditAddressParam : " + parameter); 125 } 126 catch (Exception ex) 127 { 128 Log.Error(this.GetType().ToString(), ex.ToString()); 129 throw new WxPayException(ex.ToString()); 130 } 131 132 return parameter; 133 } 134 135 [HttpPost] 136 public JsonResult CreateWxPayOrder(string openid,string orderno) 137 { 138 Log.Info(this.GetType().ToString(), "生成订单 : openid:" + openid + ",orderno=" + orderno); 139 ResponseDto<string> ret = new ResponseDto<string>(); 140 ret.IsSuccess = false; 141 var order = _order.QueryFirstOrDefault(c => c.OrderNo == orderno); //订单信息 142 var orderDetail = _orderDetail.QueryFirstOrDefault(c => c.OrderNo == orderno); //订单明细 143 JsApiPay jsApiPay = new JsApiPay(); 144 jsApiPay.openid = openid; 145 jsApiPay.total_fee = Convert.ToInt32(order.OrderAmount * 100); //付款金额 146 try 147 { 148 WxPayData unifiedOrderResult = GetUnifiedOrderResult(order,orderDetail,ref jsApiPay); 149 //ViewBag.wxJsApiParam = jsApiPay.GetJsApiParameters(); 150 ret.Data = jsApiPay.GetJsApiParameters(); 151 ret.IsSuccess = true; 152 } 153 catch (Exception ex) 154 { 155 Log.Info(this.GetType().ToString(), ex.StackTrace); 156 ret.ErrMessage = ex.Message; 157 } 158 return Json(ret); 159 } 160 161 public WxPayData GetUnifiedOrderResult(MXOrdersDto order,MXOrderDetailsDto detail,ref JsApiPay api) 162 { 163 WxPayData data = new WxPayData(); 164 data.SetValue("body", detail.ProductName); 165 data.SetValue("attach", "XX网订单"); 166 data.SetValue("out_trade_no", order.OrderNo); 167 data.SetValue("total_fee", Convert.ToInt32(order.OrderAmount * 100)); 168 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss")); 169 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss")); 170 data.SetValue("goods_tag", detail.ProductName); 171 data.SetValue("trade_type", "JSAPI"); 172 data.SetValue("openid", api.openid); 173 data.SetValue("appid", PublicConst.Wx_appid);//公众账号ID 174 data.SetValue("mch_id", PublicConst.Wx_wchid);//商户号 175 176 Log.Error(this.GetType().ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(data)); 177 WxPayData result = WxPayApi.UnifiedOrder(data); 178 if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "") 179 { 180 Log.Error(this.GetType().ToString(), "UnifiedOrder response error!"); 181 throw new WxPayException("UnifiedOrder response error!"); 182 } 183 api.unifiedOrderResult = result; 184 return result; 185 } 186 187 /// <summary> 188 /// 获取code 189 /// </summary> 190 /// <returns></returns> 191 [HttpPost] 192 public ActionResult getCode() 193 { 194 object objResult = ""; 195 if (Session["url"] != null) 196 { 197 objResult = Session["url"].ToString(); 198 } 199 else 200 { 201 objResult = "url为空。"; 202 } 203 return Json(objResult); 204 } 205 206 [HttpPost] 207 public JsonResult WxUpdateOrder(string orderno) 208 { 209 var order = _order.QueryFirstOrDefault(c => c.OrderNo == orderno); 210 if (order != null) 211 { 223 //这里写入自己的订单处理逻辑; 224 return Json(true); 225 } 226 return Json(false); 227 } 228 229 /// <summary> 230 /// 接收从微信支付后台发送过来的数据并验证签名 231 /// </summary> 232 /// <returns>微信支付后台返回的数据</returns> 233 private WxPayData GetNotifyData() 234 { 235 //接收从微信后台POST过来的数据 236 System.IO.Stream s = Request.InputStream; 237 int count = 0; 238 byte[] buffer = new byte[1024]; 239 StringBuilder builder = new StringBuilder(); 240 while ((count = s.Read(buffer, 0, 1024)) > 0) 241 { 242 builder.Append(Encoding.UTF8.GetString(buffer, 0, count)); 243 } 244 s.Flush(); 245 s.Close(); 246 s.Dispose(); 247 248 Log.Info(this.GetType().ToString(), "Receive data from WeChat : " + builder.ToString()); 249 250 //转换数据格式并验证签名 251 WxPayData data = new WxPayData(); 252 try 253 { 254 data.FromXml(builder.ToString()); 255 } 256 catch (WxPayException ex) 257 { 258 //若签名错误,则立即返回结果给微信支付后台 259 WxPayData res = new WxPayData(); 260 res.SetValue("return_code", "FAIL"); 261 res.SetValue("return_msg", ex.Message); 262 Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml()); 263 Response.Write(res.ToXml()); 264 Response.End(); 265 } 266 267 Log.Info(this.GetType().ToString(), "Check sign success"); 268 return data; 269 }
GenerateOrder.cshtml 页面代码:(需要url传入订单号)
1 <!DOCTYPE html> 2 3 <html> 4 <head> 5 <meta name="viewport" content="width=device-width" /> 6 <title>生成微信订单并支付</title> 7 <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script> 9 </head> 10 <body> 11 <p id="pmsg">生成订单中,请稍候。。。</p> 12 <input id="txtOrderNo" type="hidden" value="@Request.QueryString["orderno"]" /> 13 <input type="hidden" value="@Request.QueryString["code"]" /> 14 <input id="txtOpenID" type="hidden" value="@ViewBag.openid" /> 15 <script type="text/javascript"> 16 $(function () { 17 //if (typeof WeixinJSBridge == "undefined") { 18 // if (document.addEventListener) { 19 // document.addEventListener('WeixinJSBridgeReady', editAddress, false); 20 // } 21 // else if (document.attachEvent) { 22 // document.attachEvent('WeixinJSBridgeReady', editAddress); 23 // document.attachEvent('onWeixinJSBridgeReady', editAddress); 24 // } 25 // //jsApiCall(); 26 //} 27 //else { 28 // editAddress(); 29 //} 60 callpay(); 61 }) 62 //获取url的参数 63 function getQueryString(name) { 64 var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 65 var r = window.location.search.substr(1).match(reg); 66 if (r != null) return unescape(r[2]); return null; 67 } 68 function editAddress() { 69 WeixinJSBridge.invoke( 70 'editAddress', 71 '', 72 function (res) { 73 var addr1 = res.provinceFirstStageName; 74 var addr2 = res.addressCitySecondStageName; 75 var addr3 = res.addressCountiesThirdStageName; 76 var addr4 = res.addressDetailInfo; 77 var tel = res.telNumber; 78 var addr = addr1 + addr2 + addr3 + addr4; 79 alert(addr + ":" + tel); 80 alert(res.err_code + res.err_desc + res.err_msg); 91 } 92 ); 93 } 94 function onBridgeReady(json) { 95 WeixinJSBridge.invoke( 96 'getBrandWCPayRequest', { 97 "appId": json.appId, //公众号名称,由商户传入 98 "timeStamp": json.timeStamp, //时间戳,自1970年以来的秒数 99 "nonceStr": json.nonceStr, //随机串 100 "package": json.packageValue, 101 "signType": "MD5", //微信签名方式: 102 "paySign": json.paySign //微信签名 103 }, 104 function (res) { 105 //alert(res.err_code + res.err_desc + res.err_msg); 106 if (res.err_msg == "get_brand_wcpay_request:ok") { 107 //alert("支付成功,请稍后查询余额,如有疑问,请联系管理员."); 108 //fAlreadyPay();
<!--这里写入回传的处理逻辑--> 109 $.post("/WxUpdateOrder/?orderno="+$("#txtOrderNo").val(),function(data){ 110 111 }); 112 } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 113 } 114 ); 115 } 116 //调用微信JS api 支付 117 function jsApiCall() { 118 $.ajax({ 119 type: "post", 120 url: "/CreateWxPayOrder/?openid=" + $("#txtOpenID").val() + "&orderno=" + $("#txtOrderNo").val(), 121 async: false, 122 success: function (data) { 123 var json = $.parseJSON(data.Data); 124 $("#pmsg").text("订单生成成功,转到支付界面中。。。"); 125 //var json = eval("(" + msg + ")");//转换后的JSON对象 126 WeixinJSBridge.invoke( 127 'getBrandWCPayRequest', { 128 "appId": json.appId, //公众号名称,由商户传入 129 "timeStamp": json.timeStamp, //时间戳,自1970年以来的秒数 130 "nonceStr": json.nonceStr, //随机串 131 "package": json.package, 132 "signType": "MD5", //微信签名方式: 133 "paySign": json.paySign //微信签名 134 }, 135 function (res) { 136 //alert(res.err_code + res.err_desc + res.err_msg); 137 if (res.err_msg == "get_brand_wcpay_request:ok") { 138 //alert("支付成功,请稍后查询余额,如有疑问,请联系管理员."); 139 //fAlreadyPay(); 140 $.post("/WxUpdateOrder/?orderno=" + $("#txtOrderNo").val(), function (data) { 141 $("#pmsg").text("支付完成"); 143 }); 144 } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 145 } 146 ); 147 }, 148 error: function (XMLHttpRequest, textStatus, errorThrown) { 149 alert(XMLHttpRequest.status); 150 alert(XMLHttpRequest.readyState); 151 alert(textStatus); 152 } 153 }) 169 } 170 171 function callpay() { 172 if (typeof WeixinJSBridge == "undefined") { 173 if (document.addEventListener) { 174 document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); 175 } 176 else if (document.attachEvent) { 177 document.attachEvent('WeixinJSBridgeReady', jsApiCall); 178 document.attachEvent('onWeixinJSBridgeReady', jsApiCall); 179 } 180 //jsApiCall(); 181 } 182 else { 183 jsApiCall(); 184 } 185 } 186 187 </script> 188 </body> 189 </html>