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
Φαίνεται ότι ο καθένας έχει μια έκδοση αυτού του κώδικα, ήρθα για πρώτη φορά σε αυτή την προσέγγιση από Filip W και πρόσφατα ο παλιός μου συνάδελφος Phil Hack έχει την εκδοχή του.
Απλά για να ολοκληρώσω, έτσι το κάνω.
Ο λόγος είναι να είναι ευκολότερο να λειτουργήσει με τη διαμόρφωση. Αυτή τη στιγμή ο πρωθυπουργός χρησιμοποιεί IOptions<T>
και IOptionsSnapshot<T>
Αλλά αυτό είναι ένα κομμάτι του πόνου για να λειτουργήσει με. Αυτή η προσέγγιση σας επιτρέπει να συνεργαστείτε με τη διαμόρφωση με έναν πιο φυσικό τρόπο.
Οι περιορισμοί είναι ότι δεν μπορείτε να χρησιμοποιήσετε το IOptions<T>
μοτίβο, ώστε να μην έχετε τη δυνατότητα να ξαναγεμίσετε τη διαμόρφωση χωρίς να επανεκκινήσετε την εφαρμογή. Ωστόσο, ειλικρινά αυτό είναι κάτι που σχεδόν ποτέ δεν θέλω να κάνω.
Στην εκδοχή μου χρησιμοποιώ τα πρόσφατα στατικά μέλη διεπαφών για να διευκρινίσω ότι όλες οι περιπτώσεις αυτής της κατηγορίας πρέπει να δηλώσουν Section
ιδιοκτησία. Αυτό χρησιμοποιείται για να πάρει το τμήμα από τη διαμόρφωση.
public interface IConfigSection {
public static abstract string Section { get; }
}
Έτσι, για κάθε εφαρμογή θα πρέπει στη συνέχεια να προσδιορίσετε σε ποιο τμήμα αυτό να δεσμεύεται:
public class NewsletterConfig : IConfigSection
{
public static string Section => "Newsletter";
public string SchedulerServiceUrl { get; set; } = string.Empty;
public string AppHostUrl { get; set; } = string.Empty;
}
Σε αυτή την περίπτωση ψάχνει για ένα τμήμα στη διαμόρφωση που ονομάζεται Newsletter
.
"Newsletter": {
"SchedulerServiceUrl" : "http://localhost:5000",
"AppHostUrl" : "https://localhost:7240"
}
Θα μπορέσουμε στη συνέχεια να το συνδέσουμε αυτό με την Program.cs
αρχείο όπως:
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
services.ConfigurePOCO<NewsletterConfig>(config);
Μπορούμε επίσης να πάρουμε την αξία του config στο Program.cs
αρχείο όπως:
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(config);
Ή ακόμη και για την WebApplicationBuilder
όπως έτσι:
var newsletterConfig = builder.Configure<NewsletterConfig>();
Σημείωση: Δεδομένου ότι ο κατασκευαστής έχει πρόσβαση στο ConfigurationManager
Δεν χρειάζεται να το περάσει αυτό.
Που σημαίνει ότι τώρα έχεις επιλογές για το πώς να κλείσεις τη ρύθμιση.
Ένα άλλο πλεονέκτημα είναι ότι αν πρέπει να χρησιμοποιήσετε αυτές τις τιμές αργότερα στην Program.cs
αρχείο τότε το αντικείμενο είναι στη διάθεσή σας.
Για να μπορέσουμε όλα αυτά έχουμε μια αρκετά απλή μέθοδο επέκτασης που κάνει το έργο της δέσμευσης της διαμόρφωσης στην τάξη.
Ο παρακάτω κωδικός επιτρέπει τα ακόλουθα:
// 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>();
Όλα αυτά ενεργοποιούνται από την ακόλουθη κατηγορία επέκτασης.
Μπορείτε να δείτε ότι η κύρια ώθηση αυτού είναι να χρησιμοποιήσετε τα στατικά μέλη διεπαφής για να καθορίσετε το όνομα τμήματος. Αυτό χρησιμοποιείται στη συνέχεια για να πάρει το τμήμα από τη διαμόρφωση.
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);
}
}
Το να τα χρησιμοποιείς είναι πολύ απλό. Σε κάθε κατηγορία όπου χρειάζεστε αυτό το config μπορείτε απλά να το κάνετε ένεση έτσι:
public class NewsletterService(NewsletterConfig config {
}
Λοιπόν αυτό είναι... αρκετά απλό αλλά είναι μια τεχνική που χρησιμοποιώ σε όλες μου τις εργασίες. Είναι ένας ωραίος τρόπος να δουλεύεις με τη διαμόρφωση και νομίζω ότι είναι λίγο πιο φυσικό από το IOptions<T>
μοτίβο.