我有一个 ASP.NET Framework-4.8 中的旧项目,我可以使用这个 API。它是一个 GET 请求,带有 JSON 请求和响应。 我想使用 HttpClient GET 请求来使用 API。
网址:
<appSettings>
<add key="GetTransactionUrl" value="https://thirdpartyapi/QueryEntries/{trans_ref}"/>
</appSettings>
我收到此错误:
System.AggregateException
HResult=0x80131500
Message=One or more errors occurred.
Source=mscorlib
StackTrace:
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at Service.SingleTransferStatusRequest(String TransRef) in c:\Service.cs:line 385
This exception was originally thrown at this call stack:
System.Net.Sockets.Socket.EndReceive(System.IAsyncResult)
System.Net.Sockets.NetworkStream.EndRead(System.IAsyncResult)
Inner Exception 1:
HttpRequestException: An error occurred while sending the request.
Inner Exception 2:
WebException: The underlying connection was closed: An unexpected error occurred on a send.
Inner Exception 3:
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Inner Exception 4:
SocketException: An existing connection was forcibly closed by the remote host
当我调试并设置断点时,它指向这一行:
HttpResponseMessage response = client.GetAsync(apiBaseTransactionStatusUrl).Result;
请帮忙解决问题。
主要代码:
DTO:
public class TransferResponse
{
public String TransRef { get; set; }
public String TransactionDate { get; set; }
public String ResponseCode { get; set; }
public String ResponseText { get; set; }
public decimal Amount { get; set; }
}
public class ApiTransferResponseDto
{
public int statusCode { get; set; }
public Payload payload { get; set; }
public string message { get; set; }
public bool hasError { get; set; }
public class Payload
{
public string serviceName { get; set; }
public string operationName { get; set; }
public string entryDate { get; set; }
public string responseXml { get; set; }
public string tnxReference { get; set; }
public string responseStatus { get; set; }
public string msgId { get; set; }
public string batch { get; set; }
public string extTnxReference { get; set; }
public object isReversed { get; set; }
public string postingReference { get; set; }
public string responseStatusDesc { get; set; }
public string responseStatusCode { get; set; }
}
}
服务层:
public class Service : System.Web.Services.WebService
{
private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["QueryTransactionUrl"];
[WebMethod]
public TransferResponse TransferStatusService(String TransRef)
{
TransRef = Server.HtmlEncode(TransRef).AlphaNumeric();
TransferResponse resp = new TransferResponse();
try
{
using (HttpClient client = new HttpClient())
{
// Add headers if needed
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Define the API endpoint URL with the TransRef parameter
string apiBaseSingleTransactionStatusUrl = apiBaseSingleStatusUrl + TransRef;
// Send the GET request to the API
HttpResponseMessage response = client.GetAsync(apiBaseSingleTransactionStatusUrl).Result;
// Check if the response was successful
if (response.IsSuccessStatusCode)
{
// Read the response content as a string
string apiResponse = response.Content.ReadAsStringAsync().Result;
//string apiResponse = await response.Content.ReadAsStringAsync();
// Parse the JSON response
var responseData = JsonConvert.DeserializeObject<ApiTransferResponseDto>(apiResponse);
if (responseData.payload != null && responseData.payload.responseStatus == "SUCCESS")
{
// Parse the XML responseXml
var xmlDoc = XDocument.Parse(responseData.payload.responseXml);
var extSysAccDetails = xmlDoc.Descendants("Ext-Sys-Acc-Details").FirstOrDefault();
resp.TransactionDate = extSysAccDetails.Element("TRNDT").Value;
resp.TransRef = TransRef;
resp.Amount = decimal.Parse(extSysAccDetails.Element("LCYAMOUNT").Value);
}
else
{
resp.ResponseText = "INVALID";
}
}
else
{
resp.ResponseText = "API Request Failed";
}
}
}
catch (Exception ex)
{
Logger.WriteLog(ex.Message);
resp.ResponseCode = "8003";
resp.ResponseText = ex.Message;
return resp;
}
return resp;
}
}
首先 - 在处理http请求时,避免使用.Result from Task(它可能会导致死锁和其他问题) - http客户端方法通常是异步的,所以最好的方法是将方法签名更改为
public async Task<TransferResponse> TransferStatusService(String TransRef)
然后你可以在发送请求时使用await关键字,如下所示:
HttpResponseMessage response = await client.GetAsync(apiBaseSingleTransactionStatusUrl);
如果你不能使用 async 和await,至少使用它而不是 .Result 属性:
HttpResponseMessage response = client.GetAsync(apiBaseSingleTransactionStatusUrl).GetAwaiter().GetResult();
仍然不如 async wait,但比使用 .Result 好得多。
通过查看这一行
<add key="GetTransactionUrl" value="https://thirdpartyapi/QueryEntries/{trans_ref}"/>
和您的服务层,我发现密钥名称不匹配:
private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["QueryTransactionUrl"];
一个是 GetTransactionUrl,第二个是 QueryTransactionUrl - 不确定它是否只是旧代码并且您现在已经正确地使用了它,但我想提一下。
但是如果你会使用
<add key="GetTransactionUrl" value="https://thirdpartyapi/QueryEntries/{trans_ref}"/>
与您的 apiBaseLine
string apiBaseSingleTransactionStatusUrl = apiBaseSingleStatusUrl + TransRef;
使用您问题中的设置,您实际上会生成类似的字符串
string apiBaseSingleTransactionStatusUrl = "https://thirdpartyapi/QueryEntries/{trans_ref}123";
回到你的错误 - 尝试使用 async/await,或者至少使用 GetAwaiter().GetResult()。接下来我要尝试的是这里提到的解决方案,它不起作用:httpclient.GetAsync:底层连接已关闭:发送时发生意外错误