前期的一些说明
接上篇文章统一下单,这里主要是支付成功回调相关
回调地址在统一下单时已经提供
项目结构的一些基本说明以及微信公众号支付的准备工作上篇已经说明
回调中用到的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;
}