-
Notifications
You must be signed in to change notification settings - Fork 5k
Description
Library name and version
Microsoft.Extensions.Azure 1.10.0
Describe the bug
In our application we use the Options pattern for strongly-typed config, with validation:
var options = builder.Services
.AddOptionsWithValidateOnStart<ApplicationConfig>()
.ValidateDataAnnotations()
.Bind(builder.Configuration);
We then reference it during application startup using the following code:
var config = builder.Configuration.Get<ApplicationConfig>();
We then use the AddAzureClients
method to register azure clients using the config object:
services.AddAzureClients(x =>
{
x.UseCredential(new DefaultAzureCredential());
x.AddBlobServiceClient(new Uri(config.BlobStorageUrl));
});
However, the lambda that is passed as the Action<AzureClientFactoryBuilder> configureClients
parameter is immediately invoked, and so if e.g. config.BlobStorageUrl
is null, a ArgumentNullException
will be thrown. I would normally expect this to occur after validation has happened, so that we would instead get a validation failure that the required config key is missing or invalid.
Expected behavior
Normally, when injecting clients, the configure
action is not invoked until after the StartupValidator
has run and successfully validated the config options. This is the case when normally injecting services, e.g.
services.AddDbContextFactory<ApplicationDbContext>(dbOptions =>
{
dbOptions.UseSqlServer(config.SqlDbConnectionString);
}
In that case, if a required config value were missing, we would see e.g.
Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for 'ApplicationConfig' members: 'BlobStorageUrl' with the error: 'The BlobStorageUrl field is required.'
Actual behavior
On startup, an ArgumentNullException
is thrown without reference to the specific config value that is missing:
System.ArgumentNullException: Value cannot be null. (Parameter 'uriString')
Reproduction Steps
Abbreviated Program.cs:
var builder = WebApplication.CreateBuilder(args);
var options = builder.Services
.AddOptionsWithValidateOnStart<ApplicationConfig>()
.ValidateDataAnnotations()
.Bind(builder.Configuration);
var config = builder.Configuration.Get<ApplicationConfig>();
builder.Services.AddAzureClients(x =>
{
x.AddBlobServiceClient(new Uri(config.BlobStorageUrl));
});
var app = builder.Build();
// other startup code
app.Run();
public class ApplicationConfig
{
[Required]
[ConfigurationKeyName("BlobStorageUrl")]
public required string BlobStorageUrl { get; init; }
}
appsettings.json:
{
"BlobStorageUrl": null
}
Environment
.NET SDK:
Version: 9.0.100
Commit: 59db016f11
Workload version: 9.0.100-manifests.3068a692
MSBuild version: 17.12.7+5b8665660
Runtime Environment:
OS Name: Windows
OS Version: 10.0.26100
OS Platform: Windows
RID: win-x64
Microsoft Visual Studio Enterprise 2022 (64-bit) - Current
Version 17.11.6