In a project I have a CS8602 Dereference of a possibly null reference
warning.
Out of curiosity I changed the severity level from warning to error. Now I cannot change it back to warning, or default.
I also tried restarting VS multiple times and restoring it. How can I undo this?
CodePudding user response:
VS made an entry in the .editorconfig. Deleting it reset it to a warning level. Thanks to Jon Skeet for pointing me in the right direction.
CodePudding user response:
So I realize this isn't exactly the answer to the question that you asked--but it should help explain what's going on and possible fixes you can make:
GetService
can return null
. The compiler doesn't know that in this case the dereference of the options object and it's Value
property is safe*. So because it thinks it can be null
it's raising CS8602.
If you want the original behavior, you can ensure that this line isn't in your .editorconfig file:
dotnet_diagnostic.CS8602.severity = XXX
Similarly, there are other places where nullable warnings/errors can be configured. Rather than re-hash them here, I refer you to this QA.
If you want to keep nullable annotations and warnings enabled, you can silence this particular warning with the null suppression operator (!
):
Settings settings = serviceProvider.GetService<IOptions<Settings>>()!.Value;
There also exists a method GetRequiredService<T>
which will throw an exception if the service doesn't exist. The return value of this method is non-nullable and would therefore not trigger any warnings:
Settings settings = serviceProvider.GetRequiredService<IOptions<Settings>>().Value;
But--and a bit of a tangent here--you're doing it wrong. You should never call BuildServiceProvider
yourself. There's overhead to calling it, but more importantly the services you get won't necessarily be the same ones the application gets. There could now technically be two different instances of a singleton, including your settings object! This is such a code-smell/bad practice that in AspNetCore they've added a built-in analyzer that will yell at you for it.
The proper way to register your interface singleton in this case is to use the factory version of AddSingleton
which gives you access to the built IServiceProvider
(the one that the rest of the application will use):
builder.Services.AddSingleton<ISettings>(
sp => sp.GetRequiredService<IOptions<Settings>>().Value
);`
Now that said, AddOptions
is already called by the Azure Functions runtime. Calling Bind
the way you are is unnecessary. You should just call Configure
and pass the configuration section directly. You can retrieve your IConfiguration
object from the FunctionsHostBuilderContext
var context = builder.GetContext();
var section = context.Configuration.GetSection("YourSectionName");
builder.Services.Configure<Settings>(section);
// or if you want to bind to the root of the configuration
builder.Services.Configure<Settings>(context.Configuration);
* In fact, once you AddOptions
, any request for IOptions<>
--no matter the generic argument nor whether you've called Configure<>
for that type--will succeed.