首先要理解微信支付的流程。需二次握手。html
先把訂單信息,金額傳給微信,微信返回相應信息,再調用微信支付。前端
詳細的查看微信公衆號的相關資料windows
/// <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> /// 企業付款接口( 開通條件: /// 一、商戶號已入駐90日 /// 二、商戶號有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()); }