首先要理解微信支付的流程。需二次握手。
先把订单信息,金额传给微信,微信返回相应信息,再调用微信支付。
详细的查看微信公众号的相关资料
/// <summary> /// 新建一个普通订单 /// </summary> /// <returns></returns> public Entity NewOrder(Entity en) { string WeiXinOpenID = en.GetValue("WeiXinOpenID").TryString(); string AddressID = en.GetValue("AddressID").TryString(); string OrderMessage = en.GetValue("OrderMessage").TryString(); int OrderStatus = (int)OrderEnum.OrderStatus.待付款; string CommodityList = en.GetValue("CommodityList").TryString(); string CouponRecordGuid = en.GetValue("CouponRecordGuid").TryString(); //优惠券 decimal ManorMoney = en.GetValue("ManorMoney").TryDecimal(); //庄园币 string OrderGuid = System.Guid.NewGuid().ToString(); try { using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope()) { #region 支付信息 string PayRecordID = System.Guid.NewGuid().TryString(); int PayStatus = (int)OrderEnum.PayStatus.未支付; string OrderNum = OrderServiceDA.NewOrder(OrderGuid, WeiXinOpenID, AddressID, OriginalTotalPrice, SaleTotalPrice, OrderMessage, OrderStatus); //添加支付记录 OrderServiceDA.AddPayRecord(PayRecordID, SaleTotalPrice, WeiXinOpenID, OrderGuid, PayStatus); decimal WeixinPayMoney = SaleTotalPrice - (ManorMoney + Couponvalue); if (WeixinPayMoney > 0) { int PayType = (int)OrderEnum.PayType.微信支付; OrderServiceDA.AddPayRecordWeixinDetail(PayRecordID, PayType, WeixinPayMoney, PayStatus); OrderServiceDA.UpdatePayRecordPayType(PayRecordID, PayType); WeixinPayService WeixinPayService = new WeixinPayService(); PaymentData payData = new PaymentData(); payData.SetValue("attach", OrderNum); payData.SetValue("body", "微信在线支付"); payData.SetValue("out_trade_no", OrderNum); payData.SetValue("trade_type", "JSAPI"); payData.SetValue("total_fee", (WeixinPayMoney * 100).ToInt32());//付款金额,单位分 payData.SetValue("openid", WeiXinOpenID); PaymentData returnData = WeixinPayService.UnifiedOrder(payData); string prepay_id = ""; string SignKey = ""; string TimeStamp = ""; string NonceStr = ""; string returnCode = returnData.GetValue("return_code").ToString(); if (returnCode.ToUpper().Equals("SUCCESS")) { #region 获取支付签名 //获取支付ID prepay_id = returnData.GetValue("prepay_id").ToString(); PaymentData jsApiParam = new PaymentData(); NonceStr = WeixinPayService.GenerateNonceStr(); TimeStamp = WeixinPayService.GenerateTimeStamp(); jsApiParam.SetValue("appId", WeixinPayService.AppId); jsApiParam.SetValue("timeStamp", TimeStamp); jsApiParam.SetValue("nonceStr", NonceStr); jsApiParam.SetValue("package", "prepay_id=" + prepay_id); jsApiParam.SetValue("signType", "MD5"); SignKey = jsApiParam.MakeSign(WeixinPayService.SignKey); #endregion } else { string ErrorMessage = returnData.GetValue("return_msg").ToString(); FaultException exception = new FaultException(ErrorMessage); throw (exception); }
//保存信息,用于前端再进行调起支付。 OrderServiceDA.UpdateWeixinPayRecord(PayRecordID, prepay_id, SignKey, TimeStamp, NonceStr); } else { if (ManorMoney == 0) { int PayType = (int)OrderEnum.PayType.优惠券; OrderServiceDA.UpdatePayRecordPayType(PayRecordID, PayType); } else { int PayType = (int)OrderEnum.PayType.庄园币; OrderServiceDA.UpdatePayRecordPayType(PayRecordID, PayType); } } #endregion scope.Complete(); } } catch (Exception ex) { Entity result = new Entity(new PropertyCollection()); result.AddSimple("Status", -10, typeof(int)); result.AddSimple("StatusText", ex.Message, typeof(string)); return result; } Entity resultEntity = new Entity(new PropertyCollection()); resultEntity.AddSimple("Status", 115, typeof(int)); resultEntity.AddSimple("StatusText", "操作成功.", typeof(string)); resultEntity.AddSimple("OrderGuid", OrderGuid, typeof(string)); return resultEntity; }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using TalentCloud.Common; using TalentCloud.Base.Utils; using TalentCloud.Agriculture.Services; using System.Security.Cryptography; using System.IO; using System.Net; using System.Security.Cryptography.X509Certificates; using TalentCloud.Common.Log; namespace TalentCloud.Agriculture.Weixin.Services { public class WeixinPayService { /// <summary> /// 微信分配的AppId /// </summary> public string AppId = TCConfigManager.GetConfig("WeixinPayAppid").TryToString(); /// <summary> /// 公众号的支付密钥appsecret /// </summary> public string AppSecret = TCConfigManager.GetConfig("WeixinPayAppsecret").TryToString(); /// <summary> /// 当前用户IP /// </summary> public string Ip = WCFClientInfo.ClientIP; /// <summary> /// 商户号 /// </summary> public string MchId = TCConfigManager.GetConfig("MchId").TryToString(); /// <summary> /// 签名Key /// </summary> public string SignKey = TCConfigManager.GetConfig("SignKey").TryToString(); //=======【证书路径设置】===================================== /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要) */ public string CertPath = TCConfigManager.GetConfig("certPath").TrySafeString(); /// <summary> /// 证书密码,windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户ID /// </summary> public string CertPassword = TCConfigManager.GetConfig("certpsd").TrySafeString(); /// <summary> /// 支付结果通知回调url,用于商户接收支付结果 /// </summary> public string NOTIFY_URL =TCConfigManager.GetConfig("WebSite").TryToString()+ "/Weixin/PayCallback.aspx"; /// <summary> /// 生成随机串,随机串包含字母或数字 @return 随机串 /// </summary> /// <returns></returns> public string GenerateNonceStr() { return Guid.NewGuid().ToString().Replace("-", ""); } /// <summary> /// 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 /// </summary> /// <returns></returns> public string GenerateTimeStamp() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } /// <summary> /// * 统一下单 ///* @param WxPaydata inputObj 提交给统一下单API的参数 ///* @param int timeOut 超时时间 ///* @throws WxPayException ///* @return 成功时返回,其他抛异常 /// <returns></returns> public PaymentData UnifiedOrder(PaymentData inputObj, int timeOut = 15) { string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //检测必填参数 if (!inputObj.IsSet("out_trade_no")) { throw new Exception("缺少统一支付接口必填参数out_trade_no!"); } else if (!inputObj.IsSet("body")) { throw new Exception("缺少统一支付接口必填参数body!"); } else if (!inputObj.IsSet("total_fee")) { throw new Exception("缺少统一支付接口必填参数total_fee!"); } else if (!inputObj.IsSet("trade_type")) { throw new Exception("缺少统一支付接口必填参数trade_type!"); } //关联参数 if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid")) { throw new Exception("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id")) { throw new Exception("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } //异步通知url未设置,则使用配置文件中的url if (!inputObj.IsSet("notify_url")) { inputObj.SetValue("notify_url", NOTIFY_URL);//异步通知url } inputObj.SetValue("appid", AppId);//公众账号ID inputObj.SetValue("mch_id", MchId);//商户号 inputObj.SetValue("spbill_create_ip", Ip);//终端ip inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 //签名 inputObj.SetValue("sign", inputObj.MakeSign(SignKey)); string xml = inputObj.ToXml(); string response = HttpService.Post(xml, url, false, timeOut, "", ""); PaymentData result = new PaymentData(); result.FromXml(response); return result; } /// <summary> /// 申请退款 /// </summary> /// <param name="inputObj">提交给申请退款API的参数</param> /// <param name="CertPath">证书路径</param> /// <param name="CertPassword">证书密码</param> /// <param name="timeOut">超时时间</param> /// <returns></returns> public PaymentData Refund(PaymentData inputObj, int timeOut = 6) { string url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //检测必填参数 if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id")) { throw new Exception("退款申请接口中,out_trade_no、transaction_id至少填一个!"); } else if (!inputObj.IsSet("out_refund_no")) { throw new Exception("退款申请接口中,缺少必填参数out_refund_no!"); } else if (!inputObj.IsSet("total_fee")) { throw new Exception("退款申请接口中,缺少必填参数total_fee!"); } else if (!inputObj.IsSet("refund_fee")) { throw new Exception("退款申请接口中,缺少必填参数refund_fee!"); } else if (!inputObj.IsSet("op_user_id")) { throw new Exception("退款申请接口中,缺少必填参数op_user_id!"); } inputObj.SetValue("appid", AppId);//公众账号ID inputObj.SetValue("mch_id", MchId);//商户号 inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 inputObj.SetValue("sign", inputObj.MakeSign(SignKey));//签名 string xml = inputObj.ToXml(); string response = HttpService.Post(xml, url, true, timeOut, CertPath, CertPassword); //将xml格式的结果转换为对象以返回 PaymentData result = new PaymentData(); result.FromXml(response); return result; } /// <summary> /// 企业付款接口( 开通条件: /// 1、商户号已入驻90日 /// 2、商户号有30天连续正常交易 /// 登录微信支付商户平台-产品中心,开通企业付款。) /// </summary> /// <param name="inputObj">参数</param> /// <param name="CertPath">证书路径</param> /// <param name="CertPassword">证书密码</param> /// <param name="timeOut">超时时间</param> /// <returns></returns> public PaymentData Transfers(PaymentData inputObj, int timeOut = 6) { string url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; #region 检测必要参数 //检测必填参数 if (!inputObj.IsSet("partner_trade_no") && !inputObj.IsSet("partner_trade_no")) { throw new Exception("企业付款接口中,缺少必填参数partner_trade_no!"); } if (!inputObj.IsSet("openid")) { throw new Exception("企业付款接口中,缺少必填参数openid!"); } if (!inputObj.IsSet("check_name")) { throw new Exception("企业付款接口中,缺少必填参数check_name!"); } else { string checkName = inputObj.GetValue("check_name").ToString(); switch (checkName) { case "FORCE_CHECK": case "OPTION_CHECK": if (!inputObj.IsSet("check_name")) { throw new Exception("企业付款接口中,缺少必填参数re_user_name!"); } break; default: break; } } if (!inputObj.IsSet("amount")) { throw new Exception("企业付款接口中,缺少必填参数amount!"); } if (!inputObj.IsSet("desc")) { throw new Exception("企业付款接口中,缺少必填参数desc!"); } if (!inputObj.IsSet("spbill_create_ip")) { throw new Exception("企业付款接口中,缺少必填参数spbill_create_ip!"); } #endregion #region 添加公共参数 inputObj.SetValue("mch_appid", AppId);//公众账号ID inputObj.SetValue("mchid", MchId);//商户号 inputObj.SetValue("spbill_create_ip", Ip);//随机字符串 inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串 inputObj.SetValue("sign", inputObj.MakeSign(SignKey));//签名 #endregion string xml = inputObj.ToXml(); var start = DateTime.Now; string response = HttpService.Post(xml, url, true, timeOut, CertPath, CertPassword); LogHelper.WriteFileLog("TransfersData", response); PaymentData result = new PaymentData(); result.FromXml(response); return result; } #region 微信发红发,未事项,签名失败问题,未解决 /// <summary> /// 微信红包 /// </summary> public class PayWeiXin { public string nonce_str { get; set; } public string sign { get; set; } public string mch_billno { get; set; } public string mch_id { get; set; } public string wxappid { get; set; } public string nick_name { get; set; } public string send_name { get; set; } public string re_openid { get; set; } public int total_amount { get; set; } public int min_value { get; set; } public int max_value { get; set; } public int total_num { get; set; } public string wishing { get; set; } public string client_ip { get; set; } public string act_id { get; set; } public string act_name { get; set; } public string remark { get; set; } public string logo_imgurl { get; set; } public string share_content { get; set; } public string share_url { get; set; } public string share_imgurl { get; set; } } /// <summary> /// 调用微信支付接口,发送红包 /// </summary> /// <param name="payForWeiXin"></param> /// <returns></returns> public string PayRedBag(PaymentData inputObj) { ////商户号 inputObj.SetValue("mch_id", MchId); //商户 appid inputObj.SetValue("wxappid", AppId); inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 //签名 inputObj.SetValue("sign", inputObj.MakeSign(SignKey)); string xml = inputObj.ToXml(); string result = string.Empty; try { result = PostPage("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", xml); LogHelper.WriteFileLog("PayRedBagpostData", xml); LogHelper.WriteFileLog("PayRedBag", result); } catch (Exception ex) { LogHelper.WriteFileLog("PayRedBagError", ex.Message); } return result; } /// <summary> /// post微信请求 /// </summary> /// <param name="posturl"></param> /// <param name="postData"></param> /// <returns></returns> public string PostPage(string posturl, string postData) { Stream outstream = null; Stream instream = null; StreamReader sr = null; HttpWebResponse response = null; HttpWebRequest request = null; Encoding encoding = Encoding.UTF8; byte[] data = encoding.GetBytes(postData); // 准备请求... try { //CerPath证书路径 string certPath = TCConfigManager.GetConfig("certPath").TrySafeString(); //证书密码 string password = TCConfigManager.GetConfig("certpsd").TrySafeString(); X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, password, X509KeyStorageFlags.MachineKeySet); // 设置参数 request = WebRequest.Create(posturl) as HttpWebRequest; CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; request.AllowAutoRedirect = true; request.Method = "POST"; request.ContentType = "text/xml"; request.ContentLength = data.Length; request.ClientCertificates.Add(cert); outstream = request.GetRequestStream(); outstream.Write(data, 0, data.Length); outstream.Close(); //发送请求并获取相应回应数据 response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才开始向目标网页发送Post请求 instream = response.GetResponseStream(); sr = new StreamReader(instream, encoding); //返回结果网页(html)代码 string content = sr.ReadToEnd(); string err = string.Empty; return content; } catch (Exception ex) { string err = ex.Message; return string.Empty; } } /// <summary> /// Md5加密 /// </summary> /// <param name="s"></param> /// <returns></returns> public static String Encrypt(String s) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(s); bytes = md5.ComputeHash(bytes); md5.Clear(); string ret = ""; for (int i = 0; i < bytes.Length; i++) { ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0'); } return ret.PadLeft(32, '0'); } public string RandomStr(string str, int Length) { string result = string.Empty; Random rd = new Random(); for (int i = 0; i < Length; i++) { result += str[rd.Next(str.Length)]; } return result; } #endregion } }
//弹出微信支付页面 WeixinJSBridge.invoke('getBrandWCPayRequest', { "appId": data.AppID, //公众号名称,由商户传入 "timeStamp": data.TimeStamp, //时间戳,自1970年以来的秒数 "nonceStr": data.nonceStr, //随机串 "package": "prepay_id="+data.prepay_id, "signType": "MD5", //微信签名方式: "paySign": data.SignKey //微信签名 }, function (res) { switch (res.err_msg) { case "get_brand_wcpay_request:ok": layer.open({ content: '充值成功', skin: 'msg', time: 2 //2秒后自动关闭 }); browserHistory.push('/WeChat/dist/member/wallet/'); break; case "get_brand_wcpay_request:cancel": break; case "get_brand_wcpay_request:fail": layer.open({ content: '充值失败!', skin: 'msg', time: 2 //2秒后自动关闭 }); break; default: } });
public partial class PayCallback : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { StreamReader reader = new StreamReader(Request.InputStream, Encoding.UTF8); string postStr = reader.ReadToEnd(); reader.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(postStr); string ReturnCode = doc.SelectSingleNode("//result_code").InnerText;//获取支付结果代码 StringBuilder xmlStr = new StringBuilder(); LogHelper.WriteFileLog("PayCallback", ReturnCode); if (ReturnCode.ToUpper().Equals("SUCCESS")) { string strOrderNo = doc.SelectSingleNode("//out_trade_no").InnerText; //获取微信支付流水号 string weChatTransaction_Id = doc.SelectSingleNode("//transaction_id").InnerText; string WeiXinOpenID = doc.SelectSingleNode("//openid").InnerText; try { //获取订单号 WeiXinService WeiXinService = new WeiXinService(); Entity result= WeiXinService.PayOrder(WeiXinOpenID, strOrderNo, weChatTransaction_Id); string Status = result.GetValue("Status").ToString(); string StatusText = result.GetValue("StatusText").ToString(); LogHelper.WriteFileLog("Pay", WeiXinOpenID + "," + strOrderNo + "," + weChatTransaction_Id + "," + Status + "," + StatusText); } catch (Exception ex) { LogHelper.WriteFileLog("PayError", ex.Message + "," + WeiXinOpenID + "," + strOrderNo + "," + weChatTransaction_Id); //记录错误 throw ex; } #region 通知微信后台支付成功 Response.ContentType = "text/xml"; xmlStr.AppendLine("<xml>"); xmlStr.AppendFormat("<return_code><![CDATA[SUCCESS]]></return_code>"); xmlStr.AppendFormat("<return_msg><![CDATA[OK]]></return_msg>"); xmlStr.AppendFormat("</xml>"); #endregion } else { #region 通知微信后台支付失败 Response.ContentType = "text/xml"; xmlStr.AppendLine("<xml>"); xmlStr.AppendFormat("<return_code><![CDATA[FAIL]]></return_code>"); xmlStr.AppendFormat("<return_msg><![CDATA[支付失败]]></return_msg>"); xmlStr.AppendFormat("</xml>"); #endregion } Response.Write(xmlStr.ToString()); }