前期的一些說明
接上篇文章統一下單,這里主要是支付成功回調相關
回調地址在統一下單時已經提供
項目結構的一些基本說明以及微信公眾號支付的准備工作上篇已經說明
回調中用到的WxPayData也請參考上篇
鏈接:https://www.cnblogs.com/sylvia-/p/12771241.html
遇到的一些坑
微信回調一定要用post接收呀~~~
如果用官方SDK讀取流的方法,.net core 3.0 以后一定要加入我下邊代碼中的那段
.net core中是Request.Body
上代碼
Controller
//注:這里要用post呀~~~
[HttpPost("TestSuccess")]
public void TestSuccess()
{
_ticketRepository.TestSuccess(HttpContext);
}
Interface
(bool result, string msg) TestSuccess(HttpContext context);
業務倉儲
public (bool result, string msg) TestSuccess(HttpContext context)
{
_logger.LogWarning($"TestSuccess comming");
var result = _wxHelper.ProcessNotify(context);
if (result.result == true)
//處理業務邏輯
return (true, "success");
}
幫助方法
public (bool result, ProcessNotifyReturn data) ProcessNotify(HttpContext context)
{
WxPayData notifyData = GetNotifyData(context);
//檢查支付結果中transaction_id是否存在
if (!notifyData.IsSet("transaction_id"))
{
//若transaction_id不存在,則立即返回結果給微信支付后台
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "支付結果中微信訂單號不存在");
context.Response.WriteAsync(res.ToXml());
return (false, null);
}
string transaction_id = notifyData.GetValue("transaction_id").ToString();
string out_trade_no = notifyData.GetValue("out_trade_no").ToString();
//查詢訂單,判斷訂單真實性
if (!QueryOrder(transaction_id))
{
//若訂單查詢失敗,則立即返回結果給微信支付后台
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", "訂單查詢失敗");
context.Response.WriteAsync(res.ToXml());
return (false, null);
}
//查詢訂單成功
else
{
WxPayData res = new WxPayData();
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
context.Response.WriteAsync(res.ToXml());
ProcessNotifyReturn notifyReturn = new ProcessNotifyReturn
{
out_trade_no = out_trade_no,
transaction_id = transaction_id
};
return (true, notifyReturn);
}
}
/// <summary>
/// 接收從微信支付后台發送過來的數據並驗證簽名
/// </summary>
/// <returns>微信支付后台返回的數據</returns>
public WxPayData GetNotifyData(HttpContext context)
{
#region
//注意:如果用以下讀取流的方法,.net core 3.0 以后一定要加下邊那段
//.net core 3.0以后需加下邊這段,否則Stream會報錯
var syncIOFeature = context.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
#endregion
//接收從微信后台POST過來的數據
System.IO.Stream s = context.Request.Body;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
_logger.LogWarning($"GetNotifyData Receive data from WeChat :{builder.ToString()}");
//轉換數據格式並驗證簽名
WxPayData data = new WxPayData();
try
{
data.FromXml(builder.ToString());
}
catch (Exception ex)
{
//若簽名錯誤,則立即返回結果給微信支付后台
WxPayData res = new WxPayData();
res.SetValue("return_code", "FAIL");
res.SetValue("return_msg", ex.Message);
context.Response.WriteAsync(res.ToXml());
}
_logger.LogWarning($"GetNotifyData Check sign success");
return data;
}
/// <summary>
///
/// </summary>
/// <param name="transaction_id"></param>
/// <returns></returns>
private bool QueryOrder(string transaction_id)
{
WxPayData req = new WxPayData();
req.SetValue("transaction_id", transaction_id);
WxPayData res = OrderQuery(req);
if (res.GetValue("return_code").ToString() == "SUCCESS" &&
res.GetValue("result_code").ToString() == "SUCCESS")
{
return true;
}
else
{
return false;
}
}
/// <summary>
///
/// </summary>
/// <param name="inputObj"></param>
/// <param name="timeOut"></param>
/// <returns></returns>
public WxPayData OrderQuery(WxPayData inputObj, int timeOut = 6)
{
string url = "https://api.mch.weixin.qq.com/pay/orderquery";
//檢測必填參數
if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
{
throw new Exception("訂單查詢接口中,out_trade_no、transaction_id至少填一個!");
}
inputObj.SetValue("appid", "xxx");//公眾賬號ID
inputObj.SetValue("mch_id", "xxx");//商戶號
inputObj.SetValue("nonce_str", GenerateNonceStr());//隨機字符串
inputObj.SetValue("sign_type", "MD5");//簽名類型
inputObj.SetValue("sign", inputObj.MakeSign());//簽名
string xml = inputObj.ToXml();
var start = DateTime.Now;
string response = _webHelper.Post(xml, url, false, timeOut);//調用HTTP通信接口提交數據
var end = DateTime.Now;
int timeCost = (int)((end - start).TotalMilliseconds);//獲得接口耗時
//將xml格式的數據轉化為對象以返回
WxPayData result = new WxPayData();
result.FromXml(response);
//ReportCostTime(url, timeCost, result);//測速上報
return result;
}