13
votes

MS states Express your design intent more clearly with nullable and non-nullable reference types.

My intent is to express, that properties Issuer and Audience in my JwtOptions are never null. Which is very reasonable intent for consumers of these options, is not? These not null values are ensured by Asp.Net Core validation described below.

But if JwtOptions has not all properties initialized by the constructor, so C# 8 compiler reports

Warning CS8618 Non-nullable property 'Issuer' is uninitialized.

And for some technical reasons, Asp.Net Core options cannot have a constructor with parameters. So I am stuck with my intent. I can switch nullable checking off or declare Issuer and other properties nullable, but I think this is not the best solution.

Is there any elegant solution in this case?

Snippet from csproj:

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  <LangVersion>8.0</LangVersion>
  <Nullable>enable</Nullable>
</PropertyGroup>

I have these strongly typed options in Asp.Net Core application:

public class JwtOptions
{
    [Required]
    public string Issuer { get; set; }

    [Required]
    public string Audience { get; set; }

}

Options are configured by a next code in Startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddOptions<JwtOptions>()
            .Bind(Configuration.GetSection("JwtOption"))
            .ValidateDataAnnotations();
    }

and consumed by HomeController:

    public HomeController(IOptions<JwtOptions> options)
    {
        string audience = options.Value.Audience;
        string issuer = options.Value.Issuer;
    }

As you can see, nor Audience nor Issuer cannot be null for the consumer. Make these properties nullable makes no sense.

1

1 Answers

15
votes

As far as the compiler knows, it has not been initialized and can be null. Use the !(null-forgiving operator) as a last resort (and leave a comment explaining why you used !.

// This should be set by the options binding
public string Issuer { get; set; } = null!;