Commit 4d6a2865 authored by 吴春's avatar 吴春

提交微信回调

parent 2f963457
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
...@@ -35,35 +37,50 @@ namespace Mall.Common.Pay.WeChatPat ...@@ -35,35 +37,50 @@ namespace Mall.Common.Pay.WeChatPat
/// </summary> /// </summary>
public ResponseHandler(IHttpContextAccessor _accessor) public ResponseHandler(IHttpContextAccessor _accessor)
{ {
xmlMap = new Hashtable(); #region
//注意:如果用以下读取流的方法,.net core 3.0 以后一定要加下边那段
if (_accessor.HttpContext.Request.ContentLength > 0) //.net core 3.0以后需加下边这段,否则Stream会报错
var syncIOFeature = _accessor.HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{ {
var reader = new System.IO.StreamReader(_accessor.HttpContext.Request.Body, Encoding.UTF8); syncIOFeature.AllowSynchronousIO = true;
}
#endregion
Plugin.LogHelper.Write(null, "Notify支付回调:reader-" + reader.ToString());
_accessor.HttpContext.Request.Body.Position = 0; //接收从微信后台POST过来的数据
var xmlDoc = new XmlDocument(); System.IO.Stream s = _accessor.HttpContext.Request.Body;
xmlDoc.Load(reader); int count = 0;
var root = xmlDoc.SelectSingleNode("xml"); byte[] buffer = new byte[1024];
var xnl = root.ChildNodes; StringBuilder builder = new StringBuilder();
foreach (XmlNode xnf in xnl) while ((count = s.Read(buffer, 0, 1024)) > 0)
{ {
xmlMap.Add(xnf.Name, xnf.InnerText); builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
} }
Plugin.LogHelper.Write(null, "Notify支付回调:xmlMap-" + xmlMap.ToString()); s.Flush();
s.Close();
s.Dispose();
Plugin.LogHelper.Write($"GetNotifyData Receive data from WeChat :{builder.ToString()}");
//转换数据格式并验证签名
// WxPayData data = new WxPayData();
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(builder.ToString());
XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
XmlNodeList nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
xmlMap.Add(xn.Name, xn.InnerText);
} }
//if (HttpContext.Current.Request.InputStream.Length > 0) }
//{ catch (Exception ex)
// var xmlDoc = new XmlDocument(); {
// xmlDoc.Load(HttpContext.Current.Request.InputStream); //若签名错误,则立即返回结果给微信支付后台
// var root = xmlDoc.SelectSingleNode("xml"); }
// var xnl = root.ChildNodes; Plugin.LogHelper.Write($"GetNotifyData Check sign success");
// foreach (XmlNode xnf in xnl)
// {
// xmlMap.Add(xnf.Name, xnf.InnerText);
// }
//}
} }
/// <summary> /// <summary>
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Xml;
namespace Mall.Common.Plugin namespace Mall.Common.Plugin
{ {
public class WeiXinHelper public class WeiXinHelper
{ {
} }
/// <summary> /// <summary>
...@@ -69,4 +72,183 @@ namespace Mall.Common.Plugin ...@@ -69,4 +72,183 @@ namespace Mall.Common.Plugin
public string errmsg { get; set; } public string errmsg { get; set; }
} }
#endregion #endregion
}
public class WxPayData
{
public const string SIGN_TYPE_MD5 = "MD5";
public const string SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256";
public WxPayData()
{
}
//采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
/**
* 设置某个字段的值
* @param key 字段名
* @param value 字段值
*/
public void SetValue(string key, object value)
{
m_values[key] = value;
}
/**
* 根据字段名获取某个字段的值
* @param key 字段名
* @return key对应的字段值
*/
public object GetValue(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
return o;
}
/**
* 判断某个字段是否已设置
* @param key 字段名
* @return 若字段key已被设置,则返回true,否则返回false
*/
public bool IsSet(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
if (null != o)
return true;
else
return false;
}
/**
* @将Dictionary转成xml
* @return 经转换得到的xml串
* @throws WxPayException
**/
public string ToXml()
{
//数据为空时不能转化为xml格式
if (0 == m_values.Count)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData数据为空!");
throw new Exception("WxPayData数据为空!");
}
string xml = "<xml>";
foreach (KeyValuePair<string, object> pair in m_values)
{
//字段值不能为null,会影响后续流程
if (pair.Value == null)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw new Exception("WxPayData内部含有值为null的字段!");
}
if (pair.Value.GetType() == typeof(int))
{
xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
}
else if (pair.Value.GetType() == typeof(string))
{
xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
}
else//除了string和int类型不能含有其他数据类型
{
//_logger.LogError(this.GetType().ToString(), "WxPayData字段数据类型错误!");
throw new Exception("WxPayData字段数据类型错误!");
}
}
xml += "</xml>";
return xml;
}
public SortedDictionary<string, object> NoSignFromXml(string xml)
{
if (string.IsNullOrEmpty(xml))
{
//_logger.LogError(this.GetType().ToString(), "将空的xml串转换为WxPayData不合法!");
throw new Exception("将空的xml串转换为WxPayData不合法!");
}
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
XmlNodeList nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
XmlElement xe = (XmlElement)xn;
m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
}
return m_values;
}
/**
* @Dictionary格式转化成url参数格式
* @ return url格式串, 该串不包含sign字段值
*/
public string ToUrl()
{
string buff = "";
foreach (KeyValuePair<string, object> pair in m_values)
{
if (pair.Value == null)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw new Exception("WxPayData内部含有值为null的字段!");
}
if (pair.Key != "sign" && pair.Value.ToString() != "")
{
buff += pair.Key + "=" + pair.Value + "&";
}
}
buff = buff.Trim('&');
return buff;
}
public bool CheckSign()
{
////如果没有设置签名,则跳过检测
//if (!IsSet("sign"))
//{
// //_logger.LogError(this.GetType().ToString(), "WxPayData签名存在但不合法!");
// throw new Exception("WxPayData签名存在但不合法!");
//}
////如果设置了签名但是签名为空,则抛异常
//else if (GetValue("sign") == null || GetValue("sign").ToString() == "")
//{
// //_logger.LogError(this.GetType().ToString(), "WxPayData签名存在但不合法!");
// throw new Exception("WxPayData签名存在但不合法!");
//}
////获取接收到的签名
//string return_sign = GetValue("sign").ToString();
////在本地计算新的签名
//string cal_sign = payReq.CreateMd5Sign(_accessor, model.WeChatApiSecret);
return true;
//if (cal_sign == return_sign)
//{
// return true;
//}
//_logger.LogError(this.GetType().ToString(), "WxPayData签名验证错误!");
throw new Exception("WxPayData签名验证错误!");
}
}
}
...@@ -17,6 +17,7 @@ using Mall.Common; ...@@ -17,6 +17,7 @@ using Mall.Common;
using Mall.Model.Extend.User; using Mall.Model.Extend.User;
using NPOI.SS.Formula.Functions; using NPOI.SS.Formula.Functions;
using Org.BouncyCastle.Utilities.Net; using Org.BouncyCastle.Utilities.Net;
using Microsoft.AspNetCore.Http.Features;
namespace Mall.WebApi.App_Code namespace Mall.WebApi.App_Code
{ {
...@@ -199,6 +200,104 @@ namespace Mall.WebApi.App_Code ...@@ -199,6 +200,104 @@ namespace Mall.WebApi.App_Code
//public 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();
// LogHelper.Write($"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());
// }
// LogHelper.Write($"GetNotifyData Check sign success");
// return data;
//}
// <summary> // <summary>
/// 退款 传入订单号OrderNumber,RefundNumber,总金额total_fee(分),RefundFee退款金额(分), /// 退款 传入订单号OrderNumber,RefundNumber,总金额total_fee(分),RefundFee退款金额(分),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment