Browse Source

Revert "移除 *NotifyClient、I*NotifyClient类,相关方法分别合并至*Client、I*Client类。"

This reverts commit 218f18600f21d0f65a8c85365e4c60b105c6c5ca.
Roc 4 years ago
parent
commit
6e9e450865

+ 2 - 2
samples/WebApplicationSample/Controllers/AlipayNotifyController.cs

@@ -11,10 +11,10 @@ namespace WebApplicationSample.Controllers
     public class AlipayNotifyController : Controller
     {
         private readonly ILogger<AlipayNotifyController> _logger;
-        private readonly IAlipayClient _client;
+        private readonly IAlipayNotifyClient _client;
         private readonly IOptions<AlipayOptions> _optionsAccessor;
 
-        public AlipayNotifyController(ILogger<AlipayNotifyController> logger, IAlipayClient client, IOptions<AlipayOptions> optionsAccessor)
+        public AlipayNotifyController(ILogger<AlipayNotifyController> logger, IAlipayNotifyClient client, IOptions<AlipayOptions> optionsAccessor)
         {
             _logger = logger;
             _client = client;

+ 2 - 2
samples/WebApplicationSample/Controllers/AlipayReturnController.cs

@@ -11,10 +11,10 @@ namespace WebApplicationSample.Controllers
     public class AlipayReturnController : Controller
     {
         private readonly ILogger<AlipayReturnController> _logger;
-        private readonly IAlipayClient _client;
+        private readonly IAlipayNotifyClient _client;
         private readonly IOptions<AlipayOptions> _optionsAccessor;
 
-        public AlipayReturnController(ILogger<AlipayReturnController> logger, IAlipayClient client, IOptions<AlipayOptions> optionsAccessor)
+        public AlipayReturnController(ILogger<AlipayReturnController> logger, IAlipayNotifyClient client, IOptions<AlipayOptions> optionsAccessor)
         {
             _logger = logger;
             _client = client;

+ 2 - 2
samples/WebApplicationSample/Controllers/WeChatPayNotifyController.cs

@@ -12,10 +12,10 @@ namespace WebApplicationSample.Controllers
     public class WeChatPayNotifyController : Controller
     {
         private readonly ILogger<WeChatPayNotifyController> _logger;
-        private readonly IWeChatPayClient _client;
+        private readonly IWeChatPayNotifyClient _client;
         private readonly IOptions<WeChatPayOptions> _optionsAccessor;
 
-        public WeChatPayNotifyController(ILogger<WeChatPayNotifyController> logger, IWeChatPayClient client, IOptions<WeChatPayOptions> optionsAccessor)
+        public WeChatPayNotifyController(ILogger<WeChatPayNotifyController> logger, IWeChatPayNotifyClient client, IOptions<WeChatPayOptions> optionsAccessor)
         {
             _logger = logger;
             _client = client;

+ 2 - 2
samples/WebApplicationSample/Controllers/WeChatPayV3NotifyController.cs

@@ -12,10 +12,10 @@ namespace WebApplicationSample.Controllers
     public class WeChatPayV3NotifyController : Controller
     {
         private readonly ILogger<WeChatPayV3NotifyController> _logger;
-        private readonly IWeChatPayClient _client;
+        private readonly IWeChatPayNotifyClient _client;
         private readonly IOptions<WeChatPayOptions> _optionsAccessor;
 
-        public WeChatPayV3NotifyController(ILogger<WeChatPayV3NotifyController> logger, IWeChatPayClient client, IOptions<WeChatPayOptions> optionsAccessor)
+        public WeChatPayV3NotifyController(ILogger<WeChatPayV3NotifyController> logger, IWeChatPayNotifyClient client, IOptions<WeChatPayOptions> optionsAccessor)
         {
             _logger = logger;
             _client = client;

+ 0 - 121
src/Essensoft.Paylink.Alipay/AlipayClient.cs

@@ -504,127 +504,6 @@ namespace Essensoft.Paylink.Alipay
 
         #endregion
 
-        #region IAlipayClient Members
-
-#if NETCOREAPP3_1 || NET5_0
-        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify
-        {
-            if (options == null)
-            {
-                throw new ArgumentNullException(nameof(options));
-            }
-
-            if (string.IsNullOrEmpty(options.SignType))
-            {
-                throw new AlipayException($"options.{nameof(AlipayOptions.SignType)} is Empty!");
-            }
-
-            if (string.IsNullOrEmpty(options.AlipayPublicKey))
-            {
-                throw new AlipayException($"options.{nameof(AlipayOptions.AlipayPublicKey)} is Empty!");
-            }
-
-            var parameters = await GetParametersAsync(request);
-            return await ExecuteAsync<T>(parameters, options);
-        }
-#endif
-
-        #endregion
-
-        #region IAlipayClient Members
-
-#if NETCOREAPP3_1 || NET5_0
-        public Task<T> CertificateExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify
-        {
-            return ExecuteAsync<T>(request, options);
-        }
-#endif
-
-        #endregion
-
-        #region IAlipayClient Members
-
-#if NETCOREAPP3_1 || NET5_0
-        public async Task<IDictionary<string, string>> GetParametersAsync(Microsoft.AspNetCore.Http.HttpRequest request)
-        {
-            var parameters = new Dictionary<string, string>();
-            if (request.Method == "POST")
-            {
-                var form = await request.ReadFormAsync();
-                foreach (var iter in form)
-                {
-                    parameters.Add(iter.Key, iter.Value);
-                }
-            }
-            else
-            {
-                foreach (var iter in request.Query)
-                {
-                    parameters.Add(iter.Key, iter.Value);
-                }
-            }
-            return parameters;
-        }
-#endif
-
-        #endregion
-
-        #region IAlipayClient Members
-
-        public Task<T> ExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify
-        {
-            if (options == null)
-            {
-                throw new ArgumentNullException(nameof(options));
-            }
-
-            if (string.IsNullOrEmpty(options.SignType))
-            {
-                throw new AlipayException($"options.{nameof(AlipayOptions.SignType)} is Empty!");
-            }
-
-            if (string.IsNullOrEmpty(options.AlipayPublicKey))
-            {
-                throw new AlipayException($"options.{nameof(AlipayOptions.AlipayPublicKey)} is Empty!");
-            }
-
-            var notify = AlipayDictionaryParser.Parse<T>(parameters);
-            CheckNotifySign(parameters, options);
-            return Task.FromResult(notify);
-        }
-
-        private static void CheckNotifySign(IDictionary<string, string> dictionary, AlipayOptions options)
-        {
-            if (dictionary == null || dictionary.Count == 0)
-            {
-                throw new AlipayException("sign check fail: dictionary)} is Empty!");
-            }
-
-            if (!dictionary.TryGetValue(AlipayConstants.SIGN, out var sign))
-            {
-                throw new AlipayException("sign check fail: sign)} is Empty!");
-            }
-
-            dictionary.Remove(AlipayConstants.SIGN);
-            dictionary.Remove(AlipayConstants.SIGN_TYPE);
-            var content = AlipaySignature.GetSignContent(dictionary);
-            if (!AlipaySignature.RSACheckContent(content, sign, options.AlipayPublicKey, options.SignType))
-            {
-                throw new AlipayException("sign check fail: check Sign and Data Fail!");
-            }
-        }
-
-        #endregion
-
-        #region IAlipayClient Members
-
-        public Task<T> CertificateExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify
-        {
-            return ExecuteAsync<T>(parameters, options);
-        }
-
-        #endregion
-
         #region Common Method
 
         private static ResponseParseItem ParseRespItem<T>(IAlipayRequest<T> request, string respBody, IAlipayParser<T> parser, string encryptKey, string encryptType) where T : AlipayResponse

+ 145 - 0
src/Essensoft.Paylink.Alipay/AlipayNotifyClient.cs

@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Essensoft.Paylink.Alipay.Parser;
+using Essensoft.Paylink.Alipay.Utility;
+
+namespace Essensoft.Paylink.Alipay
+{
+    public class AlipayNotifyClient : IAlipayNotifyClient
+    {
+        #region AlipayNotifyClient Constructors
+
+        public AlipayNotifyClient()
+        {
+
+        }
+
+        #endregion
+
+        #region IAlipayNotifyClient Members
+
+#if NETCOREAPP3_1 || NET5_0
+        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify
+        {
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            if (string.IsNullOrEmpty(options.SignType))
+            {
+                throw new AlipayException($"options.{nameof(AlipayOptions.SignType)} is Empty!");
+            }
+
+            if (string.IsNullOrEmpty(options.AlipayPublicKey))
+            {
+                throw new AlipayException($"options.{nameof(AlipayOptions.AlipayPublicKey)} is Empty!");
+            }
+
+            var parameters = await GetParametersAsync(request);
+            return await ExecuteAsync<T>(parameters, options);
+        }
+#endif
+
+        #endregion
+
+        #region IAlipayNotifyClient Members
+
+#if NETCOREAPP3_1 || NET5_0
+        public Task<T> CertificateExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify
+        {
+            return ExecuteAsync<T>(request, options);
+        }
+#endif
+
+        #endregion
+
+        #region IAlipayNotifyClient Members
+
+#if NETCOREAPP3_1 || NET5_0
+        public async Task<IDictionary<string, string>> GetParametersAsync(Microsoft.AspNetCore.Http.HttpRequest request)
+        {
+            var parameters = new Dictionary<string, string>();
+            if (request.Method == "POST")
+            {
+                var form = await request.ReadFormAsync();
+                foreach (var iter in form)
+                {
+                    parameters.Add(iter.Key, iter.Value);
+                }
+            }
+            else
+            {
+                foreach (var iter in request.Query)
+                {
+                    parameters.Add(iter.Key, iter.Value);
+                }
+            }
+            return parameters;
+        }
+#endif
+
+        #endregion
+
+        #region IAlipayNotifyClient Members
+
+        public Task<T> ExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify
+        {
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            if (string.IsNullOrEmpty(options.SignType))
+            {
+                throw new AlipayException($"options.{nameof(AlipayOptions.SignType)} is Empty!");
+            }
+
+            if (string.IsNullOrEmpty(options.AlipayPublicKey))
+            {
+                throw new AlipayException($"options.{nameof(AlipayOptions.AlipayPublicKey)} is Empty!");
+            }
+
+            var notify = AlipayDictionaryParser.Parse<T>(parameters);
+            CheckNotifySign(parameters, options);
+            return Task.FromResult(notify);
+        }
+
+        #endregion
+
+        #region IAlipayNotifyClient Members
+
+        public Task<T> CertificateExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify
+        {
+            return ExecuteAsync<T>(parameters, options);
+        }
+
+        #endregion
+
+        #region Common Method
+
+        private static void CheckNotifySign(IDictionary<string, string> dictionary, AlipayOptions options)
+        {
+            if (dictionary == null || dictionary.Count == 0)
+            {
+                throw new AlipayException("sign check fail: dictionary)} is Empty!");
+            }
+
+            if (!dictionary.TryGetValue(AlipayConstants.SIGN, out var sign))
+            {
+                throw new AlipayException("sign check fail: sign)} is Empty!");
+            }
+
+            dictionary.Remove(AlipayConstants.SIGN);
+            dictionary.Remove(AlipayConstants.SIGN_TYPE);
+            var content = AlipaySignature.GetSignContent(dictionary);
+            if (!AlipaySignature.RSACheckContent(content, sign, options.AlipayPublicKey, options.SignType))
+            {
+                throw new AlipayException("sign check fail: check Sign and Data Fail!");
+            }
+        }
+
+        #endregion
+    }
+}

+ 1 - 0
src/Essensoft.Paylink.Alipay/Extensions/ServiceCollectionExtensions.cs

@@ -12,6 +12,7 @@ namespace Microsoft.Extensions.DependencyInjection
             services.AddSingleton<AlipayPublicKeyManager>();
             services.AddSingleton<IAlipayClient, AlipayClient>();
             services.AddSingleton<IAlipayMobilePublicMultiMediaClient, AlipayMobilePublicMultiMediaClient>();
+            services.AddSingleton<IAlipayNotifyClient, AlipayNotifyClient>();
         }
     }
 }

+ 1 - 46
src/Essensoft.Paylink.Alipay/IAlipayClient.cs

@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
 
 namespace Essensoft.Paylink.Alipay
 {
@@ -129,49 +128,5 @@ namespace Essensoft.Paylink.Alipay
         /// <param name="appAuthToken">三方应用授权token</param>
         /// <returns>响应对象</returns>
         Task<T> SdkExecuteAsync<T>(IAlipayRequest<T> request, AlipayOptions options, string appAuthToken) where T : AlipayResponse;
-
-#if NETCOREAPP3_1 || NET5_0
-        /// <summary>
-        /// 执行 Alipay 通知请求解析。
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="request">控制器的请求</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify;
-
-        /// <summary>
-        /// 执行 Alipay 通知请求解析。
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="request">控制器的请求</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> CertificateExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify;
-
-        /// <summary>
-        /// 获取通知参数
-        /// </summary>
-        /// <param name="request"></param>
-        Task<IDictionary<string, string>> GetParametersAsync(Microsoft.AspNetCore.Http.HttpRequest request);
-#endif
-
-        /// <summary>
-        /// 执行 Alipay 通知请求解析。
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="parameters">通知参数</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify;
-
-        /// <summary>
-        /// 执行 Alipay 通知请求解析。
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="parameters">通知参数</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> CertificateExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify;
     }
 }

+ 55 - 0
src/Essensoft.Paylink.Alipay/IAlipayNotifyClient.cs

@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Essensoft.Paylink.Alipay
+{
+    /// <summary>
+    /// Alipay 通知客户端
+    /// </summary>
+    public interface IAlipayNotifyClient
+    {
+#if NETCOREAPP3_1 || NET5_0
+        /// <summary>
+        /// 执行 Alipay 通知请求解析。
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="request">控制器的请求</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify;
+
+        /// <summary>
+        /// 执行 Alipay 通知请求解析。
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="request">控制器的请求</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> CertificateExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, AlipayOptions options) where T : AlipayNotify;
+
+        /// <summary>
+        /// 获取通知参数
+        /// </summary>
+        /// <param name="request"></param>
+        Task<IDictionary<string, string>> GetParametersAsync(Microsoft.AspNetCore.Http.HttpRequest request);
+#endif
+
+        /// <summary>
+        /// 执行 Alipay 通知请求解析。
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="parameters">通知参数</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify;
+
+        /// <summary>
+        /// 执行 Alipay 通知请求解析。
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="parameters">通知参数</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> CertificateExecuteAsync<T>(IDictionary<string, string> parameters, AlipayOptions options) where T : AlipayNotify;
+    }
+}

+ 2 - 0
src/Essensoft.Paylink.WeChatPay/Extensions/ServiceCollectionExtensions.cs

@@ -11,10 +11,12 @@ namespace Microsoft.Extensions.DependencyInjection
             services.TryAddEnumerable(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, Essensoft.Paylink.WeChatPay.V2.WeChatPayHttpMessageHandlerBuilderFilter>());
             services.AddSingleton<Essensoft.Paylink.WeChatPay.V2.WeChatPayClientCertificateManager>();
             services.AddSingleton<Essensoft.Paylink.WeChatPay.V2.IWeChatPayClient, Essensoft.Paylink.WeChatPay.V2.WeChatPayClient>();
+            services.AddSingleton<Essensoft.Paylink.WeChatPay.V2.IWeChatPayNotifyClient, Essensoft.Paylink.WeChatPay.V2.WeChatPayNotifyClient>();
 
             services.AddHttpClient(Essensoft.Paylink.WeChatPay.V3.WeChatPayClient.Name);
             services.AddSingleton<Essensoft.Paylink.WeChatPay.V3.WeChatPayPlatformCertificateManager>();
             services.AddSingleton<Essensoft.Paylink.WeChatPay.V3.IWeChatPayClient, Essensoft.Paylink.WeChatPay.V3.WeChatPayClient>();
+            services.AddSingleton<Essensoft.Paylink.WeChatPay.V3.IWeChatPayNotifyClient, Essensoft.Paylink.WeChatPay.V3.WeChatPayNotifyClient>();
         }
     }
 }

+ 0 - 19
src/Essensoft.Paylink.WeChatPay/V2/IWeChatPayClient.cs

@@ -38,24 +38,5 @@ namespace Essensoft.Paylink.WeChatPay.V2
         /// <param name="options">配置选项</param>
         /// <returns>响应字典</returns>
         Task<WeChatPayDictionary> ExecuteAsync(IWeChatPaySdkRequest request, WeChatPayOptions options);
-
-#if NETCOREAPP3_1 || NET5_0
-        /// <summary>
-        /// 执行 WeChatPay V2 通知请求解析
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="request">控制器的请求</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify;
-#endif
-        /// <summary>
-        /// 执行 WeChatPay V2 通知请求解析
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="body">通知内容</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(string body, WeChatPayOptions options) where T : WeChatPayNotify;
     }
 }

+ 29 - 0
src/Essensoft.Paylink.WeChatPay/V2/IWeChatPayNotifyClient.cs

@@ -0,0 +1,29 @@
+using System.Threading.Tasks;
+
+namespace Essensoft.Paylink.WeChatPay.V2
+{
+    /// <summary>
+    /// WeChatPay 通知客户端
+    /// </summary>
+    public interface IWeChatPayNotifyClient
+    {
+#if NETCOREAPP3_1 || NET5_0
+        /// <summary>
+        /// 执行 WeChatPay V2 通知请求解析
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="request">控制器的请求</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify;
+#endif
+        /// <summary>
+        /// 执行 WeChatPay V2 通知请求解析
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="body">通知内容</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(string body, WeChatPayOptions options) where T : WeChatPayNotify;
+    }
+}

+ 1 - 85
src/Essensoft.Paylink.WeChatPay/V2/WeChatPayClient.cs

@@ -1,9 +1,6 @@
 using System;
-using System.IO;
 using System.Net.Http;
-using System.Text;
 using System.Threading.Tasks;
-using Essensoft.Paylink.Security;
 using Essensoft.Paylink.WeChatPay.V2.Extensions;
 using Essensoft.Paylink.WeChatPay.V2.Parser;
 
@@ -199,64 +196,7 @@ namespace Essensoft.Paylink.WeChatPay.V2
 
         #endregion
 
-        #region IWeChatPayClient Members
-
-#if NETCOREAPP3_1 || NET5_0
-        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify
-        {
-            if (request == null)
-            {
-                throw new ArgumentNullException(nameof(request));
-            }
-
-            using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
-            {
-                var body = await reader.ReadToEndAsync();
-                return await ExecuteAsync<T>(body, options);
-            }
-        }
-#endif
-
-        #endregion
-
-        #region IWeChatPayClient Members
-
-        public Task<T> ExecuteAsync<T>(string body, WeChatPayOptions options) where T : WeChatPayNotify
-        {
-            if (string.IsNullOrEmpty(body))
-            {
-                throw new ArgumentNullException(nameof(body));
-            }
-
-            if (options == null)
-            {
-                throw new ArgumentNullException(nameof(options));
-            }
-
-            if (string.IsNullOrEmpty(options.APIKey))
-            {
-                throw new WeChatPayException($"options.{nameof(WeChatPayOptions.APIKey)} is Empty!");
-            }
-
-            var parser = new WeChatPayNotifyXmlParser<T>();
-            var notify = parser.Parse(body);
-            if (notify is Notify.WeChatPayRefundNotify)
-            {
-                var key = MD5.Compute(options.APIKey).ToLowerInvariant();
-                var data = AES.Decrypt((notify as Notify.WeChatPayRefundNotify).ReqInfo, key, System.Security.Cryptography.CipherMode.ECB, System.Security.Cryptography.PaddingMode.PKCS7);
-                notify = parser.Parse(body, data);
-            }
-            else
-            {
-                CheckNotifySign(notify, options);
-            }
-
-            return Task.FromResult(notify);
-        }
-
-        #endregion
-
-        #region Check Sign Method
+        #region Check Response Method
 
         private static void CheckResponseSign(WeChatPayResponse response, WeChatPayOptions options, WeChatPaySignType signType)
         {
@@ -283,30 +223,6 @@ namespace Essensoft.Paylink.WeChatPay.V2
             }
         }
 
-        private static void CheckNotifySign(WeChatPayNotify notify, WeChatPayOptions options)
-        {
-            if (string.IsNullOrEmpty(notify.Body))
-            {
-                throw new WeChatPayException("sign check fail: Body is Empty!");
-            }
-
-            if (notify.Parameters.Count == 0)
-            {
-                throw new WeChatPayException("sign check fail: Parameters is Empty!");
-            }
-
-            if (!notify.Parameters.TryGetValue("sign", out var sign))
-            {
-                throw new WeChatPayException("sign check fail: sign is Empty!");
-            }
-
-            var cal_sign = WeChatPaySignature.SignWithKey(notify.Parameters, options.APIKey, WeChatPaySignType.MD5);
-            if (cal_sign != sign)
-            {
-                throw new WeChatPayException("sign check fail: check Sign and Data Fail!");
-            }
-        }
-
         #endregion
     }
 }

+ 107 - 0
src/Essensoft.Paylink.WeChatPay/V2/WeChatPayNotifyClient.cs

@@ -0,0 +1,107 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using Essensoft.Paylink.Security;
+using Essensoft.Paylink.WeChatPay.V2.Parser;
+using MD5 = Essensoft.Paylink.Security.MD5;
+
+namespace Essensoft.Paylink.WeChatPay.V2
+{
+    public class WeChatPayNotifyClient : IWeChatPayNotifyClient
+    {
+        #region WeChatPayNotifyClient Constructors
+
+        public WeChatPayNotifyClient()
+        {
+        }
+
+        #endregion
+
+        #region IWeChatPayNotifyClient Members
+
+#if NETCOREAPP3_1 || NET5_0
+        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify
+        {
+            if (request == null)
+            {
+                throw new ArgumentNullException(nameof(request));
+            }
+
+            using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
+            {
+                var body = await reader.ReadToEndAsync();
+                return await ExecuteAsync<T>(body, options);
+            }
+        }
+#endif
+
+        #endregion
+
+        #region IWeChatPayNotifyClient Members
+
+        public Task<T> ExecuteAsync<T>(string body, WeChatPayOptions options) where T : WeChatPayNotify
+        {
+            if (string.IsNullOrEmpty(body))
+            {
+                throw new ArgumentNullException(nameof(body));
+            }
+
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            if (string.IsNullOrEmpty(options.APIKey))
+            {
+                throw new WeChatPayException($"options.{nameof(WeChatPayOptions.APIKey)} is Empty!");
+            }
+
+            var parser = new WeChatPayNotifyXmlParser<T>();
+            var notify = parser.Parse(body);
+            if (notify is Notify.WeChatPayRefundNotify)
+            {
+                var key = MD5.Compute(options.APIKey).ToLowerInvariant();
+                var data = AES.Decrypt((notify as Notify.WeChatPayRefundNotify).ReqInfo, key, CipherMode.ECB, PaddingMode.PKCS7);
+                notify = parser.Parse(body, data);
+            }
+            else
+            {
+                CheckNotifySign(notify, options);
+            }
+
+            return Task.FromResult(notify);
+        }
+
+        #endregion
+
+        #region Common Method
+
+        private static void CheckNotifySign(WeChatPayNotify notify, WeChatPayOptions options)
+        {
+            if (string.IsNullOrEmpty(notify.Body))
+            {
+                throw new WeChatPayException("sign check fail: Body is Empty!");
+            }
+
+            if (notify.Parameters.Count == 0)
+            {
+                throw new WeChatPayException("sign check fail: Parameters is Empty!");
+            }
+
+            if (!notify.Parameters.TryGetValue("sign", out var sign))
+            {
+                throw new WeChatPayException("sign check fail: sign is Empty!");
+            }
+
+            var cal_sign = WeChatPaySignature.SignWithKey(notify.Parameters, options.APIKey, WeChatPaySignType.MD5);
+            if (cal_sign != sign)
+            {
+                throw new WeChatPayException("sign check fail: check Sign and Data Fail!");
+            }
+        }
+
+        #endregion
+    }
+}

+ 0 - 20
src/Essensoft.Paylink.WeChatPay/V3/IWeChatPayClient.cs

@@ -38,25 +38,5 @@ namespace Essensoft.Paylink.WeChatPay.V3
         /// <param name="options">配置选项</param>
         /// <returns>响应对象</returns>
         Task<T> ExecuteAsync<T>(IWeChatPayPrivacyPostRequest<T> request, WeChatPayOptions options) where T : WeChatPayResponse;
-
-#if NETCOREAPP3_1 || NET5_0
-        /// <summary>
-        /// 执行 WeChatPay V3 通知请求解析
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="request">控制器的请求</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify;
-#endif
-        /// <summary>
-        /// 执行 WeChatPay V3 通知请求解析
-        /// </summary>
-        /// <typeparam name="T">领域对象</typeparam>
-        /// <param name="headers">微信Http头信息</param>
-        /// <param name="body">通知内容</param>
-        /// <param name="options">配置选项</param>
-        /// <returns>领域对象</returns>
-        Task<T> ExecuteAsync<T>(WeChatPayHeaders headers, string body, WeChatPayOptions options) where T : WeChatPayNotify;
     }
 }

+ 30 - 0
src/Essensoft.Paylink.WeChatPay/V3/IWeChatPayNotifyClient.cs

@@ -0,0 +1,30 @@
+using System.Threading.Tasks;
+
+namespace Essensoft.Paylink.WeChatPay.V3
+{
+    /// <summary>
+    /// WeChatPay 通知客户端
+    /// </summary>
+    public interface IWeChatPayNotifyClient
+    {
+#if NETCOREAPP3_1 || NET5_0
+        /// <summary>
+        /// 执行 WeChatPay V3 通知请求解析
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="request">控制器的请求</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify;
+#endif
+        /// <summary>
+        /// 执行 WeChatPay V3 通知请求解析
+        /// </summary>
+        /// <typeparam name="T">领域对象</typeparam>
+        /// <param name="headers">微信Http头信息</param>
+        /// <param name="body">通知内容</param>
+        /// <param name="options">配置选项</param>
+        /// <returns>领域对象</returns>
+        Task<T> ExecuteAsync<T>(WeChatPayHeaders headers, string body, WeChatPayOptions options) where T : WeChatPayNotify;
+    }
+}

+ 5 - 80
src/Essensoft.Paylink.WeChatPay/V3/WeChatPayClient.cs

@@ -1,10 +1,7 @@
 using System;
-using System.IO;
-using System.Linq;
 using System.Net.Http;
 using System.Security.Cryptography;
 using System.Security.Cryptography.X509Certificates;
-using System.Text;
 using System.Threading.Tasks;
 using Essensoft.Paylink.Security;
 using Essensoft.Paylink.WeChatPay.V3.Extensions;
@@ -93,7 +90,7 @@ namespace Essensoft.Paylink.WeChatPay.V3
 
             if (request.GetNeedCheckSign())
             {
-                await CheckSignAsync(headers, body, options);
+                await CheckResponseSignAsync(headers, body, options);
             }
 
             return response;
@@ -125,7 +122,7 @@ namespace Essensoft.Paylink.WeChatPay.V3
             var parser = new WeChatPayResponseJsonParser<T>();
             var response = parser.Parse(body, statusCode);
 
-            await CheckSignAsync(headers, body, options);
+            await CheckResponseSignAsync(headers, body, options);
 
             return response;
         }
@@ -161,88 +158,16 @@ namespace Essensoft.Paylink.WeChatPay.V3
             var parser = new WeChatPayResponseJsonParser<T>();
             var response = parser.Parse(body, statusCode);
 
-            await CheckSignAsync(headers, body, options);
+            await CheckResponseSignAsync(headers, body, options);
 
             return response;
         }
 
         #endregion
 
-        #region IWeChatPayClient Members
-
-#if NETCOREAPP3_1 || NET5_0
-        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify
-        {
-            if (options == null)
-            {
-                throw new ArgumentNullException(nameof(options));
-            }
-
-            var headers = GetWeChatPayHeadersFromRequest(request);
-            using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
-            {
-                var body = await reader.ReadToEndAsync();
-                return await ExecuteAsync<T>(headers, body, options);
-            }
-        }
-
-        private static WeChatPayHeaders GetWeChatPayHeadersFromRequest(Microsoft.AspNetCore.Http.HttpRequest request)
-        {
-            var headers = new WeChatPayHeaders();
-
-            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Serial, out var serialValues))
-            {
-                headers.Serial = serialValues.First();
-            }
-
-            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Timestamp, out var timestampValues))
-            {
-                headers.Timestamp = timestampValues.First();
-            }
-
-            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Nonce, out var nonceValues))
-            {
-                headers.Nonce = nonceValues.First();
-            }
-
-            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Signature, out var signatureValues))
-            {
-                headers.Signature = signatureValues.First();
-            }
-
-            return headers;
-        }
-#endif
-
-        #endregion
-
-        #region IWeChatPayClient Members
-
-        public async Task<T> ExecuteAsync<T>(WeChatPayHeaders headers, string body, WeChatPayOptions options) where T : WeChatPayNotify
-        {
-            if (options == null)
-            {
-                throw new ArgumentNullException(nameof(options));
-            }
-
-            if (string.IsNullOrEmpty(options.APIv3Key))
-            {
-                throw new WeChatPayException($"options.{nameof(options.APIv3Key)} is Empty!");
-            }
-
-            await CheckSignAsync(headers, body, options);
-
-            var parser = new WeChatPayNotifyJsonParser<T>();
-            var notify = parser.Parse(body, options.APIv3Key);
-
-            return notify;
-        }
-
-        #endregion
-
-        #region Check Sign Method
+        #region Check Response Method
 
-        private async Task CheckSignAsync(WeChatPayHeaders headers, string body, WeChatPayOptions options)
+        private async Task CheckResponseSignAsync(WeChatPayHeaders headers, string body, WeChatPayOptions options)
         {
             if (string.IsNullOrEmpty(headers.Serial))
             {

+ 129 - 0
src/Essensoft.Paylink.WeChatPay/V3/WeChatPayNotifyClient.cs

@@ -0,0 +1,129 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using Essensoft.Paylink.Security;
+using Essensoft.Paylink.WeChatPay.V3.Parser;
+
+namespace Essensoft.Paylink.WeChatPay.V3
+{
+    public class WeChatPayNotifyClient : IWeChatPayNotifyClient
+    {
+        #region WeChatPayNotifyClient Constructors
+
+        private readonly IWeChatPayClient _client;
+        private readonly WeChatPayPlatformCertificateManager _platformCertificateManager;
+
+        public WeChatPayNotifyClient(IWeChatPayClient client, WeChatPayPlatformCertificateManager platformCertificateManager)
+        {
+            _client = client;
+            _platformCertificateManager = platformCertificateManager;
+        }
+
+        #endregion
+
+        #region IWeChatPayNotifyClient Members
+
+#if NETCOREAPP3_1 || NET5_0
+        public async Task<T> ExecuteAsync<T>(Microsoft.AspNetCore.Http.HttpRequest request, WeChatPayOptions options) where T : WeChatPayNotify
+        {
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            var headers = GetWeChatPayHeadersFromRequest(request);
+            using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
+            {
+                var body = await reader.ReadToEndAsync();
+                return await ExecuteAsync<T>(headers, body, options);
+            }
+        }
+
+        private static WeChatPayHeaders GetWeChatPayHeadersFromRequest(Microsoft.AspNetCore.Http.HttpRequest request)
+        {
+            var headers = new WeChatPayHeaders();
+
+            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Serial, out var serialValues))
+            {
+                headers.Serial = serialValues.First();
+            }
+
+            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Timestamp, out var timestampValues))
+            {
+                headers.Timestamp = timestampValues.First();
+            }
+
+            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Nonce, out var nonceValues))
+            {
+                headers.Nonce = nonceValues.First();
+            }
+
+            if (request.Headers.TryGetValue(WeChatPayConsts.Wechatpay_Signature, out var signatureValues))
+            {
+                headers.Signature = signatureValues.First();
+            }
+
+            return headers;
+        }
+#endif
+
+        #endregion
+
+        #region IWeChatPayNotifyClient Members
+
+        public async Task<T> ExecuteAsync<T>(WeChatPayHeaders headers, string body, WeChatPayOptions options) where T : WeChatPayNotify
+        {
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            if (string.IsNullOrEmpty(options.APIv3Key))
+            {
+                throw new WeChatPayException($"options.{nameof(options.APIv3Key)} is Empty!");
+            }
+
+            await CheckNotifySignAsync(headers, body, options);
+
+            var parser = new WeChatPayNotifyJsonParser<T>();
+            var notify = parser.Parse(body, options.APIv3Key);
+
+            return notify;
+        }
+
+        #endregion
+
+        #region Check Notify Method
+
+        private async Task CheckNotifySignAsync(WeChatPayHeaders headers, string body, WeChatPayOptions options)
+        {
+            if (string.IsNullOrEmpty(headers.Serial))
+            {
+                throw new WeChatPayException($"sign check fail: {nameof(headers.Serial)} is empty!");
+            }
+
+            if (string.IsNullOrEmpty(headers.Signature))
+            {
+                throw new WeChatPayException($"sign check fail: {nameof(headers.Signature)} is empty!");
+            }
+
+            if (string.IsNullOrEmpty(body))
+            {
+                throw new WeChatPayException("sign check fail: body is empty!");
+            }
+
+            var cert = await _platformCertificateManager.GetCertificateAsync(_client, options, headers.Serial);
+            var signSourceData = WeChatPayUtility.BuildSignatureSourceData(headers.Timestamp, headers.Nonce, body);
+            var signCheck = SHA256WithRSA.Verify(cert.Certificate.GetRSAPublicKey(), signSourceData, headers.Signature);
+            if (!signCheck)
+            {
+                throw new WeChatPayException("sign check fail: check Sign and Data Fail!");
+            }
+        }
+
+        #endregion
+    }
+}