Skip to content

What is the correct way to use Dictionary with FormUrlEncodedContent in .NET 5 without compiler warnings? #38494

@martincostello

Description

@martincostello

As part of updating some OAuth provider libraries to target .NET 5 using preview 6 (see aspnet-contrib/AspNet.Security.OAuth.Providers#438), I've come across an issue with new nullable annotations I'm not sure of how to resolve correctly.

The FormUrlEncodedContent type has been updated to add nullable annotations (see #33268) and now the constructor takes an IEnumerable<KeyValuePair<string?, string?>>.

A common existing pattern to populate the values for an instance of FormUrlEncodedContent was to use a Dictionary<string, string>, but that now generates an CS8620 warning.

However simply changing the dictionary to use string? then generates CS8714 because the key cannot be null.

It's possible to fix the warning by casting the dictionary to IEnumerable<KeyValuePair<string?, string?>>, but then Visual Studio suggests the cast is redundant and can be removed.

The redundant cast and warnings can be eliminated by using a list or array of KeyValuePair<string?, string?>, but that's much more verbose.

Below is a simple program that demonstrates different approaches I took to try and fix the warning.

using System.Collections.Generic;
using System.Net.Http;

#nullable enable

namespace FormUrlEncodedContentNullable
{
    class Program
    {
        static void Main()
        {
            var dictionary = new Dictionary<string, string>
            {
                ["foo"] = "bar"
            };

            _ = new FormUrlEncodedContent(dictionary); // CS8620
            _ = new FormUrlEncodedContent((IEnumerable<KeyValuePair<string?, string?>>)dictionary); // OK, but says cast is redundant

            var nullableValueDictionary = new Dictionary<string, string?>
            {
                ["foo"] = "bar"
            };

            _ = new FormUrlEncodedContent(nullableValueDictionary); // CS8620

            var nullableDictionary = new Dictionary<string?, string?> // CS8714
            {
                ["foo"] = "bar"
            };

            _ = new FormUrlEncodedContent(nullableDictionary);

            var listOfKvps = new List<KeyValuePair<string?, string?>>
            {
                new KeyValuePair<string?, string?>("foo", "bar")
            };

            _ = new FormUrlEncodedContent(listOfKvps); // OK, but verbose

            var arrayOfKvps = new[]
            {
                new KeyValuePair<string?, string?>("foo", "bar")
            };

            _ = new FormUrlEncodedContent(arrayOfKvps); // OK, but verbose
        }
    }
}

For now I've settled with the cast, but none of the above approaches seem correct to me.

What is the "correct" fix for this code pattern for .NET 5 when nullable is in use? It doesn't seem to be resolvable without suppressing warnings or making the code a lot more verbose that it was before.

Metadata

Metadata

Assignees

Labels

api-needs-workAPI needs work before it is approved, it is NOT ready for implementationarea-System.Net.Http

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions