.NET 4.7.1中HttpClient.SendAsync遇HTTP 204触发空引用异常
.NET 4.7.1中HttpClient处理HTTP 204响应触发未捕获NullReferenceException的解决办法
问题详情
在目标框架为.NET 4.7.1的应用中,使用HttpClient执行GET请求时,若服务器返回HTTP 204(无内容)响应,会触发System.NullReferenceException,且该异常无法被try-catch语句捕获。相同请求在使用IHttpClientFactory的.NET Core应用中可正常运行。
涉及代码
protected async Task<HttpResponseMessage> GetResponse(string path, Dictionary<string, string> headers) { HttpResponseMessage responseMessage = null; var request = new HttpRequestMessage(HttpMethod.Get, path); if (headers != null) { foreach (var header in headers) { request.Headers.Add(header.Key, header.Value); } } var proxy = new WebProxy { Address = new Uri($"http://{ProxyHost}:{ProxyPort}"), BypassProxyOnLocal = false, UseDefaultCredentials = false, Credentials = new NetworkCredential(userName: ProxyUser, password: ProxyPW) }; // 创建使用该代理的客户端处理器 var httpClientHandler = new HttpClientHandler { Proxy = proxy }; var httpclient = new HttpClient(httpClientHandler); try { responseMessage = await httpclient.SendAsync(request); } catch (Exception ex) { // 错误处理逻辑 } return responseMessage; }
异常触发点
responseMessage = await httpclient.SendAsync(request);
Visual Studio捕获的未处理异常详情
System.NullReferenceException HResult=0x80004003 Message=未将对象引用设置到对象的实例。 Source=mscorlib StackTrace: at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask) --- End of stack trace from previous location --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() This exception was originally thrown at this call stack: [External Code]
事件查看器中的异常堆栈
StackTrace: at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext) at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext) at System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state) at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state) at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch()
解决方案
该异常的根源并非HTTP 204响应本身,而是.NET Framework 4.7.1中旧ASP.NET同步上下文(LegacyAspNetSynchronizationContext)在异步回调时的空引用BUG,可通过以下方式解决:
1. 禁用旧ASP.NET同步上下文
在应用启动时(如Global.asax.cs的Application_Start方法)添加以下代码,强制使用新的同步上下文:
System.Web.AspNetSynchronizationContext.SetUseLegacyAspNetSynchronizationContext(false);
2. 优化HttpClient使用方式
- 复用HttpClient实例:避免每次请求都创建新的
HttpClient,复用实例能减少资源开销,同时规避部分同步上下文相关问题。 - 指定响应完成选项:调用
SendAsync时显式传入HttpCompletionOption.ResponseHeadersRead,确保即使是204响应也能正确返回响应对象:
responseMessage = await httpclient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
3. 捕获未处理的异步任务异常
若禁用旧同步上下文不可行,可注册全局事件捕获未处理的异步任务异常,避免程序崩溃:
TaskScheduler.UnobservedTaskException += (sender, e) => { e.SetObserved(); // 此处添加异常日志记录逻辑 };
4. 升级.NET Framework版本
如果条件允许,将应用升级到.NET Framework 4.8或更高版本,微软在后续版本中修复了多个异步同步上下文相关的BUG,可彻底解决此类问题。
内容的提问来源于stack exchange,提问作者redrobot
相关产品推荐
相关产品推荐

