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

.NET 7中使用ExecutionContext.SuppressFlow()抛出异常问题咨询

问题描述

我的WebApi客户端项目调用HttpClient.SendAsync时,当前用户的WindowsIdentity会丢失,HttpContext.User返回应用池标识而非模拟的WindowsIdentity。项目基于.NET Standard,兼容.NET Framework和.NET Core。用RestSharp时无需ExecutionContext.SuppressFlow()就能正常运行,但客户端由NSwag生成,没法改用RestSharp。

在.NET Framework中,用ExecutionContext.SuppressFlow()可以把Identity正确委派到服务器;但在.NET 7中会抛出异常:

Cannot call Set on a null context

异常调用栈:

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Security.Principal.WindowsIdentity.RunImpersonatedInternal(SafeAccessTokenHandle token, Action action)
at System.Security.Principal.WindowsIdentity.GetName()
at System.Net.Http.CurrentUserIdentityProvider.GetIdentity()
at System.Net.Http.HttpConnectionPoolManager.GetConnectionKey(HttpRequestMessage request, Uri proxyUri, Boolean isProxyConnect)
at System.Net.Http.HttpConnectionPoolManager.SendAsyncCore(HttpRequestMessage request, Uri proxyUri, Boolean async, Boolean doRequestAuth, Boolean isProxyConnect, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPoolManager.SendAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.HttpAuthenticatedConnectionHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageHandlerStage.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()
at System.Net.Http.HttpClient.<<SendAsync>g__Core|83_0>d.MoveNext()

最小复现代码片段:

UriBuilder uriBuilder = new()
{
    Scheme = Uri.UriSchemeHttps,
    Host = "localhost",
    Port = 7042
};

var urlBuilder = new StringBuilder();
urlBuilder.Append(uriBuilder.ToString() + "/WeatherForecast");

HttpClientHandler handler = new()
{
    UseDefaultCredentials = true,
    PreAuthenticate = true
};
         
HttpClient client = new(handler);
using var request = new HttpRequestMessage();
request.Method = new HttpMethod("GET");
var url = urlBuilder.ToString();
request.RequestUri = new Uri(url, UriKind.RelativeOrAbsolute);

ExecutionContext.SuppressFlow();
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);

请问在.NET Core中是否需要以不同方式使用ExecutionContext?

解决方案

在.NET Core/.NET 5+中,ExecutionContext的处理逻辑和.NET Framework有差异,直接调用ExecutionContext.SuppressFlow()会导致上下文为空的异常,因为.NET Core中ExecutionContext的流动控制更严格。针对Windows身份委派的问题,推荐以下两种处理方式:

方式一:安全包裹ExecutionContext.SuppressFlow()

调用SuppressFlow()前先检查当前是否有可流动的上下文,并用try/finally确保恢复流动状态,避免上下文泄漏:

bool flowSuppressed = false;
try
{
    if (!ExecutionContext.IsFlowSuppressed())
    {
        ExecutionContext.SuppressFlow();
        flowSuppressed = true;
    }
    var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
}
finally
{
    if (flowSuppressed)
    {
        ExecutionContext.RestoreFlow();
    }
}

方式二:自定义HttpMessageHandler处理身份委派

创建自定义DelegatingHandler,在发送请求时显式传递当前模拟的WindowsIdentity,绕过ExecutionContext的流动限制:

public class ImpersonationHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var currentIdentity = WindowsIdentity.GetCurrent();
        if (currentIdentity != null && currentIdentity.ImpersonationLevel != TokenImpersonationLevel.None)
        {
            using (currentIdentity.Impersonate())
            {
                return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
            }
        }
        return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
    }
}

使用时将该handler添加到HttpClient管道:

HttpClientHandler handler = new()
{
    UseDefaultCredentials = true,
    PreAuthenticate = true
};
var client = new HttpClient(new ImpersonationHandler { InnerHandler = handler });

关键说明

  • .NET Core中HttpClient的连接池机制会复用连接,ExecutionContext的流动会干扰连接池的身份关联,这是直接调用SuppressFlow()报错的核心原因。
  • NSwag生成的客户端可通过配置自定义HttpMessageHandler集成上述方案,无需修改生成的客户端代码,只需在初始化客户端时传入自定义handler即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:57:54