状态码不成功时无法读取HttpResponseMessage内容

Max*_*ini 6 c# dotnet-httpclient .net-core

我有一个使用 SMS REST API 的服务HttpClient

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    try
    {
        _ = response.EnsureSuccessStatusCode();
    }
    catch (HttpRequestException)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

API 返回错误,但我希望能够记录它。因此,我需要记录失败的状态代码(我可以从中读取response.StatusCode)和相关内容(其中可能包含其他有用的错误详细信息)。

此代码在await response.Content.ReadAsStringAsync()此异常的指令上失败:

System.ObjectDisposedException:无法访问已处理的对象。
对象名称:'System.Net.Http.HttpConnection+HttpConnectionResponseContent'。
    模块“System.Net.Http.HttpContent”,在 CheckDisposed
    模块“System.Net.Http.HttpContent”,在 ReadAsStringAsync

一些消息来源建议,当状态码不在成功范围(200-299)内时,您不应读取响应内容,但如果响应确实包含有用的错误详细信息呢?

使用的 .NET 版本:AWS lambda linux 运行时上的 .NET Core 2.1.12。

Max*_*ini 6

好的,显然这是.NET API 中的一个已知问题,已在 .NET Core 3.0 中解决。response.EnsureSuccessStatusCode()实际上是在处理响应内容。它以这种方式实现,据称可以帮助用户:

// 处理内容应该对用户有所帮助:如果用户调用EnsureSuccessStatusCode(),
// 如果响应状态代码为!= 2xx ,则抛出异常。即行为类似于失败的请求(例如
// 连接失败)。在这种情况下,用户不希望处理内容:如果
// 抛出异常,则对象负责清理其状态。

这是从 3.0 中删除的不良行为。与此同时,我只是切换到使用IsSuccessStatusCode之前的日志:

HttpClient http = this._httpClientFactory.CreateClient();
// Skipped: setup HttpRequestMessage
using (HttpResponseMessage response = await http.SendAsync(request))
{
    if (!response.IsSuccessStatusCode)
    {
        string responseString = await response.Content.ReadAsStringAsync(); // Fails with ObjectDisposedException
        this._logger.LogInformation(
            "Received invalid HTTP response status '{0}' from SMS API. Response content was {1}.",
            (int)response.StatusCode,
            responseString
        );
        _ = response.EnsureSuccessStatusCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

有点多余,但它应该可以工作。