ASP.NET 4.7.2调用SendAsync()时mscorlib.dll抛出未捕获NullReferenceException
ASP.NET 4.7.2异步POST请求抛出未捕获NullReferenceException问题
问题描述
基于ASP.NET 4.7.2(C#)的Web应用中,使用HttpClient发送POST请求时,执行代码response = await client.SendAsync(request);会抛出An unhandled exception of type 'System.NullReferenceException' occurred in mscorlib.dll,且外层的try/catch无法捕获该异常。完全相同的代码在WinForms应用和控制台项目中可正常运行。
异常详情
at System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state) at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state) at System.Web.LegacyAspNetSynchronizationContext.Post(SendOrPostCallback callback, Object state) at System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.PostAction(Object state) at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask) --- End of stack trace from previous location --- at System.Threading.Tasks.AwaitTaskContinuation.<>c.<ThrowAsyncIfNecessary>b__18_0(Object s) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) 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() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() <ExceptionString>System.NullReferenceException: Δεν έχει οριστεί αναφορά αντικειμένου at μια παρουσία αντικειμένου. 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.Web.LegacyAspNetSynchronizationContext.Post(SendOrPostCallback callback, Object state) at System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.PostAction(Object state) at System.Threading.Tasks.AwaitTaskContinuation.RunCallback(ContextCallback callback, Object state, Task& currentTask) --- End of stack trace from previous location --- at System.Threading.Tasks.AwaitTaskContinuation.<>c.<ThrowAsyncIfNecessary>b__18_0(Object s) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) 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() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()</ExceptionString> An unhandled exception of type 'System.NullReferenceException' occurred in mscorlib.dll
精简代码
public async Task<bool> SendPostRequestAsync() { string endpoint = "endpointname"; url = endpointUrl; var client = new HttpClient(); var queryString = HttpUtility.ParseQueryString(string.Empty); // 添加认证请求头 client.DefaultRequestHeaders.Add(...); client.DefaultRequestHeaders.Add(...); var uri = url + endpoint + "?" + queryString; HttpResponseMessage response = new HttpResponseMessage(); byte[] byteData = Encoding.UTF8.GetBytes(bodyxml); using (var content = new ByteArrayContent(byteData)) { try { Uri myUri = new Uri(uri, UriKind.Absolute); HttpRequestMessage request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = myUri, Content = content }; content.Headers.ContentType = new MediaTypeHeaderValue("text/plain"); // 检查关键对象是否为空 bool iAmOk = ((client != null) && (response != null) && (url != null) && (request != null) && (bodyxml != null)); if (!iAmOk) { return false; } try { response = await client.SendAsync(request); // 此处抛出异常 } catch (Exception ex) { string msg = ex.Message; // 从未进入此处 } var contents = response.Content.ReadAsStringAsync().Result; if (response.StatusCode == HttpStatusCode.OK) { // 请求成功 return true; } else { _log.Error("errordata"); // 请求失败 return false; } } catch (Exception exx) { // 也从未进入此处 _log.Error("exceptiondata"); return false; } } }
开发环境
- Microsoft Visual Studio Community 2019 Version 16.11.29
- ASP.NET and Web Tools 2019 16.11.116.46506
- ASP.NET Web Frameworks and Tools 2019 16.11.116.46506
- .NET Framework 4.7.2
问题原因与解决方案
原因
这是ASP.NET传统同步上下文(LegacyAspNetSynchronizationContext)的问题:异步操作完成后,回调尝试回到原ASP.NET上下文时,ThreadContext对象已为空,导致NullReferenceException。这种异常发生在同步上下文的回调逻辑中,无法被业务代码的try/catch捕获。
解决方案
- 启用Task友好的同步上下文
在web.config的<appSettings>节点中添加配置,让ASP.NET使用现代的AspNetSynchronizationContext:
<appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> </appSettings>
该配置从.NET 4.5开始支持,4.7.2完全兼容,能解决绝大多数异步上下文相关的异常。
- 避免异步代码中混用同步阻塞
代码中response.Content.ReadAsStringAsync().Result使用了同步阻塞的.Result,这会破坏异步流程,甚至引发死锁。改为异步等待:
var contents = await response.Content.ReadAsStringAsync();
保持异步调用链完整
确保调用SendPostRequestAsync的上游代码也是异步等待,不要使用.Wait()或.Result,避免同步阻塞导致上下文异常。复用HttpClient实例
每次创建HttpClient是不良实践,会导致socket资源耗尽。建议将HttpClient注册为单例或静态实例复用:
private static readonly HttpClient _client = new HttpClient();
内容的提问来源于stack exchange,提问作者athskar
相关产品推荐
相关产品推荐

