1.获取用户open_id
/// <summary> /// 获取openid 并返回视图 /// </summary> /// <param name="Code"></param> /// <param name="OrderGuid"></param> /// <returns></returns> public ActionResult VisaPay(string Code, Guid OrderGuid) { try { var appid = "wxxxxxxxxxxxxxxxxxxxxxxx"; var secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; if (string.IsNullOrEmpty(Code)) { //向微信发送请求 获取code string url1 = UrlEncode("http://wechat.yimalx.com/WeChatSite/WeChatPay/VisaPay?orderGuid=" + OrderGuid); var url = string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect", appid, url1); return Redirect(url); } else { //获取token var client = new System.Net.WebClient(); client.Encoding = System.Text.Encoding.UTF8; var url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", appid, secret, Code); var data = client.DownloadString(url); var serializer = new JavaScriptSerializer(); var obj = serializer.Deserialize<Dictionary<string, string>>(data); string accessToken; if (!obj.TryGetValue("access_token", out accessToken)) return Redirect("404"); var opentid = obj["openid"]; var model = OrderInfoManager.Instance.GetById(OrderGuid); ViewData["PayAmount"] = model.PayAmount; ViewData["OrderGuid"] = OrderGuid; string str = WeChatPayHelper.GoToWeCharJSPay(OrderGuid, opentid); CreateLog.SaveLogs("str==============================" + str + "=================================", 1); var codeId = new XmlDocument(); codeId.LoadXml(str); var info = new WeChatInfo(); //8.读取xml节点的值 info.return_code = codeId.SelectSingleNode("xml/return_code").InnerText; info.return_msg = codeId.SelectSingleNode("xml/return_msg").InnerText; info.appid = codeId.SelectSingleNode("xml/appid").InnerText; info.mch_id = codeId.SelectSingleNode("xml/mch_id").InnerText; info.nonce_str = codeId.SelectSingleNode("xml/nonce_str").InnerText; info.openid = opentid; info.sign = codeId.SelectSingleNode("xml/sign").InnerText; info.result_code = codeId.SelectSingleNode("xml/result_code").InnerText; info.prepay_id = codeId.SelectSingleNode("xml/prepay_id").InnerText; info.trade_type = codeId.SelectSingleNode("xml/trade_type").InnerText; string timestamp = WeChatPayHelper.GetTimeStamp(); var res = new Dictionary<string, object> { {"appId", info.appid }, {"nonceStr", info.nonce_str}, {"timeStamp",timestamp}, {"signType","MD5"}, {"package","prepay_id="+info.prepay_id} }; info.sign = WeChatPayHelper.GetSignString(res); info.timeStamp = timestamp; return View(info); } } catch (Exception e) { CreateLog.SaveLogs(e.Message, 0); return Redirect("WeChatSite/WeChatPay/VisaPay?OrderGuid=" + OrderGuid); } }
2.调用统一下单接口生成预付款单
/// <summary> /// 微信客户端内部提交支付申请 /// </summary> /// <param name="orderGuid"></param> /// <returns></returns> [HttpGet] public static string GoToWeCharJSPay(Guid orderGuid, string token) { var weCharUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; var model = OrderInfoManager.Instance.GetById(orderGuid); unifiedorder unOrder = new unifiedorder(); unOrder.appid = ConfigurationManager.AppSettings["wx_appid"]; unOrder.mch_id = ConfigurationManager.AppSettings["wx_mch_id"]; unOrder.nonce_str = Guid.NewGuid().ToString().Replace("-", ""); unOrder.sign = ""; unOrder.body = model.ProductName; unOrder.out_trade_no = model.OrderCode; //payAmountmodel.PayAmount unOrder.total_fee = Convert.ToInt32(model.PayAmount * 100); unOrder.spbill_create_ip = GetWebClientIp(); unOrder.notify_url = ConfigurationManager.AppSettings["wechatUrl"] + "WeChatSite/WeChatPay/ProcessingCallback"; unOrder.trade_type = "JSAPI"; unOrder.openid = token; unOrder.device_info = "WEB"; var dc = new Dictionary<string, object>() { {"appid",unOrder.appid}, {"mch_id",unOrder.mch_id}, {"total_fee",unOrder.total_fee}, {"out_trade_no",unOrder.out_trade_no}, {"body",unOrder.body}, {"notify_url",unOrder.notify_url}, {"trade_type",unOrder.trade_type}, {"nonce_str",unOrder.nonce_str}, {"spbill_create_ip",unOrder.spbill_create_ip}, {"openid",unOrder.openid}, //{"scene_info","h5_info"} }; dc.Add("sign", GetSignString(dc));//签名 //2.将参数转换为xml格式 var sb = new StringBuilder(); sb.Append("<xml>"); foreach (var d in dc) { sb.Append("<" + d.Key + ">" + d.Value + "</" + d.Key + ">"); } sb.Append("</xml>"); //应用场景信息 //1.创建请求连接 var request = (HttpWebRequest)WebRequest.Create(weCharUrl); //2.设置参数 var data = Encoding.UTF8.GetBytes(sb.ToString()); //4.设置属性 request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; //5.将转换后的参数以文件流的形式写入到请求中 using (var stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); } //6.声明变量,获取响应 var response = (HttpWebResponse)request.GetResponse(); //7.以文件流的方式读取响应结果 var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd(); // return responseString; }
3.回调
1).同步回调:前端拉起微信支付界面,判断支付结果
<script> function onBridgeReady() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId": "@Model.appid", //公众号名称,由商户传入 "timeStamp": "@Model.timeStamp", //时间戳,自1970年以来的秒数 "nonceStr": "@Model.nonce_str", //随机串 "package": "prepay_id=@Model.prepay_id", "signType": "MD5", //微信签名方式: "paySign": "@Model.sign" //微信签名 }, function (res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。 if (res.err_msg == "get_brand_wcpay_request:ok") { alert("支付成功"); window.location.href = "/WeChatSite/Home/Index"; } else if (res.err_msg == "get_brand_wcpay_request:cancel") { alert("支付过程中用户取消"); } else if (res.err_msg == "get_brand_wcpay_request:fail") { alert("支付失败"); } } ); } $(".immediate_payment").click(function () { if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } } else { onBridgeReady(); } }); </script>
2)异步:获取微信回台一步返回的结果,(方法地址:请求统一下单API的notify_url字段)
{ 1.获取异步返回的文件流
2.读取文件流并解析文件流,判断执行结果,如果成功则需要验证签名是否正确,
3.签名验证成功执行数据操作,更改本地支付信息。
/// <summary> /// 处理回调数据 /// </summary> public ActionResult ProcessingCallback() { //1.获取微信支付回调信息 string XmlData = getPostStr(); //判断数据是否为空 if (XmlData.IsNotNullOrEmpty()) { DataSet ds = new DataSet(); StringReader sr = new StringReader(XmlData); XmlTextReader dataReader = new XmlTextReader(sr); ds.ReadXml(dataReader); CreateLog.SaveLogs("--------------------XMLData&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" + XmlData + "&&&&&&&&&&&&&&&&&&&", 1); if (ds.Tables[0].Rows[0]["return_code"].ToString() == "SUCCESS") { #region 解析ds获取对象 //将dataset转换为对象 WeChatPaymentReturn wcpr = new WeChatPaymentReturn() { appid = ds.Tables[0].Rows[0]["appid"].ToString(), bank_type = ds.Tables[0].Rows[0]["bank_type"].ToString(), cash_fee = ds.Tables[0].Rows[0]["cash_fee"].ToString(), fee_type = ds.Tables[0].Rows[0]["fee_type"].ToString(), is_subscribe = ds.Tables[0].Rows[0]["is_subscribe"].ToString(), mch_id = ds.Tables[0].Rows[0]["mch_id"].ToString(), nonce_str = ds.Tables[0].Rows[0]["nonce_str"].ToString(), openid = ds.Tables[0].Rows[0]["openid"].ToString(), out_trade_no = ds.Tables[0].Rows[0]["out_trade_no"].ToString(), result_code = ds.Tables[0].Rows[0]["result_code"].ToString(), return_code = ds.Tables[0].Rows[0]["return_code"].ToString(), time_end = ds.Tables[0].Rows[0]["time_end"].ToString(), total_fee = ds.Tables[0].Rows[0]["total_fee"].ToString(), trade_type = ds.Tables[0].Rows[0]["trade_type"].ToString(), transaction_id = ds.Tables[0].Rows[0]["transaction_id"].ToString(), sign = ds.Tables[0].Rows[0]["sign"].ToString(), }; #endregion //4.支付成功之后验证Sign var againSign = new Dictionary<string, object>(); againSign.Add("appid", wcpr.appid); againSign.Add("bank_type", wcpr.bank_type); againSign.Add("cash_fee", wcpr.cash_fee); againSign.Add("fee_type", wcpr.fee_type); againSign.Add("is_subscribe", wcpr.is_subscribe); againSign.Add("mch_id", wcpr.mch_id); againSign.Add("nonce_str", wcpr.nonce_str); againSign.Add("openid", wcpr.openid); againSign.Add("out_trade_no", wcpr.out_trade_no); againSign.Add("result_code", wcpr.result_code); againSign.Add("return_code", wcpr.return_code); againSign.Add("time_end", wcpr.time_end); againSign.Add("total_fee", wcpr.total_fee); againSign.Add("trade_type", wcpr.trade_type); againSign.Add("transaction_id", wcpr.transaction_id); string againSignStr = WeChatPayHelper.GetSignString(againSign); if (wcpr.sign.ToUpper() == againSignStr.ToUpper()) { CreateLog.SaveLogs("####签名验证成功againSignStr######" + againSignStr + "-------sign-------------" + wcpr.sign, 1); #region 处理数据逻辑 //更新订单信息 //添加支付信息 CreateLog.SaveLogs("开始付款", 1); //签名正确 处理订单操作逻辑 var oderInfo = OrderInfoManager.Instance.GetByField("OrderCode", wcpr.out_trade_no).FirstOrDefault(); if (oderInfo.OrderState != (int)OrderState.代付款) { CreateLog.SaveLogs("支付成功!但是在此发出请求", 1); return null; } if (oderInfo != null) { try { OrderInfoManager.Instance.UpdataStatus(oderInfo.Guid, (int) OrderState.已付款); CreateLog.SaveLogs("状态修改结束", 1); PaymentInfo info = new PaymentInfo() { OrderGuid = oderInfo.Guid, PayState = 1, PayMethod = (int)PayMethod.微信支付, Guid = Guid.NewGuid(), Mark = (int)DataMark.正常, PayDateTime = DateTime.Now, PayMoney = Convert.ToDecimal(wcpr.total_fee) / 100, Qid = wcpr.transaction_id }; PaymentInfoManager.Instance.Insert(info); CreateLog.SaveLogs("支付信息添加成功", 1); } catch (Exception e) { CreateLog.SaveLogs("-----Exception" + e,1); throw; } } //CreateLog.SaveLogs("状态修改结束", 1); #endregion } else { CreateLog.SaveLogs("####签名验证失败againSignStr######" + againSignStr + "-------sign-------------" + wcpr.sign, 1); } } else { // 返回信息,如非空,为错误原因 签名失败 参数格式校验错误 string return_msg = ds.Tables[0].Rows[0]["return_msg"].ToString(); CreateLog.SaveLogs("支付失败", 1); } } return View(); } //getPostStr /// <summary> /// 获取微信支付毁掉的数据; /// </summary> /// <returns></returns> public string getPostStr() { Int32 intLen = Convert.ToInt32(Request.InputStream.Length); byte[] b = new byte[intLen]; Request.InputStream.Read(b, 0, intLen); return System.Text.Encoding.UTF8.GetString(b); }
}
微信支付辅助方法
/// <summary> /// 获取客户端ip /// </summary> /// <returns>返回客户端IP地址</returns> public static string GetWebClientIp() { HttpRequest request = HttpContext.Current.Request; string result = request.ServerVariables["HTTP_X_FORWARDED_FOR"]; string a = request.UserHostAddress; if (String.IsNullOrEmpty(result)) { result = request.ServerVariables["REMOTE_ADDR"]; } if (String.IsNullOrEmpty(result)) { result = request.UserHostAddress; } if (String.IsNullOrEmpty(result)) { result = "0.0.0.0"; } return result; //string userIP = "IP"; //try //{ // if (System.Web.HttpContext.Current == null //|| System.Web.HttpContext.Current.Request == null //|| System.Web.HttpContext.Current.Request.ServerVariables == null) // return ""; // string CustomerIP = ""; // //CDN加速后取到的IP // CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"]; // if (!string.IsNullOrEmpty(CustomerIP)) // { // return CustomerIP; // } // CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; // if (!String.IsNullOrEmpty(CustomerIP)) // return CustomerIP; // if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null) // { // CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; // if (CustomerIP == null) // CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; // } // else // { // CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; // } // if (string.Compare(CustomerIP, "unknown", true) == 0) // return System.Web.HttpContext.Current.Request.UserHostAddress; // return CustomerIP; //} //catch { } //return userIP; string user_IP; if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null) { user_IP = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString(); } else { user_IP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"].ToString(); } return user_IP; } /// <summary> /// 获取Sign签名 /// </summary> /// <param name="dic">键值对集合</param> /// <returns>字符串类型的签名</returns> public static string GetSignString(Dictionary<string, object> dic) { string key = WebConfigurationManager.AppSettings["wx_key"].ToString(); ;//商户平台 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; //MD5 sign = FormsAuthentication.HashPasswordForStoringInConfigFile(sign, "MD5").ToUpper(); return sign; } /// <summary> /// 时间格式化 /// </summary> /// <param name="date"></param> /// <returns></returns> public static string Format(DateTime date) { var dates = ""; dates += date.Year; dates += date.Month; dates += date.Date; dates += date.Hour; dates += date.Minute; dates += date.Second; return dates; } /// <summary> /// 获取时间戳 /// </summary> /// <returns></returns> public static string GetTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); }
微信支付实体类
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Travel.WeChat.ViewModel.WeiPay { public class unifiedorder { /// <summary> /// 公众账号ID /// </summary> public string appid { get; set; } /// <summary> /// 商户号 /// </summary> public string mch_id { get; set; } /// <summary> /// 设备号 /// </summary> public string device_info { get; set; } /// <summary> /// 随机字符串 /// </summary> public string nonce_str { get; set; } /// <summary> /// 签名 /// </summary> public string sign { get; set; } public string sign_type { get; set; } /// <summary> /// 商品描述 /// </summary> public string body { get; set; } public string detail { get; set; } public string attach { get; set; } /// <summary> /// 商户订单号 /// </summary> public string out_trade_no { get; set; } public string fee_type { get; set; } /// <summary> /// 总金额 /// </summary> public int total_fee { get; set; } /// <summary> /// 终端IP /// </summary> public string spbill_create_ip { get; set; } public string time_start { get; set; } public string time_expire { get; set; } public string goods_tag { get; set; } /// <summary> /// 通知地址 /// </summary> public string notify_url { get; set; } /// <summary> /// 交易类型 /// </summary> public string trade_type { get; set; } public string product_id { get; set; } public string limit_pay { get; set; } public string openid { get; set; } public List<h5_info> scene_info { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Travel.WeChat.ViewModel.WeiPay { public class WeChatInfo { //统一下单接口返回值 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 openid { get; set; } public string sign { get; set; } public string result_code { get; set; } public string prepay_id { get; set; } public string trade_type { get; set; } public string timeStamp { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Travel.WeChat.ViewModel.WeiPay { public class WeChatPaymentReturn { //异步回调的返回信息 public string appid { get; set; } public string bank_type { get; set; } public string cash_fee { get; set; } public string fee_type { get; set; } public string is_subscribe { get; set; } public string mch_id { get; set; } public string nonce_str { get; set; } public string openid{ get; set; } public string out_trade_no{ get; set; } public string result_code{ get; set; } public string return_code{ get; set; } public string sign{ get; set; } public string time_end{ get; set; } public string total_fee{ get; set; } public string trade_type{ get; set; } public string transaction_id{ get; set; } } }