1. 程式人生 > >C#微信支付(六)—— 通知回撥

C#微信支付(六)—— 通知回撥

這是重頭戲了,修改訂單狀態一般就是兩個地方,一個是前臺輪訓後發現微信訂單完成後修改狀態,另一個就是通知回撥那了。

通知回撥類,修改了下微信Demo程式碼,相容了支付和退款兩種情況,覺得放一起不好的,想分成兩個介面就拆開就好了

    /// <summary>
    /// 支付結果通知回撥處理類
    /// 負責接收微信支付後臺傳送的支付結果並對訂單有效性進行驗證,將驗證結果反饋給微信支付後臺
    /// </summary>
    public class ResultNotify : Notify
    {
        public override WxPayData ProcessNotify
(HttpContext context) { WxPayData notifyData = GetNotifyData(context); //支付回撥 if (notifyData.IsSet("result_code")) { #region 驗證簽名 try { notifyData.CheckSign();//驗證簽名,不通過會拋異常 } catch
(Exception ex) { //若簽名錯誤,則立即返回結果給微信支付後臺 WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", ex.Message); //Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
context.Response.Write(res.ToXml()); return null; } #endregion //檢查支付結果中transaction_id是否存在 if (!notifyData.IsSet("transaction_id")) { //若transaction_id不存在,則立即返回結果給微信支付後臺 WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", "支付結果中微信訂單號不存在"); //Log.Error(this.GetType().ToString(), "The Pay result is error : " + res.ToXml()); context.Response.Write(res.ToXml()); } else { string transaction_id = notifyData.GetValue("transaction_id").ToString(); //查詢訂單,判斷訂單真實性 if (!QueryPayOrder(transaction_id)) { //若訂單查詢失敗,則立即返回結果給微信支付後臺 WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", "訂單查詢失敗"); //Log.Error(this.GetType().ToString(), "Order query failure : " + res.ToXml()); context.Response.Write(res.ToXml()); } //查詢訂單成功 else { WxPayData res = new WxPayData(); res.SetValue("return_code", "SUCCESS"); res.SetValue("return_msg", "OK"); //Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml()); context.Response.Write(res.ToXml()); return notifyData; } } } //退款回撥 else if (notifyData.IsSet("req_info")) { if (!notifyData.IsSet("return_code") || notifyData.GetValue("return_code").ToString() != "SUCCESS" || !notifyData.IsSet("req_info")) { WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", "未返回正確微信支付退款解密資訊"); context.Response.Write(res.ToXml()); } //資訊解密 string req_info = DecodeReqInfo(notifyData.GetValue("req_info").ToString()); if (req_info == null) { WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", "解密資訊出錯"); context.Response.Write(res.ToXml()); } else { WxPayData res = new WxPayData(); res.SetValue("return_code", "SUCCESS"); res.SetValue("return_msg", "OK"); //Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml()); context.Response.Write(res.ToXml()); //FormXML會校驗簽名 WxPayData riData = new WxPayData(); riData.FromXmlNoCheck(req_info); notifyData.SetValue("req_info", riData); return notifyData; } } else { WxPayData res = new WxPayData(); res.SetValue("return_code", "FAIL"); res.SetValue("return_msg", "未知的通知回撥"); context.Response.Write(res.ToXml()); } return null; } //查詢訂單 private bool QueryPayOrder(string transaction_id) { WxPayData req = new WxPayData(); req.SetValue("transaction_id", transaction_id); WxPayData res = WxPayApi.OrderQuery(req); if (res.GetValue("return_code").ToString() == "SUCCESS" && res.GetValue("result_code").ToString() == "SUCCESS") { return true; } else { return false; } } #region 退款解密 /// <summary> /// AES-256-ECB字元解密 /// </summary> /// <param name="s">要解密字串</param> /// <param name="key">金鑰</param> /// <returns></returns> public static string DecodeAES256ECB(string s, string key) { string r = null; try { byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key); byte[] toEncryptArray = Convert.FromBase64String(s); RijndaelManaged rDel = new RijndaelManaged(); rDel.Key = keyArray; rDel.Mode = CipherMode.ECB; rDel.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = rDel.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); r = UTF8Encoding.UTF8.GetString(resultArray); } catch { } return r; } /// <summary> /// 解密微信支付退款結果通知 /// </summary> /// <param name="s">要解密字串</param> /// <returns></returns> public static string DecodeReqInfo(string s) { string r = null; string key = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(Config.Key, "md5").ToLower(); r = DecodeAES256ECB(s, key); return r; } #endregion }

具體介面呼叫

        public void ProcessRequest(HttpContext context)
        {
            ResultNotify resultNotify = new ResultNotify();
            WxPayData notifyData = resultNotify.ProcessNotify(context);

            if (notifyData != null)
            {
                //支付回撥
                if (notifyData.IsSet("result_code"))
                {
                    //TODO:核對訂單金額與微信訂單是否一致

                    //TODO:核對訂單金額與系統訂單是否一致

                    //TODO:核對訂單號,系統訂單號,商戶訂單號三者是否一致

                    //TODO:修改訂單狀態

                    //TODO:記錄日誌
                }
                //退款回撥
                else if (notifyData.IsSet("req_info"))
                {
                    //TODO:核對退款金額與系統退款是否一致

                    //TODO:核對訂單號,系統訂單號,商戶訂單號三者是否一致

                    //TODO:修改訂單狀態

                    //TODO:記錄日誌
                }
            }
        }

一定要核對下訂單金額和訂單號,並且返回結果給微信,不然前者會有假冒資料,後者會讓微信幾分鐘內一直髮請求給你。。。。。

解密那有點坑,解密的流程有點繁瑣,遇到好幾次錯誤才通過了。其他的沒啥想到的,感覺出錯都是自己程式碼問題,微信那好像沒什麼坑,另外這個回撥並不是即時傳送的,有延遲的,微信那邊人多的時候,有一次30多秒才收到回撥。。。所以實際開發的時候,最好輪訓和回撥都要有。