C# 9+ 中的 HttpClient 空警告

Posted

技术标签:

【中文标题】C# 9+ 中的 HttpClient 空警告【英文标题】:HttpClient null warning in C# 9+ 【发布时间】:2021-12-14 10:33:10 【问题描述】:

我刚刚将 .NET3.1 应用程序迁移到 .NET6(我使用的是 VS 2022),我注意到他们引入了一些与可空类型相关的约束。我修复了所有代码以遵循最佳实践,但不确定如何解决此问题:

当创建一个新的 HttpClient 实例时,它返回一个可为空的 HttpClient 类型(代码在 Polly 重试策略中执行):

   public async Task<List<InterestedParty>> GetInterestedPartiesAsync()
    
        return await _retryPolicy.ExecuteAsync(async () =>
        
            using var client = new HttpClient()
            const string endpoint = "my-endpoint";
            var url = $"endpoint/test";

            var response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();

            var jsonString = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<List<InterestedParty>>(jsonString);
        );
    

编译器抱怨可能返回空引用。 我知道我可以使用以下命令来抑制警告:

#pragma warning disable CS8603 // Possible null reference return.

但我认为这不是最好的解决方案。

还有其他建议吗?谢谢。

【问题讨论】:

你的方法实际返回是什么?不是HttpClient,我接受。从字面上看,这个警告当然是无稽之谈——new 不会返回null。不过,我怀疑这不是警告的内容(看看所有其他的也是弯曲的)。忽略var 上的类型提示,这是另一回事。 IntelliSense 建议修复什么? 请给我们完整的代码,代码截图大多没用。此外,请确保您包含足够的上下文,以便我们可以复制它。基本上我们需要一个minimal reproducible example 尽管如此 - 你真的不应该在每个请求上都创建 HttpClient。处理 HttpClient 的正确方法是存储单个静态引用或使用 HttpClientFactory。我真的不能足够强调这是多么重要。更多详情:aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong @DragosStoica 是唯一的外部调用,但是这个调用执行了多少次?当然,您不想每次都创建一个新实例,这会影响性能,并且您可能会在此过程中遇到一些错误,因为 http 客户端不是以这种方式使用的。 【参考方案1】:

问题本身与我一开始认为的 HttpClient 无关。

方法的返回类型是 Task 并且在我返回的 using 语句中

JsonConvert.DeserializeObject&lt;List&lt;InterestedParty&gt;&gt;(jsonString); 事实上,反序列化的对象可以为 null,因此一种解决方案是在末尾添加“null forgiving”运算符 (!):

   public async Task<List<InterestedParty>> GetInterestedPartiesAsync()
    
        return await _retryPolicy.ExecuteAsync(async () =>
        
            using var client = new HttpClient();
            const string endpoint = "my-endpoint";
            var url = $"endpoint/test";

            var response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();

            var jsonString = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<List<InterestedParty>>(jsonString)!;
        );
    

另一个更好的建议是:

  public async Task<IEnumerable<InterestedParty>> GetInterestedPartiesAsync()

    return await _retryPolicy.ExecuteAsync(async () =>
    
        using var client = new HttpClient();
        const string endpoint = "my-endpoint";
        var url = $"endpoint/test";

        var response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode();

        var jsonString = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<List<InterestedParty>>(jsonString) ??
               Enumerable.Empty<InterestedParty>();
    );

感谢@JeroenMostert 和@DavidG 的建议。

【讨论】:

我认为这不是解决问题的正确方法。 Null forgiving 运算符应该很少使用,几乎从不使用 - 它不是为了解决这些问题。更好的方法是返回Task&lt;List&lt;InterestedParty&gt;?&gt; 或者,根据你的数据模型,返回?? new List&lt;InterestedParty&gt;();空集合通常比null 好,因为它们需要更少的代码来处理异常情况(当然,除非有业务需求来进行区分)。 是的,@JeroenMostert 是对的,?? new List&lt;InterestedParty&gt;() 在很多情况下更合适 @JeroenMostert 你介意添加一个答案吗?我想批准你的答案是正确的。 或者更好的是,返回IEnumerable&lt;InterestedParty&gt; 并使用?? Enumerable.Empty&lt;InterestedParty&gt;(),因为这不会创建新的列表并被缓存。【参考方案2】:

在 .csproj 中的 .NET 6 中,您可以设置可为空的 disable

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>disable</Nullable>
</PropertyGroup>

【讨论】:

以上是关于C# 9+ 中的 HttpClient 空警告的主要内容,如果未能解决你的问题,请参考以下文章

C# HttpClient 在补丁请求中返回 415 Unsupported media type

空声明中的静态结构警告无用的存储类说明符

如何将所有 C# 8 可空引用警告视为错误?

C# 中的 HttpClient 多部分表单发布

C#的未来:简化参数空值验证

C# 中的 httpClient 调用超时,而 cUrl 正在工作