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 _logger; public AlipayApiClient(IOptionsMonitor optionsMonitor, ILogger 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 Request(TInput input, string methodName, string getMethod = "POST") where TResult : class, new() where TInput : class, new() { Dictionary runtime_ = new Dictionary { {"connectTimeout", 15000}, {"readTimeout", 15000}, {"retry", new Dictionary { {"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 bizParams = Parse2Dic(input); var body = JsonConvert.SerializeObject(bizParams); if (body.Length < 2000) { _logger.LogError("请求支付宝接口:" + methodName + "内容为:" + body); } Dictionary textParams = new Dictionary() { }; request_.Protocol = this._client.GetConfig("protocol"); request_.Method = getMethod; request_.Pathname = "/gateway.do"; var test = this._client.GetConfig("merchantPrivateKey"); request_.Headers = new Dictionary { {"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 ( new Dictionary() { {"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 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(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(respModel); #endif return TeaModel.ToObject(this._client.ToRespModel(respMap)); } } throw new TeaException(new Dictionary { {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, }); } catch (Exception e) { if (TeaCore.IsRetryable(e)) { _lastException = e; continue; } throw e; } } throw new TeaUnretryableException(_lastRequest, _lastException); } public async Task RequestWithFile(TInput input, Dictionary fileParams, string methodName, string getMethod = "POST") where TResult : class, new() where TInput : class, new() { Dictionary runtime_ = new Dictionary { {"connectTimeout", 15000}, {"readTimeout", 15000}, {"retry", new Dictionary { {"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 bizParams = new Dictionary(); Dictionary 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 { {"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 ( new Dictionary() { {"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 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(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(respModel); #endif return TeaModel.ToObject(this._client.ToRespModel(respMap)); } } throw new TeaException(new Dictionary { {"message", "验签失败,请检查支付宝公钥设置是否正确。"}, }); } catch (Exception e) { if (TeaCore.IsRetryable(e)) { _lastException = e; continue; } throw e; } } throw new TeaUnretryableException(_lastRequest, _lastException); } public async Task PageRequest(TInput input, string methodName, string returnUrl, string getMethod = "POST") where TResult : class, new() where TInput : class, new() { var systemParams = this.GetSystemParams(methodName); Dictionary bizParams = ClientUtil.Parse2Dic(input); Dictionary textParams = new Dictionary { {"return_url", returnUrl }, }; string sign = this._client.Sign(systemParams, bizParams, textParams, this._client.GetConfig("merchantPrivateKey")); Dictionary response = new Dictionary { {"body", this._client.GeneratePage(getMethod, systemParams, bizParams, textParams, sign) }, }; return TeaModel.ToObject(response); } public Dictionary GetSystemParams(string methodName) { Dictionary systemParams = new Dictionary { {"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 textParams, Dictionary fileParams, string boundary) { MemoryStream memoryStream = new MemoryStream(); foreach (KeyValuePair 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 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 Parse2StrDic(TInput input) where TInput : class, new() { Dictionary dictionary = new Dictionary(); 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(); 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 Parse2Dic(object input) { if (input == null) { return new Dictionary(); } // 将对象序列化为 JSON 字符串 string jsonString = JsonConvert.SerializeObject(input); return ConvertJsonStringToDictionary(jsonString); } private Dictionary ConvertJsonStringToDictionary(string jsonString) { JToken token = JToken.Parse(jsonString); return ParseToken(token) as Dictionary; } 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 ParseObject(JObject jObject) { var dict = new Dictionary(); foreach (var property in jObject.Properties()) { dict[property.Name] = ParseToken(property.Value); } return dict; } private Dictionary ParseArray(JArray jArray) { var dict = new Dictionary(); for (int i = 0; i < jArray.Count; i++) { dict[i.ToString()] = ParseToken(jArray[i]); } return dict; } } }