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
Sembra che tutti abbiano una versione di questo codice, mi sono imbattuto in questo approccio da Filip W e recentemente il mio vecchio collega Phil Haack ha la sua versione.
Solo per completare questo è come lo faccio io.
Il motivo è quello di rendere più facile lavorare con la configurazione. Al momento la via principale sta usando IOptions<T>
e IOptionsSnapshot<T>
Ma questo e' un po' un dolore con cui lavorare. Questo approccio consente di lavorare con la configurazione in modo più naturale.
I limiti sono che non è possibile utilizzare il IOptions<T>
pattern, in modo da non avere la possibilità di ricaricare la configurazione senza riavviare l'applicazione. Per quanto onestamente questa sia una cosa che non voglio quasi mai fare.
Nella mia versione uso i recenti membri statici di Interface per specificare che tutti i casi di questa classe devono dichiarare un Section
proprieta'. Questo viene usato per ottenere la sezione dalla configurazione.
public interface IConfigSection {
public static abstract string Section { get; }
}
Quindi per ogni implementazione si specifica a quale sezione questo dovrebbe essere vincolato:
public class NewsletterConfig : IConfigSection
{
public static string Section => "Newsletter";
public string SchedulerServiceUrl { get; set; } = string.Empty;
public string AppHostUrl { get; set; } = string.Empty;
}
In questo caso è alla ricerca di una sezione nella configurazione chiamata Newsletter
.
"Newsletter": {
"SchedulerServiceUrl" : "http://localhost:5000",
"AppHostUrl" : "https://localhost:7240"
}
Noi saremo poi in grado di legare questo nel Program.cs
file in questo modo:
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
services.ConfigurePOCO<NewsletterConfig>(config);
Possiamo anche ottenere il valore della configurazione nel Program.cs
file in questo modo:
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(config);
O anche per il WebApplicationBuilder
così:
var newsletterConfig = builder.Configure<NewsletterConfig>();
Nota: Poiché il costruttore ha accesso alla ConfigurationManager
Non c'e' bisogno di farlo passare.
Significa che ora hai delle opzioni su come legare la config.
Un altro vantaggio è che se avete bisogno di utilizzare questi valori in seguito nel vostro Program.cs
quindi l'oggetto è disponibile per voi.
Per abilitare tutto questo abbiamo un metodo di estensione abbastanza semplice che fa il lavoro di vincolare la configurazione alla classe.
Il codice qui sotto permette quanto segue:
// 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>();
Tutto questo è abilitato dalla seguente classe di estensione.
Potete vedere che l'impulso principale di questo è l'utilizzo dei membri dell'interfaccia statica per specificare il nome della sezione. Questo viene poi usato per ottenere la sezione dalla configurazione.
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);
}
}
Usare questi è abbastanza semplice. In qualsiasi classe in cui hai bisogno di questa configurazione puoi semplicemente iniettarla in questo modo:
public class NewsletterService(NewsletterConfig config {
}
Beh, è... abbastanza semplice, ma è una tecnica che uso in tutti i miei progetti. E 'un bel modo di lavorare con la configurazione e penso che è un po 'più naturale IOptions<T>
schema.