ASP.NET Framework - 如何解决 WebException:底层连接已关闭:发送时发生意外错误

问题描述 投票:0回答:1

我有一个 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;
    }
}
c# asp.net frameworks
1个回答
0
投票

首先 - 在处理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:底层连接已关闭:发送时发生意外错误

© www.soinside.com 2019 - 2024. All rights reserved.