ASP.NET Framework 4.8调用API遇WebException问题求助
问题分析与解决方案
核心问题定位
从异常栈和代码来看,导致连接被远程主机强制关闭的原因涉及以下几点:
- URL配置读取错误,导致请求地址无效
- URL拼接方式错误,未正确替换模板占位符
- TLS版本不兼容(第三方API可能要求TLS 1.2+/禁用旧协议)
- HttpClient频繁创建导致连接池耗尽
- 同步调用异步方法的潜在死锁风险
分步修复
1. 修正URL配置读取错误
代码中读取的配置项是QueryTransactionUrl,但实际配置的key是GetTransactionUrl,这会导致请求地址为空或错误,先修正配置读取:
private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"];
2. 正确拼接请求URL
原代码直接将TransRef拼接到URL末尾,未替换模板中的{trans_ref}占位符,会生成无效地址,改为占位符替换:
// 替换模板中的占位符,生成正确的API地址 string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef);
3. 配置兼容的TLS版本
第三方API通常要求使用TLS 1.2或更高版本,在.NET Framework 4.8中显式启用对应协议:
在服务类的静态构造函数或请求发起前添加:
// 启用TLS 1.2和1.3,根据第三方API要求调整 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13; // 禁用旧协议(可选) ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
4. 优化HttpClient复用
频繁创建HttpClient会导致TCP连接耗尽,应复用静态实例:
public class Service : System.Web.Services.WebService { // 静态HttpClient实例,全局复用 private static readonly HttpClient _httpClient = new HttpClient(); private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"]; static Service() { // 初始化默认请求头 _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // 配置TLS版本 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13; } // ... 其他代码 }
5. 避免同步调用异步方法的死锁风险
原代码使用.Result同步等待异步操作,在ASP.NET环境下可能引发死锁,推荐改为异步WebMethod:
[WebMethod] public async Task<TransferResponse> TransferStatusService(String TransRef) { TransRef = Server.HtmlEncode(TransRef).AlphaNumeric(); TransferResponse resp = new TransferResponse(); try { string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef); HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); if (response.IsSuccessStatusCode) { string apiResponse = await response.Content.ReadAsStringAsync(); var responseData = JsonConvert.DeserializeObject<ApiTransferResponseDto>(apiResponse); if (responseData.payload != null && responseData.payload.responseStatus == "SUCCESS") { // 填充resp的逻辑 resp.TransRef = responseData.payload.extTnxReference; resp.ResponseCode = responseData.payload.responseStatusCode; resp.ResponseText = responseData.payload.responseStatusDesc; // 其他字段赋值... } else { resp.ResponseText = "INVALID"; } } else { resp.ResponseText = $"API Request Failed: {response.StatusCode}"; } } catch (Exception ex) { Logger.WriteLog(ex.ToString()); // 记录完整异常栈而非仅消息 resp.ResponseCode = "8003"; resp.ResponseText = "请求处理异常"; return resp; } return resp; }
6. 网络层面排查
- 用Postman/curl测试API地址是否能正常访问,确认地址、参数、请求头正确性
- 检查服务器防火墙/代理是否允许出站访问该第三方API域名
- 确认第三方API是否要求IP白名单、Authorization等额外请求头
- 查看第三方API文档,确认请求格式是否符合要求
修复后完整代码示例
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 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 static readonly HttpClient _httpClient = new HttpClient(); private string apiBaseSingleStatusUrl = ConfigurationManager.AppSettings["GetTransactionUrl"]; static Service() { _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13; ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11); } [WebMethod] public async Task<TransferResponse> TransferStatusService(string TransRef) { TransRef = Server.HtmlEncode(TransRef).AlphaNumeric(); TransferResponse resp = new TransferResponse(); try { string apiUrl = apiBaseSingleStatusUrl.Replace("{trans_ref}", TransRef); HttpResponseMessage response = await _httpClient.GetAsync(apiUrl); if (response.IsSuccessStatusCode) { string apiResponse = await response.Content.ReadAsStringAsync(); var responseData = JsonConvert.DeserializeObject<ApiTransferResponseDto>(apiResponse); if (responseData.payload != null && responseData.payload.responseStatus == "SUCCESS") { resp.TransRef = responseData.payload.extTnxReference; resp.ResponseCode = responseData.payload.responseStatusCode; resp.ResponseText = responseData.payload.responseStatusDesc; // 补充其他字段赋值逻辑 } else { resp.ResponseText = "INVALID"; } } else { resp.ResponseText = $"API请求失败: {response.StatusCode}"; } } catch (Exception ex) { Logger.WriteLog(ex.ToString()); resp.ResponseCode = "8003"; resp.ResponseText = "请求处理异常"; return resp; } return resp; } }
内容的提问来源于stack exchange,提问作者Ayobamilaye
相关产品推荐
相关产品推荐

