# Omien sääntöjen mukaiset Config-osuuksien laajennukset

<!--category-- C#, ASP.NET -->
<datetime class="hidden">2024-09-27T06:20</datetime>

# Esitys

Vaikuttaa siltä, että kaikilla on versioni tästä kodesta, Ensin kuullut tätä lähestymistapaa [Filip W](https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/) ja äskettäin vanha kollegani Phil Haack [hänen versionsa](https://haacked.com/archive/2024/07/18/better-config-sections/).

Vain täydentämiseksi tämä on se, miten teen sen.

[TOC]

# Miksi?

Miksi on helpompaa työskennellä kokoonpanon kanssa. Tällä hetkellä ensisijainen tapa käyttää `IOptions<T>` ja `IOptionsSnapshot<T>` Tämä lähestymistapa antaa mahdollisuuden työskennellä kokoonpanon kanssa luonnollisemmin.
Rajoituksia on se, että te ette voi käyttää `IOptions<T>` malli, joten ette' saa mahdollisuutta ladata uudelleen kokoonpanoa aloittamatta uudelleen sovellustaM SK2 mutta rehellisesti sanottuna tämä on asia, jota en lähes koskaan halua tehdä

# Luettelo

Omassa versiossani käytän viimeaikaisia statisia Interface-jäseniä täsmentääkseni, että kaikkien tämän luokan tapausten on ilmoitettava `Section` property. Tätä käytetään osuuden saamiseksi konfiguraatiosta

```csharp
public interface IConfigSection {
    public static abstract string Section { get; }
}
```

Näin ollen kunkin täytäntöönpanon osalta määrittelette sitten, mihin osuuteen tämä olisi sidottava:

```csharp
public class NewsletterConfig : IConfigSection
{
    public static string Section => "Newsletter";
    
    public string SchedulerServiceUrl { get; set; } = string.Empty;
    public string AppHostUrl { get; set; } = string.Empty;
}
```

Tässä tapauksessa se' etsii kohtaa konfiguraatiossa, joka kutsutaan `Newsletter`.

```json
  "Newsletter": {
      "SchedulerServiceUrl" : "http://localhost:5000",
        "AppHostUrl" : "https://localhost:7240"
    
  }

```

Sen jälkeen voimme sitoa tämän `Program.cs` file like so:

```csharp

var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
services.ConfigurePOCO<NewsletterConfig>(config);

```

Voimme myös saada configin arvon `Program.cs` file like so:

```csharp
var newsletterConfig = services.ConfigurePOCO<NewsletterConfig>(config);

```

Tai jopa `WebApplicationBuilder` Kuten niin

```csharp
var newsletterConfig = builder.Configure<NewsletterConfig>();
```

Huomautus: Koska rakentajalla on pääsy `ConfigurationManager` ei ole tarpeen, että se menee läpi

Tämä tarkoittaa, että teillä on nyt vaihtoehtoja siitä, miten yhdistää config.

Toinen etu on se, että jos tarvitsette käyttää näitä arvoja myöhemmin `Program.cs` sitten asia on käytettävissänne.

# Laajentumismenetelmä

Kaiken tämän mahdollistamiseksi meillä on melko yksinkertainen laajentamismenetelmä, joka tekee kokoonpanon sitomisen luokitukseen.

jäljempänä oleva koodi sallii seuraavan:

```csharp
// 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>();

```

Tämä kaikki on mahdollista seuraavalla laajentumisryhmällä.

Huomaatte, että tämän tärkein sysäys on se, että käyttämme statisia liittymiskumppaneita osuuden nimeämiseen. Tämän jälkeen sitä käytetään osan saamiseksi konfiguraatiostaM SK1

```csharp
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);
    }
}
```

# Käytettävissä

Niiden käyttö on varsin yksinkertaista. Kaikissa luokissa, joissa tarvitsette tätä konfigurointia, voitte vain sekoittaa sen niin.

```csharp
public class NewsletterService(NewsletterConfig config {
 
}
```

# Päätelmissä

No, se on hyvin yksinkertainen, mutta se on tekniikka, jota käytän kaikissa hankkeissani. Se on mukava tapa työskennellä kokoonpanossa ja mielestäni se on hieman luonnollisempaa kuin `IOptions<T>` malli.