2022-08-08 19:58:58 +08:00
|
|
|
using System;
|
2021-05-10 15:30:00 +08:00
|
|
|
using System.Net.Http;
|
2024-01-29 23:12:37 +08:00
|
|
|
using System.Reflection;
|
2021-05-10 15:30:00 +08:00
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Flurl.Http;
|
|
|
|
|
|
|
|
|
|
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 一个微信支付 API HTTP 客户端。
|
|
|
|
|
/// </summary>
|
2021-11-09 15:23:23 +08:00
|
|
|
public class WechatTenpayClient : CommonClientBase, ICommonClient
|
2021-05-10 15:30:00 +08:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
2022-01-21 14:41:40 +08:00
|
|
|
/// 获取当前客户端使用的微信支付商户凭证。
|
2021-05-10 15:30:00 +08:00
|
|
|
/// </summary>
|
2021-07-27 00:50:03 +08:00
|
|
|
public Settings.Credentials Credentials { get; }
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
2022-01-21 14:41:40 +08:00
|
|
|
/// 获取当前客户端使用的微信支付平台证书管理器。
|
2021-05-10 15:30:00 +08:00
|
|
|
/// </summary>
|
2022-01-21 14:41:40 +08:00
|
|
|
public Settings.CertificateManager PlatformCertificateManager { get; }
|
2021-11-25 18:05:22 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
2021-11-25 21:15:54 +08:00
|
|
|
/// 获取是否自动加密请求中的敏感信息字段。
|
2021-11-25 18:05:22 +08:00
|
|
|
/// </summary>
|
2022-11-13 23:17:18 +08:00
|
|
|
protected internal bool AutoEncryptRequestSensitiveProperty { get; }
|
2021-11-25 18:05:22 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
2021-11-25 21:15:54 +08:00
|
|
|
/// 获取是否自动解密请求中的敏感信息字段。
|
2021-11-25 18:05:22 +08:00
|
|
|
/// </summary>
|
2022-11-13 23:17:18 +08:00
|
|
|
protected internal bool AutoDecryptResponseSensitiveProperty { get; }
|
2021-05-10 15:30:00 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 用指定的配置项初始化 <see cref="WechatTenpayClient"/> 类的新实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options">配置项。</param>
|
|
|
|
|
public WechatTenpayClient(WechatTenpayClientOptions options)
|
2024-01-29 23:12:37 +08:00
|
|
|
: this(options, null)
|
2021-05-10 15:30:00 +08:00
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="options"></param>
|
|
|
|
|
/// <param name="httpClient"></param>
|
|
|
|
|
/// <param name="disposeClient"></param>
|
|
|
|
|
internal protected WechatTenpayClient(WechatTenpayClientOptions options, HttpClient? httpClient, bool disposeClient = true)
|
|
|
|
|
: base(httpClient, disposeClient)
|
|
|
|
|
{
|
|
|
|
|
if (options is null) throw new ArgumentNullException(nameof(options));
|
2021-05-10 15:30:00 +08:00
|
|
|
|
2021-07-27 00:50:03 +08:00
|
|
|
Credentials = new Settings.Credentials(options);
|
2022-01-21 14:41:40 +08:00
|
|
|
PlatformCertificateManager = options.PlatformCertificateManager;
|
2021-11-25 18:05:22 +08:00
|
|
|
AutoEncryptRequestSensitiveProperty = options.AutoEncryptRequestSensitiveProperty;
|
|
|
|
|
AutoDecryptResponseSensitiveProperty = options.AutoDecryptResponseSensitiveProperty;
|
2021-05-10 15:30:00 +08:00
|
|
|
|
2023-03-12 08:05:24 +08:00
|
|
|
FlurlClient.BaseUrl = options.Endpoint ?? WechatTenpayEndpoints.DEFAULT;
|
2024-01-29 23:12:37 +08:00
|
|
|
FlurlClient.WithHeader(HttpHeaders.Accept, "application/json");
|
|
|
|
|
FlurlClient.WithHeader(HttpHeaders.AcceptLanguage, options.AcceptLanguage);
|
|
|
|
|
FlurlClient.WithHeader(HttpHeaders.UserAgent, $"OS/{Environment.OSVersion.Platform} SKIT.FlurlHttpClient.Wechat.Tenpay/{Assembly.GetAssembly(typeof(WechatTenpayClient))!.GetName().Version}");
|
|
|
|
|
FlurlClient.WithTimeout(options.Timeout <= 0 ? Timeout.InfiniteTimeSpan : TimeSpan.FromMilliseconds(options.Timeout));
|
|
|
|
|
|
|
|
|
|
Interceptors.Add(new Interceptors.WechatTenpayRequestSigningInterceptor(
|
2022-05-09 19:28:47 +08:00
|
|
|
scheme: options.SignScheme,
|
2021-05-10 15:30:00 +08:00
|
|
|
mchId: options.MerchantId,
|
2022-01-21 14:41:40 +08:00
|
|
|
mchCertSn: options.MerchantCertificateSerialNumber,
|
|
|
|
|
mchCertPk: options.MerchantCertificatePrivateKey
|
2021-06-17 19:46:16 +08:00
|
|
|
));
|
2021-05-10 15:30:00 +08:00
|
|
|
}
|
|
|
|
|
|
2021-07-11 00:55:41 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 使用当前客户端生成一个新的 <see cref="IFlurlRequest"/> 对象。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
2024-01-29 23:12:37 +08:00
|
|
|
/// <param name="httpMethod"></param>
|
2021-07-11 00:55:41 +08:00
|
|
|
/// <param name="urlSegments"></param>
|
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
public IFlurlRequest CreateFlurlRequest(WechatTenpayRequest request, HttpMethod httpMethod, params object[] urlSegments)
|
2021-07-11 00:55:41 +08:00
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
IFlurlRequest flurlRequest = base.CreateFlurlRequest(request, httpMethod, urlSegments);
|
2021-07-11 00:55:41 +08:00
|
|
|
|
2022-01-11 17:51:28 +08:00
|
|
|
if (AutoEncryptRequestSensitiveProperty)
|
|
|
|
|
{
|
|
|
|
|
this.EncryptRequestSensitiveProperty(request);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 23:12:37 +08:00
|
|
|
if (request.WechatpayCertificateSerialNumber is not null)
|
2021-07-11 00:55:41 +08:00
|
|
|
{
|
2022-01-21 14:41:40 +08:00
|
|
|
flurlRequest.WithHeader("Wechatpay-Serial", request.WechatpayCertificateSerialNumber);
|
2021-07-11 00:55:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flurlRequest;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-10 15:30:00 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 异步发起请求。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
2021-06-17 19:46:16 +08:00
|
|
|
/// <param name="flurlRequest"></param>
|
2021-07-11 00:55:41 +08:00
|
|
|
/// <param name="httpContent"></param>
|
2021-05-10 15:30:00 +08:00
|
|
|
/// <param name="cancellationToken"></param>
|
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
public async Task<T> SendFlurlRequestAsync<T>(IFlurlRequest flurlRequest, HttpContent? httpContent = null, CancellationToken cancellationToken = default)
|
2021-05-10 15:30:00 +08:00
|
|
|
where T : WechatTenpayResponse, new()
|
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
|
2021-05-10 15:30:00 +08:00
|
|
|
|
2024-02-05 21:24:16 +08:00
|
|
|
using IFlurlResponse flurlResponse = await base.SendFlurlRequestAsync(flurlRequest, httpContent, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
2021-05-10 15:30:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 异步发起请求。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
2021-06-17 19:46:16 +08:00
|
|
|
/// <param name="flurlRequest"></param>
|
2021-05-10 15:30:00 +08:00
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <param name="cancellationToken"></param>
|
|
|
|
|
/// <returns></returns>
|
2024-01-29 23:12:37 +08:00
|
|
|
public async Task<T> SendFlurlRequestAsJsonAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default)
|
2021-05-10 15:30:00 +08:00
|
|
|
where T : WechatTenpayResponse, new()
|
|
|
|
|
{
|
2024-01-29 23:12:37 +08:00
|
|
|
if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
|
|
|
|
|
|
|
|
|
|
bool isSimpleRequest = data is null ||
|
|
|
|
|
flurlRequest.Verb == HttpMethod.Get ||
|
|
|
|
|
flurlRequest.Verb == HttpMethod.Head ||
|
|
|
|
|
flurlRequest.Verb == HttpMethod.Options;
|
|
|
|
|
using IFlurlResponse flurlResponse = isSimpleRequest ?
|
2024-02-05 21:24:16 +08:00
|
|
|
await base.SendFlurlRequestAsync(flurlRequest, null, cancellationToken).ConfigureAwait(false) :
|
|
|
|
|
await base.SendFlurlRequestAsJsonAsync(flurlRequest, data, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
2021-05-10 15:30:00 +08:00
|
|
|
}
|
|
|
|
|
|
2024-01-29 23:12:37 +08:00
|
|
|
private new async Task<TResponse> WrapFlurlResponseAsJsonAsync<TResponse>(IFlurlResponse flurlResponse, CancellationToken cancellationToken = default)
|
2022-01-04 19:27:53 +08:00
|
|
|
where TResponse : WechatTenpayResponse, new()
|
2021-05-10 15:30:00 +08:00
|
|
|
{
|
2024-02-05 21:24:16 +08:00
|
|
|
TResponse result = await base.WrapFlurlResponseAsJsonAsync<TResponse>(flurlResponse, cancellationToken).ConfigureAwait(false);
|
2021-05-10 15:30:00 +08:00
|
|
|
|
2021-11-26 00:33:50 +08:00
|
|
|
if (AutoDecryptResponseSensitiveProperty && result.IsSuccessful())
|
2021-11-25 18:05:22 +08:00
|
|
|
{
|
|
|
|
|
this.DecryptResponseSensitiveProperty(result);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-10 15:30:00 +08:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|