对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效

Posted

技术标签:

【中文标题】对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效【英文标题】:Using RunImpersonated for an HttpClient call fails for a NUnit test, but works in Console 【发布时间】:2020-11-18 23:02:08 【问题描述】:

我需要让我的测试作为测试帐户运行。为此,我设置了以下代码以在我的测试帐户中创建一个句柄:

SafeAccessTokenHandle testAccountHandle;

bool returnValue = LogonUser("TestAccount", "myDom.net", 
       "pass", 2, 0, out testAccountHandle);

然后我可以调用加载 URL:

HttpResponseMessage response = null;

await WindowsIdentity.RunImpersonated<Task>(testAccountHandle, async () =>

    var url = "https://accounts.google.com/.well-known/openid-configuration";
    response = await httpClient.GetAsync(url);
);
testAccountHandle.Dispose();

当我在控制台应用程序中运行它时,它工作得很好。 (在 LinqPad 中也是如此。)

但是,当我在 NUnit 测试中运行此代码时,我收到以下错误:

System.Net.Sockets.SocketException :这通常是主机名解析期间的临时错误,意味着本地服务器没有收到来自权威服务器的响应。

它说这通常是一个临时错误,但每次我在 NUnit 测试中模拟运行时都会发生这种情况,而在控制台中运行时则不会。如果我没有模拟运行,当我在 NUnit 测试中运行时,它也永远不会发生。 (简而言之,它只发生在 NUnit 测试和模拟中。)

我不确定如何进行调试。很明显 NUnit 不喜欢我的模仿,但我不知道该怎么办。

如何在 NUnit 测试中使用 RunImpersonated 时成功调用 HttpClient.GetAsync

注意:完整的复制代码可以在这里找到:https://github.com/nunit/nunit/issues/3672

【问题讨论】:

如果您以测试用户身份登录并打开浏览器,您可以成功访问该网址还是出现错误?以测试用户身份在 accounts.google.com 上运行 nslookup 怎么样?我只是想确认你的网络配置没有问题 @kylejrp - 以测试用户身份登录时,我可以正常访问 URL。此外,它在未在 NUnit 测试中运行时运行良好(但仍以测试用户身份在代码中运行)。 这可能与您声明httpClient 的上下文有关吗?看起来您声明它超出了RunImpersonated 的范围,我想知道这是否会影响HttpClient 使用的用户。这是在黑暗中拍摄,但如果您在模拟范围内声明 httpClient 会怎样? @kylejrp - 听起来很有希望,但我刚刚尝试过,但仍然失败。 @kylejrp - 我在 NUnit GitHub 网站上发布了这个:github.com/nunit/nunit/issues/3672 如果你有兴趣,我在那里发布了一个完整的复制品。 【参考方案1】:

这似乎是 .NET Core 的一个错误。在此处查看未解决的问题和讨论:https://github.com/dotnet/runtime/issues/29935

与 .NET Framework 相比,WindowsIdentity.RunImpersonated() 在 .NET Core 中的工作方式似乎有所不同。这会导致各种问题,包括影响 ASP.NET Core 的问题 #29351。

在模拟令牌上设置身份令牌权限的方式有所不同。这会以多种方式导致“拒绝访问”问题。

解决方法

Issue #29351 from ASP.NET Core 引用此确切的错误消息并包含解决方法。将环境变量 DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER 设置为 0 会禁用 SocketsHttpHandler 并使这个问题消失。例如,以下工作没有错误:

Environment.SetEnvironmentVariable("DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER", "0");
HttpResponseMessage response = null;

await WindowsIdentity.RunImpersonated<Task>(testAccountHandle, async () =>

    var url = "https://accounts.google.com/.well-known/openid-configuration";
    response = await httpClient.GetAsync(url);
);

您可能需要考虑仅为此特定测试设置此环境变量,而不是为每个测试设置此环境变量。我不确定禁用 SocketsHttpHandler 的影响是什么,因此使用该解决方法需要您自担风险。

【讨论】:

感谢您的回答!我接受这个作为答案,但我会补充(对于未来的读者)这个设置在 .Net 5.0 中被删除了。因此,此解决方法仅适用于 .Net Core。

以上是关于对 NUnit 测试使用 RunImpersonated 进行 HttpClient 调用失败,但在控制台中有效的主要内容,如果未能解决你的问题,请参考以下文章

Nunit测试工具使用实例

无法将 ReactiveUI 添加到 NUnit 测试项目

Rider NUnit 测试问题:程序不包含 main

NUnit - 读写文件的程序集

如何 File.Exists 在 Nunit 测试中

使用参数并行运行 nunit 测试 (nunit 3.8.x)