# 自定义区域配置扩展

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

# 一. 导言导言 导言 导言 导言

似乎每个人都有这个代码的版本 , [菲利普 W](https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/) 最近我的老同事菲尔·哈克 [其版本](https://haacked.com/archive/2024/07/18/better-config-sections/).

仅供完成,这是我如何做到的

[TOC]

# 为什么?

为何要让配置更方便地工作? `IOptions<T>` 和 `IOptionsSnapshot<T>` 这个方法允许您以更自然的方式与配置一起工作 \ .\ \ @
限制是您可以使用 `IOptions<T>` @ ,} @ 这样您就不会在不重新启动应用程序的情况下获得重新装入配置的能力@ MS K2 @ 但是说实话, 我几乎从来不想这样做 @ I.}

# 《刑法典》

在我的版本中,我使用最近的静态界面成员来说明这一类的所有情况必须宣布 `Section` 属性@.}% 1 用于从配置中获取区域 .}{}

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

所以对于每次执行, 您会指定它应该与 @ : @ @ { label

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

在此情况下, 它正在寻找配置中名为“ I'” 的区段 `Newsletter`.

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

```

然后,我们将能够将这一点约束在 `Program.cs` 类似文件@ @ : @ {}

```csharp

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

```

我们也可以得到配置的价值 在 `Program.cs` 类似文件@ @ : @ {}

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

```

甚至为了 `WebApplicationBuilder` {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}就像

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

注::作为建造者可以进入 `ConfigurationManager` 不需要在.中通过

意思是您现在可以选择如何绑定 config.

另一个好处是,如果你以后需要使用这些数值 `Program.cs` 然后该对象可以为您提供文件@. @%

# 推广方法

要启用所有这些功能, 我们有一个相当简单的扩展方法, 可以将配置与等级绑定 {.} @ {}

以下代码允许使用以下“:”

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

```

所有这一切都由以下扩展类\ . 启用

您可以看到它的主要动力是使用静态界面成员来指定区域名称@ .。 这将用来从配置中获取此部分\ .

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

# 使用中

要使用这些非常简单@ . @ 在任何您需要这种配置的类中, 您可以简单地将其输入到类似 so:\} @

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

# 在结论中的结论

我在所有项目中都使用这个技术 和配置合作的好方法 我认为它比 `IOptions<T>` 模式@. @%