C# .NET core 3.1中的HttpResponseMessage.Content出现意外的空行为
我正在编写一段代码,它基本上是.NET core 3.1类库中的一个API客户端 我正在使用Visual Studio 2019企业版16.5.5 我启用了可为null的引用类型特性,以便在VisualStudio中享受针对null的编译器警告。这是我的类库项目的csproj:C# .NET core 3.1中的HttpResponseMessage.Content出现意外的空行为,c#,.net-core,dotnet-httpclient,c#-8.0,nullable-reference-types,C#,.net Core,Dotnet Httpclient,C# 8.0,Nullable Reference Types,我正在编写一段代码,它基本上是.NET core 3.1类库中的一个API客户端 我正在使用Visual Studio 2019企业版16.5.5 我启用了可为null的引用类型特性,以便在VisualStudio中享受针对null的编译器警告。这是我的类库项目的csproj: <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</T
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Flurl" Version="2.8.2" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Text.Json" Version="4.7.2" />
</ItemGroup>
</Project>
通过检查所涉及对象的类型注释和visual studio intellisense,我可以了解到我要取消引用的对象中没有一个是null
(visual studio intellisense表示“此处内容不为null”,“此处标题不为null”等等…)
一个简单的检查。通过检查代码,似乎允许将null
值设置为属性,但是当调用getter时,通过??=
操作符将基础字段更改为new EmptyContent()
因此,根据我的理解,根据属性类型(即不可为null的引用类型HttpContent
)和visual studio intellisense,此属性的getter从不返回null。到目前为止,一切顺利
几天前,我写了一段类似的代码,我们的一位客户有一个微妙的错误。由于请求查询字符串很长,被调用的端点返回的414URI太长
响应没有响应内容。在这种情况下,为了检测响应mime类型而取消引用Content
属性会导致NullReferenceException
。这发生在.NETCore2.2类库中
为了避免两次犯同样的错误,我为我全新的.NET core 3.1代码添加了一个单元测试,其中我对调用的API使用了一个模拟,配置方式如下(为了重现之前的场景):
\u messageHandlerMock
.Protected()
.设置(
“SendAsync”,
ItExpr.IsAny(),
ItExpr.IsAny()
)
.Returns(异步()=>
{
等待任务。延迟(2)。配置等待(false);
返回新的HttpResponseMessage
{
StatusCode=HttpStatusCode.RequestUriTooLong,
内容=空
};
});
由于response.Content.Headers
的值为null,因此在取消引用response.Content
时,测试失败并引发null引用异常
由于visual studio intellisense建议、Content
属性的不可空引用类型以及上面链接的HttpResponseMessage
类的源代码,这对我来说是出乎意料的
我遗漏了什么?您正在查看的代码仅在8天前提交。以下是您可能使用的版本:
正如您所看到的,它返回的内容没有空检查
3天前推出了一个更新版本,现在可能会使用此代码,但我不确定。我建议您更新或更改代码,使其不将内容设置为空。您正在查看的代码仅在8天前提交。以下是您可能使用的版本:
正如您所看到的,它返回的内容没有空检查
3天前推出了一个更新版本,现在可能会使用此代码,但我不确定。我建议您更新或更改代码,使其不将内容设置为null。您确定您的模拟(以及ReturnsAsync中的回调)正在使用吗?我似乎还记得几个月前我在模拟同一个受保护的方法时遇到的一个非常类似的问题,当时该方法没有被调用。不记得问题最终是什么,也不记得我是如何解决的。@pinkfloydx33我确信模拟软件确实被使用过。如果您需要一些代码示例来模拟HTTP客户机,请遵循本指南。我发现它很有用,我们总是在这种单元测试中使用这种方法。你确定你的mock(以及ReturnsAsync中的回调)正在使用吗?我似乎还记得几个月前我在模拟同一个受保护的方法时遇到的一个非常类似的问题,当时该方法没有被调用。不记得问题最终是什么,也不记得我是如何解决的。@pinkfloydx33我确信模拟软件确实被使用过。如果您需要一些代码示例来模拟HTTP客户机,请遵循本指南。我发现它很有用,我们总是使用这种方法进行此类单元测试。非常感谢。我被VisualStudioIntelliSense关于可空性的建议愚弄了。出于某种奇怪的原因,它似乎在最新版本的代码中使用了类型注释。非常感谢。我被VisualStudioIntelliSense关于可空性的建议愚弄了。出于某种奇怪的原因,它似乎对最新版本的代码使用了类型注释。
var responseMediaType = response.Content.Headers.ContentType.MediaType;
_messageHandlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.Returns(async () =>
{
await Task.Delay(2).ConfigureAwait(false);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.RequestUriTooLong,
Content = null
};
});