如何在ASP.NET WebForm中通过HttpClient调用ASP.NET Core Web API?
ASP.NET WebForms调用ASP.NET Core API无响应问题排查与解决
问题描述
我有两个项目:一个是基于ASP.NET Core 3.1(MVC)的Web API,另一个是ASP.NET WebForms网站(.NET Framework 4.8)。从WebForms网站调用Core API时没有响应,但在另一个.NET Core项目中,使用Page_Load里的相同HttpClient代码却能正常调用。
ASP.NET Core 3.1 API控制器代码
namespace User { [Authorize] [Route("api/[controller]")] [ApiController] public class UserController : ControllerBase { [HttpGet("GetUserDetailsByUserName/{userName}")] public IActionResult GetUserDetailsByUserName(string userName) { //根据userName从数据库获取数据 } [HttpPost("AddNewUser")] public ActionResult AddNewUser([FromBody] UserModel userModel) { //将新用户数据保存到数据库 } } }
ASP.NET WebForms(.NET Framework 4.8)代码
using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; namespace WebApplication { public partial class User : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //调用GetUserDetailsByUserName(); HttpClient httpClient = Client.GetClient(); httpClient.BaseAddress = new Uri("https://*******/"); //DOT_NET_CORE_WEBSITE_URL httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "TOKEN"); HttpResponseMessage httpResponseMessage; httpResponseMessage = await httpClient.GetAsync($"https://*******/GetUserDetailsByUserName/{userName}"); //此处无响应 httpResponseMessage.EnsureSuccessStatusCode(); string result = await httpResponseMessage.Content.ReadAsStringAsync(); } } public class Client { public static HttpClient GetClient() { var httpClientHandler = new HttpClientHandler(); httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; httpClientHandler.UseDefaultCredentials = true; HttpClient httpClient = new HttpClient(httpClientHandler); httpClient.Timeout = TimeSpan.FromMinutes(10); httpClient.DefaultRequestHeaders.Accept.Clear(); return httpClient; } } public class UserModel { public string UserName{get;set;} public string Password{get;set;} } }
排查与解决办法
1. 修复异步方法使用问题
WebForms的Page_Load是同步方法,直接使用await会触发上下文死锁——ASP.NET Framework的同步上下文会等待异步操作完成,但await会捕获该上下文,导致线程阻塞。
解决: 将Page_Load标记为异步方法:
protected async void Page_Load(object sender, EventArgs e) { // 原有业务逻辑保留,await正常使用 }
注:async void仅在页面事件处理程序中允许,其他场景尽量避免使用。
2. 修正请求URL路径错误
API的路由规则是api/[controller]/GetUserDetailsByUserName/{userName},完整路径应为https://xxx/api/User/GetUserDetailsByUserName/{userName},但现有代码的请求URL缺少api/User前缀。
解决: 调整请求URL,可结合BaseAddress使用相对路径:
httpClient.BaseAddress = new Uri("https://*******/"); // 使用相对路径调用 httpResponseMessage = await httpClient.GetAsync($"api/User/GetUserDetailsByUserName/{userName}");
3. 优化HttpClient实例管理
WebForms中每次创建新的HttpClient实例可能导致连接池耗尽,虽不是当前无响应的直接原因,但会引发长期稳定性问题。
优化方案: 将HttpClient改为静态单例:
public class Client { private static readonly HttpClient _httpClient; static Client() { var httpClientHandler = new HttpClientHandler(); httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true; httpClientHandler.UseDefaultCredentials = true; _httpClient = new HttpClient(httpClientHandler); _httpClient.Timeout = TimeSpan.FromMinutes(10); _httpClient.DefaultRequestHeaders.Accept.Clear(); } public static HttpClient GetClient() { return _httpClient; } }
4. 排查证书与权限冲突
- 若API使用自签名证书,虽已关闭验证,但仍需确保WebForms服务器能正常访问API端点(可先用浏览器/Postman在WebForms服务器上测试API连通性)。
UseDefaultCredentials = true会发送当前Windows凭据,若API仅需Bearer Token授权,可能导致权限冲突,可尝试设置为false:
httpClientHandler.UseDefaultCredentials = false;
5. 避免同步上下文捕获
若仍存在死锁问题,可在await时使用ConfigureAwait(false)跳过同步上下文捕获:
httpResponseMessage = await httpClient.GetAsync($"api/User/GetUserDetailsByUserName/{userName}").ConfigureAwait(false); string result = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
内容的提问来源于stack exchange,提问作者Prashant Girase
相关产品推荐
相关产品推荐

