# Aangepaste sectieextensies

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

# Inleiding

Het lijkt erop dat iedereen een versie van deze code heeft, ik kwam eerst deze benadering tegen van [Filip W](https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/) en onlangs heeft mijn oude collega Phil Haack [zijn versie](https://haacked.com/archive/2024/07/18/better-config-sections/).

Gewoon voor de voltooiing dit is hoe ik het doe.

[TOC]

# Waarom?

De reden is om het makkelijker te maken om te werken met configuratie. Op dit moment wordt de belangrijkste manier gebruikt `IOptions<T>` en `IOptionsSnapshot<T>` Maar dit is een beetje lastig om mee te werken. Deze aanpak stelt u in staat om op een meer natuurlijke manier met de configuratie te werken.
De beperkingen zijn dat u de `IOptions<T>` patroon, zodat u niet de mogelijkheid krijgt om de configuratie te herladen zonder de toepassing te herstarten. Maar eerlijk gezegd is dit iets wat ik bijna nooit wil doen.

# De code

In mijn versie gebruik ik de recente statische Interface-leden om aan te geven dat alle instanties van deze klasse een `Section` eigendom. Dit wordt gebruikt om de sectie uit de configuratie te krijgen.

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

Voor elke implementatie geef je dan aan aan aan welke sectie dit moet worden gebonden aan:

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

In dit geval is het op zoek naar een sectie in de configuratie genaamd `Newsletter`.

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

```

We zullen dan in staat zijn om dit te binden in de `Program.cs` bestand als volgt:

```csharp

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

```

We kunnen ook de waarde van de config in de `Program.cs` bestand als volgt:

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

```

Of zelfs voor de `WebApplicationBuilder` Zoals:

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

Opmerking: Omdat de bouwer toegang heeft tot de `ConfigurationManager` Dat hoeft niet doorgegeven te worden.

Dat betekent dat je nu opties hebt om config te binden.

Een ander voordeel is dat als u deze waarden later in uw `Program.cs` bestand dan is het object beschikbaar voor u.

# De extensiemethode

Om dit alles mogelijk te maken hebben we een vrij eenvoudige extensie methode die het werk van het binden van de configuratie aan de klasse doet.

De onderstaande code staat het volgende toe:

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

```

Dit is allemaal ingeschakeld door de volgende extensieklasse.

U kunt zien dat de belangrijkste impuls hiervan is het gebruik van de statische interface leden om de sectienaam op te geven. Dit wordt dan gebruikt om de sectie uit de configuratie te krijgen.

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

# In gebruik

Om deze te gebruiken is vrij eenvoudig. In elke klasse waar u deze configuratie nodig heeft, kunt u deze gewoon zo injecteren:

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

# Conclusie

Nou dat is het... vrij eenvoudig maar het is een techniek die ik gebruik in al mijn projecten. Het is een leuke manier om te werken met configuratie en ik denk dat het is een beetje natuurlijker dan de `IOptions<T>` patroon.