You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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捕获。

解决方案

  1. 启用Task友好的同步上下文
    在web.config的<appSettings>节点中添加配置,让ASP.NET使用现代的AspNetSynchronizationContext:
<appSettings>
  <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>

该配置从.NET 4.5开始支持,4.7.2完全兼容,能解决绝大多数异步上下文相关的异常。

  1. 避免异步代码中混用同步阻塞
    代码中response.Content.ReadAsStringAsync().Result使用了同步阻塞的.Result,这会破坏异步流程,甚至引发死锁。改为异步等待:
var contents = await response.Content.ReadAsStringAsync();
  1. 保持异步调用链完整
    确保调用SendPostRequestAsync的上游代码也是异步等待,不要使用.Wait()或.Result,避免同步阻塞导致上下文异常。

  2. 复用HttpClient实例
    每次创建HttpClient是不良实践,会导致socket资源耗尽。建议将HttpClient注册为单例或静态实例复用:

private static readonly HttpClient _client = new HttpClient();

内容的提问来源于stack exchange,提问作者athskar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:54:57