MetallixBrother
MetallixBrother
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
Thank you, much appreciated. The "optional" path seems to have done the trick (no idea how I missed that before). Thanks again for your assistance!
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
Regarding reading the configuration directly, and having to manually parse string values into Uris - I'm confused as to why this is not an antipattern, but retrieving only the pertinent details and parsing it once is an antipattern.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
I don't believe that's strictly true - in that method, I'm adding options classes using the Option pattern. Then in AddAzureAppConfiguration, I'm parsing the configuration to get the relevant configuration details.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
In my defence, I was following the guidelines provided by Microsoft: https://learn.microsoft.com/en-us/dotnet/core/extensions/options#options-validation
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
I'm afraid that I'm a bit lost as to what you mean here; what is the purpose of configuration if not to read it?
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
I'll give that a go shortly, thank you for looking into this
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
https://github.com/ntyrrell/azure-app-config-problem I've set up a very basic implementation as suggested. Thank you for the suggestion, I hope that this will make things clearer.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
I can try to create a cloneable repo, but I would need to pare it down significantly as this is software being developed for work. I had looked at PostConfigure, but I think that it still encounters the same problems as previously mentioned.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
ServiceCollectionExtensions.cs
internal static class ServiceCollectionExtensions
{
[ExcludeFromCodeCoverage]
public static IServiceCollection AddWorkerOptions(this IServiceCollection services)
{
services
.AddOptionsWithValidateOnStart<AppConfigOptions>()
.BindConfiguration(AppConfigOptions.ConfigurationSectionName)
.ValidateDataAnnotations();

// code omitted

return services;
}
// code omitted
}
internal static class ServiceCollectionExtensions
{
[ExcludeFromCodeCoverage]
public static IServiceCollection AddWorkerOptions(this IServiceCollection services)
{
services
.AddOptionsWithValidateOnStart<AppConfigOptions>()
.BindConfiguration(AppConfigOptions.ConfigurationSectionName)
.ValidateDataAnnotations();

// code omitted

return services;
}
// code omitted
}
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
Apologies, I'll add that shortly, but it's using the validation methodology provided by Microsoft for the options pattern.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
I tried that. Part of the problem is that the options class is structured. If I set AppConfig:Endpoint to null using an in memory collection, you'll hit the problem mentioned in the first bullet point (i.e. it will skip trying to do Azure App Configuration, but fail validation). Right now there is validation on the option class, which will pass either if the instance is specified (non-null) and Endpoint is also non-null, or if there is no instance of AppConfigOptions.
78 replies
CC#
Created by MetallixBrother on 1/7/2025 in #help
✅ Overriding IConfigurationManager.GetSection for integration tests in .NET 8 Minimal API
Program.cs
var builder = WebApplication.CreateBuilder(args);
// code omitted
builder.Configuration.AddAzureAppConfiguration();

builder.Services.AddWorkerOptions();
// code omitted
await app.RunAsync();
var builder = WebApplication.CreateBuilder(args);
// code omitted
builder.Configuration.AddAzureAppConfiguration();

builder.Services.AddWorkerOptions();
// code omitted
await app.RunAsync();
AppConfigOptions.cs
public sealed class AppConfigOptions
{
public const string ConfigurationSectionName = "AppConfig";

[Required]
public required Uri Endpoint { get; init; }
}
public sealed class AppConfigOptions
{
public const string ConfigurationSectionName = "AppConfig";

[Required]
public required Uri Endpoint { get; init; }
}
ConfigurationManagerExtensions.cs
internal static class ConfigurationManagerExtensions
{
public static IConfigurationManager AddAzureAppConfiguration(this IConfigurationManager builder)
{
var appConfig = builder.GetSection(AppConfigOptions.ConfigurationSectionName).Get<AppConfigOptions>();

if (appConfig?.Endpoint is null)
{
return builder;
}

var appConfigUri = appConfig.Endpoint;

if (appConfigUri.IsAbsoluteUri && (appConfigUri.IsHttp() || appConfigUri.IsHttps()))
{
var credentials = new DefaultAzureCredential();

builder.AddAzureAppConfiguration(SetupAzureAppConfiguration(appConfigUri, credentials));
}

return builder;
}

[ExcludeFromCodeCoverage]
private static Action<AzureAppConfigurationOptions> SetupAzureAppConfiguration(Uri appConfigEndpoint, Azure.Core.TokenCredential credential) => options =>
{
options.Connect(appConfigEndpoint, credential)
.UseFeatureFlags()
.ConfigureKeyVault(keyVaultOptions =>
{
keyVaultOptions.SetCredential(credential);
});
};
}
internal static class ConfigurationManagerExtensions
{
public static IConfigurationManager AddAzureAppConfiguration(this IConfigurationManager builder)
{
var appConfig = builder.GetSection(AppConfigOptions.ConfigurationSectionName).Get<AppConfigOptions>();

if (appConfig?.Endpoint is null)
{
return builder;
}

var appConfigUri = appConfig.Endpoint;

if (appConfigUri.IsAbsoluteUri && (appConfigUri.IsHttp() || appConfigUri.IsHttps()))
{
var credentials = new DefaultAzureCredential();

builder.AddAzureAppConfiguration(SetupAzureAppConfiguration(appConfigUri, credentials));
}

return builder;
}

[ExcludeFromCodeCoverage]
private static Action<AzureAppConfigurationOptions> SetupAzureAppConfiguration(Uri appConfigEndpoint, Azure.Core.TokenCredential credential) => options =>
{
options.Connect(appConfigEndpoint, credential)
.UseFeatureFlags()
.ConfigureKeyVault(keyVaultOptions =>
{
keyVaultOptions.SetCredential(credential);
});
};
}
78 replies