I'm writing a piece of code which is basically an API client inside a .NET core 3.1 class library.
I'm using Visual Studio 2019 enterprise version 16.5.5.
I have enabled the nullable reference type feature, in order to enjoy the compiler warnings for nulls in Visual Studio. This is the csproj of my class library project:
<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>
In my code I want to ensure that the response content type is actually application/json
, which is the expected reuturn type from my API:
var responseMediaType = response.Content.Headers.ContentType.MediaType;
By checking the type annotations of the involved objects and the visual studio intellisense I can read that none of the objects I'm dereferencing is expected to be null
(the visual studio intellisense says that 'Content is not null here', 'Headers is not null here' and so on...).
A simple check to the .NET core github repository seems to confirm that calling the getter for property Content
of class HttpResponseMessage
never returns null
. By checking the code, it seems that setting a null
value to the property is allowed, but when the getter is invoked the underlying field is changed to new EmptyContent()
by means of the ??=
operator.
So, based on my understanding, the getter for this property never returns null, according to the property type (which is the non nullable reference type HttpContent
) and the visual studio intellisense. So far, so good.
Some times ago I wrote a similar piece of code and we had a subtle bug with one of our customers. Due to a very long request query string the called endpoint returned a 414 URI too long
response having no response content. In that case, dereferencing the Content
property in order to detect the response mime type caused a NullReferenceException
. This happened with a .NET core 2.2 class library.
In order to avoid making the same mistake twice, I have added a unit test for my brand new .NET core 3.1 code where I use a mock for the called API, configured this way (in order to reproduce the same scenario that bit me previously):
_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
};
});
The test fails with a NullReferenceException
raised when response.Content.Headers
is dereferenced, because the value of response.Content
is null
.
This is unexpected to me, due to the visual studio intellisense suggestions, the non nullable reference type of Content
property and the source code of the HttpResponseMessage
class linked above.
What am I missing ?
The code you're looking at was only commited 8 days ago. Here is the version you're likely using:
As you can see it returns content without a null check.
There was an updated pushed out 3 days ago which may now use this code I'm unsure however. I would recommend updating or else changing your code to not set content to null.