C# HttpClient 和 Windows 身份验证:无法访问已关闭的流

C# HttpClient and Windows Authentication: Cannot access a closed Stream

我正在使用带有处理程序的本机 C# HTTP 客户端来处理 Windows 身份验证,并且我有 ObjectDisposedException

using (var httpClientHandler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
{
    bool disposeHandler = true; //Setting true or false does not fix the problem
    using (var httpClient = new HttpClient(httpClientHandler, disposeHandler))
    {
        using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes("Hello")))
        {
            // Commenting/uncommenting the line below does not fix the problem
            // httpRequestMessage.Headers.Connection.Add("Keep-Alive");

            using (var httpResponseMessage = await httpClient.PostAsync("http://SomeUrl", content)) // This line throws an ObjectDisposedException
            {

            }
        }
    }
}

有什么想法吗?

您是否尝试过设置 PreAuthenticate = true,它将使用 AD/User 令牌添加授权 header,您应该得到一个 401,然后是第二个请求,带有 header ,建议在fiddler中查看。

httpClientHandler.PreAuthenticate = true;

经过一些新的调查,我 think/fear 在 HttpClientHandler(或 HttpClient):

中有一个 Microsoft 错误

如果我不使用 PostAsync 方法而是使用 SendAsync 方法,我可以用更多选项编写我的请求,尤其是将 HTTP 版本1.1(默认情况下)到 1.0。然后在这种情况下,真正的异常被揭示了(并且它不再是 hidden/overridden 由 ObjectDisposedException 异常)。供您参考,我真正的例外情况如下:

--> System.Net.WebException: 远程服务器返回错误: (401) Unauthorized.

--> System.ComponentModel.Win32Exception: 目标主体名称不正确

(仅供参考,此异常是由于 Active Directory 中用户的 SPN 配置错误所致)

using (var httpClientHandler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
{
    bool disposeHandler = true; //Setting true or false does not fix the problem
    using (var httpClient = new HttpClient(httpClientHandler, disposeHandler))
    {
        using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes("Hello")))
        {
            // Commenting/uncommenting the line below does not fix the problem
            // httpRequestMessage.Headers.Connection.Add("Keep-Alive");

            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://SomeUrl")
            {
                Content = content,
                Version = HttpVersion.Version10
            };

            using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) // This line still throws but with the real exception (and not the ObjectDisposedException)
            {

            }
        }
    }
}

注意:降级 HTTP 版本只是为了获取真正的异常消息而进行的黑客攻击,HTTP 1.0 已经很老了。

如有专家分析,将不胜感激。希望这会对其他人有所帮助。

您在 HttpResponseMessage 有机会进行评估之前就将其处理掉了。试试这个。

HttpResponseMessage httpResponseMessage = null;
using (var content = new ByteArrayContent(Encoding.UTF8.GetBytes("Hello")))
{
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://SomeUrl")
    {
        Content = content,
        Version = HttpVersion.Version10
    };

    using (var httpClient = new HttpClient(httpClientHandler, disposeHandler))
    {
        httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
    }
}