using Alipay.EasySDK.Kernel;
|
using Alipay.EasySDK.Kernel.Util;
|
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Options;
|
using Newtonsoft.Json;
|
using Newtonsoft.Json.Linq;
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Reflection;
|
using System.Threading.Tasks;
|
using Tea;
|
using Volo.Abp.Domain.Services;
|
using ZeroD.Util;
|
|
namespace LifePayment.Domain
|
{
|
public class AlipayApiClient : DomainService
|
{
|
public const string SDKVERSION = "alipay-easysdk-net-2.0.0";
|
protected Client _client;
|
private ILogger<AlipayApiClient> _logger;
|
|
|
public AlipayApiClient(IOptionsMonitor<Config> optionsMonitor, ILogger<AlipayApiClient> logger, string optionsName = null)
|
{
|
Context context = new Context(optionsName.IsNullOrEmpty() ? optionsMonitor.CurrentValue : optionsMonitor.Get(optionsName), SDKVERSION);
|
_logger = logger;
|
this._client = new Client(context);
|
}
|
|
public async Task<TResult> Request<TInput, TResult>(TInput input, string methodName, string getMethod = "POST")
|
where TResult : class, new()
|
where TInput : class, new()
|
{
|
Dictionary<string, object> runtime_ = new Dictionary<string, object>
|
{
|
{"connectTimeout", 15000},
|
{"readTimeout", 15000},
|
{"retry", new Dictionary<string, int?>
|
{
|
{"maxAttempts", 0},
|
}},
|
};
|
|
TeaRequest _lastRequest = null;
|
Exception _lastException = null;
|
long _now = System.DateTime.Now.Millisecond;
|
int _retryTimes = 0;
|
while (TeaCore.AllowRetry((IDictionary)runtime_["retry"], _retryTimes, _now))
|
{
|
if (_retryTimes > 0)
|
{
|
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
|
if (backoffTime > 0)
|
{
|
TeaCore.Sleep(backoffTime);
|
}
|
}
|
_retryTimes = _retryTimes + 1;
|
try
|
{
|
TeaRequest request_ = new TeaRequest();
|
|
Dictionary<string, object> bizParams = Parse2Dic(input);
|
var body = JsonConvert.SerializeObject(bizParams);
|
if (body.Length < 2000)
|
{
|
_logger.LogError("请求支付宝接口:" + methodName + "内容为:" + body);
|
}
|
|
Dictionary<string, string> textParams = new Dictionary<string, string>() { };
|
request_.Protocol = this._client.GetConfig("protocol");
|
request_.Method = getMethod;
|
request_.Pathname = "/gateway.do";
|
var test = this._client.GetConfig("merchantPrivateKey");
|
request_.Headers = new Dictionary<string, string>
|
{
|
{"host", this._client.GetConfig("gatewayHost")},
|
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
|
};
|
var systemParams = this.GetSystemParams(methodName);
|
request_.Query = this._client.SortMap(TeaConverter.merge<string>
|
(
|
new Dictionary<string, string>()
|
{
|
{"sign", this._client.Sign(systemParams, bizParams, textParams, this._client.GetConfig("merchantPrivateKey")) },
|
},
|
systemParams,
|
textParams
|
));
|
request_.Body = TeaCore.BytesReadable(this._client.ToUrlEncodedRequestBody(bizParams));
|
_lastRequest = request_;
|
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);
|
|
Dictionary<string, object> respMap = this._client.ReadAsJson(response_, methodName);
|
var responseBody = JsonConvert.SerializeObject(respMap);
|
if (responseBody.Length < 2000)
|
{
|
_logger.LogError("支付宝返回结果:" + methodName + "内容为:" + responseBody);
|
}
|
if (this._client.IsCertMode())
|
{
|
if (this._client.Verify(respMap, this._client.ExtractAlipayPublicKey(this._client.GetAlipayCertSN(respMap))))
|
{
|
return TeaModel.ToObject<TResult>(this._client.ToRespModel(respMap));
|
}
|
}
|
else
|
{
|
if (this._client.Verify(respMap, this._client.GetConfig("alipayPublicKey")))
|
{
|
#if DEBUG
|
// var respModel = this._client.ToRespModel(respMap);
|
// var resultObject = TeaModel.ToObject<TResult>(respModel);
|
|
#endif
|
return TeaModel.ToObject<TResult>(this._client.ToRespModel(respMap));
|
}
|
}
|
throw new TeaException(new Dictionary<string, string>
|
{
|
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
|
});
|
}
|
catch (Exception e)
|
{
|
if (TeaCore.IsRetryable(e))
|
{
|
_lastException = e;
|
continue;
|
}
|
throw e;
|
}
|
}
|
|
throw new TeaUnretryableException(_lastRequest, _lastException);
|
}
|
|
public async Task<TResult> RequestWithFile<TInput, TResult>(TInput input, Dictionary<string, (string Name, byte[] Bytes)> fileParams, string methodName, string getMethod = "POST")
|
where TResult : class, new()
|
where TInput : class, new()
|
{
|
Dictionary<string, object> runtime_ = new Dictionary<string, object>
|
{
|
{"connectTimeout", 15000},
|
{"readTimeout", 15000},
|
{"retry", new Dictionary<string, int?>
|
{
|
{"maxAttempts", 0},
|
}},
|
};
|
|
TeaRequest _lastRequest = null;
|
Exception _lastException = null;
|
long _now = System.DateTime.Now.Millisecond;
|
int _retryTimes = 0;
|
while (TeaCore.AllowRetry((IDictionary)runtime_["retry"], _retryTimes, _now))
|
{
|
if (_retryTimes > 0)
|
{
|
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
|
if (backoffTime > 0)
|
{
|
TeaCore.Sleep(backoffTime);
|
}
|
}
|
_retryTimes = _retryTimes + 1;
|
try
|
{
|
TeaRequest request_ = new TeaRequest();
|
|
Dictionary<string, object> bizParams = new Dictionary<string, object>();
|
Dictionary<string, string> textParams = Parse2StrDic(input);
|
var body = JsonConvert.SerializeObject(textParams);
|
if (body.Length < 2000)
|
{
|
_logger.LogError("请求支付宝接口:" + methodName + "内容为:" + body);
|
}
|
request_.Protocol = this._client.GetConfig("protocol");
|
request_.Method = getMethod;
|
request_.Pathname = "/gateway.do";
|
var boundary = _client.GetRandomBoundary();
|
var test = this._client.GetConfig("merchantPrivateKey");
|
request_.Headers = new Dictionary<string, string>
|
{
|
{"host", this._client.GetConfig("gatewayHost")},
|
{"content-type",_client.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)}
|
};
|
var systemParams = this.GetSystemParams(methodName);
|
request_.Query = this._client.SortMap(TeaConverter.merge<string>
|
(
|
new Dictionary<string, string>()
|
{
|
{"sign", this._client.Sign(systemParams, bizParams, textParams, this._client.GetConfig("merchantPrivateKey")) },
|
},
|
systemParams,
|
textParams
|
));
|
//request_.Body = TeaCore.BytesReadable(this._client.ToUrlEncodedRequestBody(bizParams));
|
request_.Body = ToMultipartRequestBody(textParams, fileParams, boundary);
|
_lastRequest = request_;
|
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);
|
|
Dictionary<string, object> respMap = this._client.ReadAsJson(response_, methodName);
|
var responseBody = JsonConvert.SerializeObject(respMap);
|
if (responseBody.Length < 2000)
|
{
|
_logger.LogError("支付宝返回结果:" + methodName + "内容为:" + responseBody);
|
}
|
if (this._client.IsCertMode())
|
{
|
if (this._client.Verify(respMap, this._client.ExtractAlipayPublicKey(this._client.GetAlipayCertSN(respMap))))
|
{
|
return TeaModel.ToObject<TResult>(this._client.ToRespModel(respMap));
|
}
|
}
|
else
|
{
|
if (this._client.Verify(respMap, this._client.GetConfig("alipayPublicKey")))
|
{
|
#if DEBUG
|
// var respModel = this._client.ToRespModel(respMap);
|
// var resultObject = TeaModel.ToObject<TResult>(respModel);
|
|
#endif
|
return TeaModel.ToObject<TResult>(this._client.ToRespModel(respMap));
|
}
|
}
|
throw new TeaException(new Dictionary<string, string>
|
{
|
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
|
});
|
}
|
catch (Exception e)
|
{
|
if (TeaCore.IsRetryable(e))
|
{
|
_lastException = e;
|
continue;
|
}
|
throw e;
|
}
|
}
|
|
throw new TeaUnretryableException(_lastRequest, _lastException);
|
}
|
|
public async Task<TResult> PageRequest<TInput, TResult>(TInput input, string methodName, string returnUrl, string getMethod = "POST")
|
where TResult : class, new()
|
where TInput : class, new()
|
{
|
var systemParams = this.GetSystemParams(methodName);
|
Dictionary<string, object> bizParams = ClientUtil.Parse2Dic(input);
|
Dictionary<string, string> textParams = new Dictionary<string, string>
|
{
|
{"return_url", returnUrl },
|
};
|
string sign = this._client.Sign(systemParams, bizParams, textParams, this._client.GetConfig("merchantPrivateKey"));
|
Dictionary<string, string> response = new Dictionary<string, string>
|
{
|
{"body", this._client.GeneratePage(getMethod, systemParams, bizParams, textParams, sign) },
|
};
|
return TeaModel.ToObject<TResult>(response);
|
}
|
|
public Dictionary<string, string> GetSystemParams(string methodName)
|
{
|
Dictionary<string, string> systemParams = new Dictionary<string, string>
|
{
|
{"method", methodName},
|
{"app_id", this._client.GetConfig("appId")},
|
{"timestamp", this._client.GetTimestamp()},
|
{"format", "json"},
|
{"version", "1.0"},
|
{"alipay_sdk", this._client.GetSdkVersion()},
|
{"charset", "UTF-8"},
|
{"sign_type", this._client.GetConfig("signType")},
|
{"app_cert_sn", this._client.GetMerchantCertSN()},
|
{"alipay_root_cert_sn", this._client.GetAlipayRootCertSN()},
|
};
|
return systemParams;
|
}
|
|
private Stream ToMultipartRequestBody(Dictionary<string, string> textParams, Dictionary<string, (string Name, byte[] Bytes)> fileParams, string boundary)
|
{
|
MemoryStream memoryStream = new MemoryStream();
|
foreach (KeyValuePair<string, string> textParam in textParams)
|
{
|
if (!string.IsNullOrEmpty(textParam.Key) && !string.IsNullOrEmpty(textParam.Value))
|
{
|
MultipartUtil.WriteToStream(memoryStream, MultipartUtil.GetEntryBoundary(boundary));
|
MultipartUtil.WriteToStream(memoryStream, MultipartUtil.GetTextEntry(textParam.Key, textParam.Value));
|
}
|
}
|
|
foreach (KeyValuePair<string, (string Name, byte[] Bytes)> fileParam in fileParams)
|
{
|
if (!string.IsNullOrEmpty(fileParam.Key))
|
{
|
MultipartUtil.WriteToStream(memoryStream, MultipartUtil.GetEntryBoundary(boundary));
|
MultipartUtil.WriteToStream(memoryStream, GetFileEntry(fileParam.Key, fileParam.Value.Name));
|
MultipartUtil.WriteToStream(memoryStream, fileParam.Value.Bytes);
|
}
|
}
|
|
MultipartUtil.WriteToStream(memoryStream, MultipartUtil.GetEndBoundary(boundary));
|
memoryStream.Seek(0L, SeekOrigin.Begin);
|
return memoryStream;
|
}
|
|
private byte[] GetFileEntry(string fieldName, string fileName)
|
{
|
string s = "Content-Disposition:form-data;name=\"" + fieldName + "\";filename=\"" + fileName + "\"\r\nContent-Type:application/octet-stream\r\n\r\n";
|
return AlipayConstants.DEFAULT_CHARSET.GetBytes(s);
|
}
|
|
private Dictionary<string, string> Parse2StrDic<TInput>(TInput input) where TInput : class, new()
|
{
|
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
Type typeFromHandle = typeof(TInput);
|
PropertyInfo[] properties = typeFromHandle.GetProperties().Where(x => !x.CustomAttributes.Any(x => x.AttributeType == typeof(JsonIgnoreAttribute))).ToArray();
|
PropertyInfo[] array = properties;
|
foreach (PropertyInfo propertyInfo in array)
|
{
|
JsonPropertyAttribute attribute = propertyInfo.GetCustomAttribute<JsonPropertyAttribute>();
|
string key = string.Empty;
|
bool flag = false;
|
if (attribute != null)
|
{
|
if (attribute.PropertyName != null)
|
{
|
key = attribute.PropertyName;
|
}
|
|
if (attribute.NullValueHandling == NullValueHandling.Ignore)
|
{
|
flag = true;
|
}
|
else if (attribute.NullValueHandling == NullValueHandling.Include)
|
{
|
flag = false;
|
}
|
}
|
else
|
{
|
key = propertyInfo.Name;
|
}
|
|
object obj = propertyInfo.GetValue(input, null);
|
if (!flag || obj != null)
|
{
|
if (obj is IDictionary && obj != null)
|
{
|
obj = JsonConvert.SerializeObject(obj);
|
}
|
|
dictionary.Add(key, Convert.ToString(obj));
|
}
|
}
|
|
return dictionary;
|
}
|
|
private Dictionary<string, object> Parse2Dic(object input)
|
{
|
if (input == null)
|
{
|
return new Dictionary<string, object>();
|
}
|
|
// 将对象序列化为 JSON 字符串
|
string jsonString = JsonConvert.SerializeObject(input);
|
return ConvertJsonStringToDictionary(jsonString);
|
}
|
|
private Dictionary<string, object> ConvertJsonStringToDictionary(string jsonString)
|
{
|
JToken token = JToken.Parse(jsonString);
|
return ParseToken(token) as Dictionary<string, object>;
|
}
|
|
private object ParseToken(JToken token)
|
{
|
switch (token.Type)
|
{
|
case JTokenType.Object:
|
return ParseObject(token as JObject);
|
case JTokenType.Array:
|
return ParseArray(token as JArray);
|
default:
|
return ((JValue)token).Value;
|
}
|
}
|
|
private Dictionary<string, object> ParseObject(JObject jObject)
|
{
|
var dict = new Dictionary<string, object>();
|
foreach (var property in jObject.Properties())
|
{
|
dict[property.Name] = ParseToken(property.Value);
|
}
|
return dict;
|
}
|
|
private Dictionary<string, object> ParseArray(JArray jArray)
|
{
|
var dict = new Dictionary<string, object>();
|
for (int i = 0; i < jArray.Count; i++)
|
{
|
dict[i.ToString()] = ParseToken(jArray[i]);
|
}
|
return dict;
|
}
|
}
|
}
|