NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Friday, 27 September 2024
//Less than a minute
Det verkar som om alla har en version av denna kod, Jag kom först över denna strategi från Filip W Ordförande och nyligen har min gamla kollega Phil Haack hans version.
Bara för att slutföra så här gör jag det.
Varför är att göra det lättare att arbeta med konfiguration. Just nu är det bästa sättet att använda IOptions<T>
och IOptionsSnapshot<T>
Men det här är lite jobbigt att jobba med. Detta tillvägagångssätt gör att du kan arbeta med konfigurationen på ett mer naturligt sätt.
Begränsningarna är att du inte kan använda IOptions<T>
mönster, så att du inte får möjlighet att ladda om konfigurationen utan att starta om programmet. Men ärligt talat är detta något jag nästan aldrig vill göra.
I min version använder jag den senaste statiska Interface medlemmar för att ange att alla fall av denna klass måste deklarera en Section
egendom. Detta används för att få avsnittet från konfigurationen.
public interface IConfigSection {
public static abstract string Section { get; }
}
Så för varje genomförande du sedan ange vilken avsnitt detta ska vara bunden till:
public class NewsletterConfig : IConfigSection
{
public static string Section => "Newsletter";
public string SchedulerServiceUrl { get; set; } = string.Empty;
public string AppHostUrl { get; set; } = string.Empty;
}
I det här fallet letar den efter ett avsnitt i konfigurationen som heter Newsletter
.
"Newsletter": {
"SchedulerServiceUrl" : "http://localhost:5000",
"AppHostUrl" : "https://localhost:7240"
}
Vi kommer då att kunna binda detta i Program.cs
Filen så här:
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
services.ConfigurePOCO<NewsletterConfig>(config);
Vi kan också få värdet av konfigurationen i Program.cs
Filen så här:
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(config);
Eller till och med för WebApplicationBuilder
så här:
var newsletterConfig = builder.Configure<NewsletterConfig>();
Observera: Eftersom byggherren har tillgång till ConfigurationManager
Den behöver inte passera in.
Vilket innebär att du nu har alternativ om hur man binder konfiguration.
En annan fördel är att om du behöver använda dessa värden senare i din Program.cs
filen då objektet är tillgänglig för dig.
För att möjliggöra allt detta har vi en ganska enkel förlängningsmetod som gör arbetet med att binda konfigurationen till klassen.
Koden nedan tillåter följande:
// These get the values and bind them to the class while adding these to Singleton Scope
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(config);
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(configuration.GetSection(NewsletterConfig.Section));
// Or for Builder...These obviously only work for ASP.NET Core applications, take them out if you are using this in a different context.
var newsletterConfig = builder.Configure<NewsletterConfig>();
var newsletterConfig = builder.Configure<NewsletterConfig>(NewsletterConfig.Section);
// These just return a dictionary, which can be useful to get all the values in a section
var newsletterConfig = builder.GetConfigSection<NewsletterConfig>();
Allt detta är aktiverat genom följande utökningsklass.
Du kan se att huvudimpulsen för detta är att använda det statiska gränssnittet medlemmar för att ange sektionsnamnet. Detta används sedan för att få avsnittet från konfigurationen.
namespace Mostlylucid.Shared.Config;
public static class ConfigExtensions {
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfigurationSection configuration)
where TConfig : class, new() {
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, ConfigurationManager configuration)
where TConfig : class, IConfigSection, new()
{
var sectionName = TConfig.Section;
var section = configuration.GetSection(sectionName);
return services.ConfigurePOCO<TConfig>(section);
}
public static TConfig Configure<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var services = builder.Services;
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
return services.ConfigurePOCO<TConfig>(configuration.GetSection(sectionName));
}
public static TConfig GetConfig<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
var section = configuration.GetSection(sectionName).Get<TConfig>();
return section;
}
public static Dictionary<string, object> GetConfigSection(this IConfiguration configuration, string sectionName) {
var section = configuration.GetSection(sectionName);
var result = new Dictionary<string, object>();
foreach (var child in section.GetChildren()) {
var key = child.Key;
var value = child.Value;
result.Add(key, value);
}
return result;
}
public static Dictionary<string, object> GetConfigSection<TConfig>(this WebApplicationBuilder builder)
where TConfig : class, IConfigSection, new() {
var configuration = builder.Configuration;
var sectionName = TConfig.Section;
return configuration.GetConfigSection(sectionName);
}
}
Att använda dessa är ganska enkelt. I alla klasser där du behöver denna konfiguration kan du helt enkelt injicera den så här:
public class NewsletterService(NewsletterConfig config {
}
Tja det är det... ganska enkelt men det är en teknik jag använder i alla mina projekt. Det är ett trevligt sätt att arbeta med konfiguration och jag tycker att det är lite mer naturligt än den IOptions<T>
Mönster.