Today I was happily migrating some C# projects to Net 5 when I stumbled upon something unexpected. My focus was on a library (a NetStandard2.0 REST API client, an SDK) and its associated test suite. The test project was a NetCore 3.1 application.
As you can imagine, being a REST API client, the library does a lot of talking
with a remote Web Service. It does that by leveraging the almightly
System.Net.HttpClient. The library has a private, static
HttpResponseMessage parser method. Its job is, well, to parse all responses
from the remote. It looks for known, expected headers, gracefully handle them,
and then deserializes the response content, if there is any.
The test suite has one primary task: to ensure that the SDK can adequately
handle the request-response cycle. It does that by mocking
HttpMessageHandler, which is then used by the library HttpClient on every
Until this morning, all 239 tests were passing just fine. Then, I switched the
test project’s target framework moniker (TFM) to
net5.0. Suddenly, most tests
With no code changes, only a rebuild after the TFM switch, I knew I was up to something weird.
A couple of debug breakpoints later, I was back looking at my little response parser, contemplating the following, rather innocent-looking line:
if (httpResponseMessage.Content == null) return (response, token);
Its purpose is to skip deserialization if there no content in the response. I knew all the failing tests had no response content.
When the caller (the test suite in this case) is a NetCore 3.1 application, it
Content value is null, as expected.
Instead, it appears that when a NET5 application invokes the same method, the
HttpResponseMessage.Content carries an obscure
Unexpected and, more importantly, undocumented (at least to my knowledge1.)
A not-so-quick investigation revealed that, in fact, sometime during the NET5
development process, the type of
HttpResponseMessage.Content has changed from
nullable to non-nullable2.
if (httpResponseMessage.Content == null || httpResponseMessage.Content.Headers.ContentLength == 0) return response;
The double condition makes sure that no matter the calling moniker, we’ll handle it just fine.
There we go. All tests are green again.