question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

(string[])Request.Headers["NonExistentHeader"] is null while (IEnumerable<string>)Request.Headers["NonExistentHeader"] is not

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Consider the following code:

string value = string.Join("\n", Request.Headers["NonExistentHeader"]);

It causes the following exception in runtime at method string.Join(string separator, string[] value):

ArgumentNullException: Value cannot be null. (Parameter 'value')

For a very strange reason, the implicit cast of an empty StringValues struct to string[] type returns null:

string[] arr = default(StringValues);
Console.WriteLine("string[] is null: {0}", arr is null);  // prints 'string[] is null: True' message

While a similar cast to IEnumerable<string> returns an expected non-null value:

var seq = (IEnumerable<string>)default(StringValues);
Console.WriteLine("IEnumerable<string> is null: {0}", seq is null);  // prints 'IEnumerable<string> is null: False' message

When C# compiler compiles string.Join("\n", Request.Headers["NonExistentHeader"]) expression, it selects string.Join(string separator, string[] value) overload and this makes the expression to crash at runtime. While the project has nullable checks enabled, C# compiler is not able to catch that null reference error at compile time.

It looks like a bug because structs are never expected to be null and thus their cast operators should avoid producing null values as well, unless there is a very good reason for that.

The following approach allows to workaround the issue:

string value = string.Join("\n", (IEnumerable<string>)Request.Headers["NonExistentHeader"]);

It would be nice to have a consistent behavior here (non-null string[] is expected and preferred). But even if there is a null then C# compiler should be able to catch it at compile time.

Expected Behavior

(string[])default(StringValues) aways returns a non-null value.

Steps To Reproduce

string value = string.Join("\n", Request.Headers["NonExistentHeader"]);

Exceptions (if any)

ArgumentNullException: Value cannot be null. (Parameter ‘value’) at string.Join(string separator, string[] value)

.NET Version

6.0.401

Anything else?

Server: Kestrel

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:24 (14 by maintainers)

github_iconTop GitHub Comments

3reactions
halter73commented, Jan 20, 2023
1reaction
eerhardtcommented, Oct 12, 2022

I’m not sure this suggestion is inline with the original design of StringValues. Reading https://github.com/aspnet/Announcements/issues/60, it says:

The value is implicitly convertable to and from string and string[]

Changing the implicit conversion to string[] is going to lose the “nullness” of it. Take the following code as an example:

string? a = null;
StringValues values = a;

string? b = values;
Console.WriteLine(b is null); // prints 'true'

string?[]? aArray = null;
values = aArray;

string?[]? bArray = values;
Console.WriteLine(bArray is null); // prints 'true' today, but with this change will print 'false'

This seems pretty inconsistent to be implicitly convertible to and from a Type, but lose information when you do.

To back up this point, see https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads

❌ DO NOT provide an implicit conversion operator if the conversion is potentially lossy.

For example, there should not be an implicit conversion from Double to Int32 because Double has a wider range than Int32. An explicit conversion operator can be provided even if the conversion is potentially lossy.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unable to check null for header value in request
It has a method TryGetValues which can be used to safely retrieve the values of a header. String header = null; IEnumerable<String> headerValues ......
Read more >
Use empty string, null or remove empty property in API ...
TLDR; Remove null properties. The first thing to bear in mind is that applications at their edges are not object-oriented (nor functional if ......
Read more >
Use empty string, null or remove empty property in API ...
With some framework, completely removing a property from the result only in some cases can be difficult, if not impossible. On the other...
Read more >
String.IsNullOrEmpty(String) Method (System)
The following example examines three strings and determines whether each string has a value, is an empty string, or is null .
Read more >
and ??= operators - null-coalescing operators
The `??` and `??=` operators are the C# null-coalescing operators. They return the value of the left-hand operand if it isn't null.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found