在使用ExecutionContext.SuppressFlow()时出现异常。

5
我的WebApi客户端项目在执行HttpClient的SendAsync方法时丢失了当前用户的WindowsIdentity。
HttpContext.User返回的是应用程序池身份,而不是模拟的WindowsIdentity。
客户端项目是.net标准的,因此可以在net framework和net core中使用。
使用RestSharp时一切正常,不需要使用ExecutionContext.SuppressFlow()。(我不能使用RestSharp,因为客户端是由NSwag生成的。)
.NET Framework:
使用ExecutionContext.SuppressFlow()时,身份将正确委派给服务器。
.NET Core:
在使用.NET 7时会抛出以下异常:
无法在空上下文中调用Set方法。
异常:
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中,是否需要以不同的方式使用ExcecutionContext?

你正在使用一个完全不同的运行时环境,其构建是为了在Linux和MacOS上运行,而不仅仅是Windows。此外,你现有的Web API代码也不会在没有明确配置的情况下模拟调用者身份。 - Panagiotis Kanavos
1个回答

1

ASP.NET和ASP.NET Core有相当大的区别(.NET Framework和.NET Core也是如此)。当前实现使用WindowsIdentity.RunImpersonatedInternal,该方法具有以下特点:

ExecutionContext? currentContext = ExecutionContext.Capture();

// Run everything else inside of ExecutionContext.Run, so that any EC changes will be undone
// on the way out.
ExecutionContext.Run(currentContext, ...)

ExecutionContext.SuppressFlow(); 会将当前上下文设置为 null,这导致 InvalidOperation_NullContext(即 Cannot call Set on a null context 消息)。
看起来你需要涉及到 条件编译,即类似以下的代码(未经测试,可能需要多目标):
#if NETFRAMEWORK
    ExecutionContext.SuppressFlow();
#endif

阅读更多:

1
谢谢。条件编译似乎正常工作。 - user22464113
@user22464113很高兴能够帮助! - Guru Stron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接