[ASP.NET Core 3框架揭秘] 配置[9]:自定义配置源

我们在前面对配置模型中默认提供的各种IConfigurationSource实现类型进行了深入详尽的介绍,如果它们依然不能满足项目中的需求,我们还可以通过自定义IConfigurationSource实现类型来支持我们希望的配置源。就配置数据的持久化方式来说,将配置存储在数据库中应该是一种常见的方式。接下来我们会创建一个针对数据库的IConfigurationSource实现类型,它采用Entity Framework Core来完成数据库的存取操作。

我们将这个自定义ConfigurationSource命名为DbConfigurationSource。在正式介绍的实现之前,我们先来看看它在项目中的应用。我们将配置保存在SQL Server数据库中的某个数据表中,并采用Entity Framework Core来读取它。我们将连接字符串作为配置定义在一个名为“appSettings.json”的JSON文件中。

{
  "connectionStrings": {
    "DefaultDb":  "Server = ... ; Database=...; Uid = ...; Pwd = ..."
  }
}

在如下所示的演示程序中,我们首先创建了一个ConfigurationBuilder对象,并在它上面注册了一个指向connectionString.json文件的JsonConfigurationSource对象。针对DbConfigurationSource对象的注册体现在扩展方法AddDatabase上,这个方法具有两个参数,分别代表连接字符串的名称和初始的配置数据。前者正是connectionString.json设置的连接字符串名称DefaultDb,后者是一个字典对象,它提供的原始配置正好可以构成一个Profile对象。在利用ConfigurationBuilde对象创建出相应的IConfiguration对象之后,我们读取配置将其绑定为一个Profile对象。

public class Program
{
    static void Main()
    {
        var initialSettings = new Dictionary<string, string>
        {
            ["Gender"] = "Male",
            ["Age"] = "18",
            ["ContactInfo:EmailAddress"] = "[email protected]",
            ["ContactInfo:PhoneNo"] = "123456789"
        };

        var profile = new ConfigurationBuilder()
            .AddJsonFile("appSettings.json")
            .AddDatabase("DefaultDb", initialSettings)
            .Build()
            .Get<Profile>();

        Debug.Assert(profile.Gender == Gender.Male);
        Debug.Assert(profile.Age == 18);
        Debug.Assert(profile.ContactInfo.EmailAddress == "[email protected]");
        Debug.Assert(profile.ContactInfo.PhoneNo == "123456789");
    }
}

如上面的代码片断所示,针对DbConfigurationSource的应用仅仅体现在我们为IConfigurationBuilder对象定义的AddDatabase扩展方法上,所以使用起来是非常方便的,那么这个扩展方法背后有着怎样的逻辑实现呢?DbConfigurationSource采用Entity Framework Core并以Code First的方式进行数据操作,如下所示的ApplicationSetting是表示基本配置项的POCO类型,我们将配置项的Key以小写的方式存储。另一个ApplicationSettingsContext是对应的DbContext类型。

[Table("ApplicationSettings")]
public class ApplicationSetting
{
    private string key;

    [Key]
    public string Key
    {
        get { return key; }
        set { key = value.ToLowerInvariant(); }
    }

    [Required]
    [MaxLength(512)]
    public string Value { get; set; }

    public ApplicationSetting()
    { }

    public ApplicationSetting(string key, string value)
    {
        Key = key;
        Value = value;
    }
}

public class ApplicationSettingsContext : DbContext
{
    public ApplicationSettingsContext(DbContextOptions options) : base(options)
    { }

    public DbSet<ApplicationSetting> Settings { get; set; }
}

如下所示的是DbConfigurationSource类型的定义,它的构造函数具有两个参数,第一个参数类型为Action<DbContextOptionsBuilder>,我们用这个委托对象来对创建DbContext采用的DbContextOptions进行设置,另一个可选的参数用来指定一些需要自动初始化的配置项。DbConfigurationSource在重写的Build方法中利用这两个对象 创建一个DbConfigurationProvider对象。

public class DbConfigurationSource : IConfigurationSource
{
    private Action<DbContextOptionsBuilder> _setup;
    private IDictionary<string, string> _initialSettings;

    public DbConfigurationSource(Action<DbContextOptionsBuilder> setup, IDictionary<string, string> initialSettings = null)
    {
        _setup = setup;
        _initialSettings     = initialSettings;
    }
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new DbConfigurationProvider(_setup, _initialSettings);
    }
}

DbConfigurationProvider派生于抽象类ConfigurationProvider。在重写的Load方法中,它会根据提供的Action<DbContextOptionsBuilder>创建ApplicationSettingsContext对象,并利用它从数据库中读取配置数据并转换成字典对象并赋值给代表配置字典的Data属性 。如果数据表中没有数据,该方法还会利用这个DbContext对象将提供的初始化配置添加到数据库中。

public class DbConfigurationProvider: ConfigurationProvider
{
    private readonly IDictionary<string, string> _initialSettings;
    private readonly Action<DbContextOptionsBuilder> _setup;

    public DbConfigurationProvider(Action<DbContextOptionsBuilder> setup,  IDictionary<string, string> initialSettings)
    {
        _setup  = setup;
        _initialSettings     = initialSettings?? new Dictionary<string, string>() ;
    }

    public override void Load()
    {
        var builder =  new DbContextOptionsBuilder<ApplicationSettingsContext>();
        _setup(builder);
        using (ApplicationSettingsContext dbContext =  new ApplicationSettingsContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();
            Data = dbContext.Settings.Any()
                ? dbContext.Settings.ToDictionary(it => it.Key, it => it.Value,  StringComparer.OrdinalIgnoreCase)
                : Initialize(dbContext);
        }
    }

    private IDictionary<string, string> Initialize( ApplicationSettingsContext dbContext)
    {
        foreach (var item in _initialSettings)
        {
            dbContext.Settings.Add(new ApplicationSetting(item.Key, item.Value));
        }
        return _initialSettings.ToDictionary(it => it.Key, it => it.Value,  StringComparer.OrdinalIgnoreCase);
    }
}

实例演示中用来注册DbConfigurationSource对象的扩展方法AddDatabase具有如下的定义。该方法首先调用IConfigurationBuilder对象的Build方法创建出一个IConfiguration对象,并调用该对象[A5] 的扩展方法GetConnectionString根据指定的连接字符串名称得到完整的连接字符串。接下来我们调用构造函数创建一个DbConfigurationSource对象并注册到ConfigurationBuilder对象上。创建DbConfigurationSource对象时指定的Action<DbContextOptionsBuilder>会完成针对连接字符串的设置。

public static class DbConfigurationExtensions
{
    public static IConfigurationBuilder AddDatabase(  this IConfigurationBuilder builder, string connectionStringName,  IDictionary<string, string> initialSettings = null)
    {
        var connectionString = builder.Build() .GetConnectionString(connectionStringName);
        var source = new DbConfigurationSource( optionsBuilder => optionsBuilder.UseSqlServer(connectionString), initialSettings);
        builder.Add(source);
        return builder;
    }
}

[ASP.NET Core 3框架揭秘] 配置[1]:读取配置数据[上篇]
[ASP.NET Core 3框架揭秘] 配置[2]:读取配置数据[下篇]
[ASP.NET Core 3框架揭秘] 配置[3]:配置模型总体设计
[ASP.NET Core 3框架揭秘] 配置[4]:将配置绑定为对象
[ASP.NET Core 3框架揭秘] 配置[5]:配置数据与数据源的实时同步
[ASP.NET Core 3框架揭秘] 配置[6]:多样化的配置源[上篇]
[ASP.NET Core 3框架揭秘] 配置[7]:多样化的配置源[中篇]
[ASP.NET Core 3框架揭秘] 配置[8]:多样化的配置源[下篇]
[ASP.NET Core 3框架揭秘] 配置[9]:自定义配置源

原文地址:https://www.cnblogs.com/artech/p/inside-asp-net-core-05-09.html

时间: 2024-08-26 20:12:58

[ASP.NET Core 3框架揭秘] 配置[9]:自定义配置源的相关文章

[ASP.NET Core 3框架揭秘] Options[7]: 与配置系统的整合

Options模型本身与配置系统完全没有关系,但是配置在大部分情况下会作为绑定Options对象的数据源,所以有必要将两者结合在一起.与<扩展与定制>演示的两个例子一样,针对配置系统的集成同样是通过定制Options模型相应的对象来实现的.具体来说,集成配置系统需要解决如下两个问题: 将承载配置数据的IConfiguration对象绑定为Options对象. 自动感知配置数据的变化. 第一个问题涉及针对Options对象的初始化问题,这自然是通过自定义IConfigureOptions<

[ASP.NET Core 3框架揭秘] Options[4]: Options模型[下篇]

六.IOptionsMonitorCache<TOptions> IOptionsFactory<TOptions>解决了Options的创建与初始化问题,但由于它自身是无状态的,所以Options模型对Options对象实施缓存可以获得更好的性能.Options模型中针对Options对象的缓存由IOptionsMonitorCache<TOptions>对象来完成,如下所示的代码片段是该接口的定义. public interface IOptionsMonitorC

[ASP.NET Core 3框架揭秘] 配置[5]:配置数据与数据源的实时同步

在<配置模型总体设计>介绍配置模型核心对象的时候,我们刻意回避了与配置同步相关的API,现在我们利用一个独立文章来专门讨论这个话题.配置的同步涉及到两个方面:第一,对原始的配置源实施监控并在其发生变化之后重新加载配置:第二,配置重新加载之后及时通知应用程序进而使应用能够及时使用最新的配置.要了解配置同步机制的实现原理,我们先得了解一下配置数据的流向. 一.配置数据流 通过前面的介绍,我们已经对配置模型有了充分的了解,处于核心地位的 IConfigurationBuilder对象借助注册的ICo

[ASP.NET Core 3框架揭秘] 配置[3]:配置模型总体设计

原文:[ASP.NET Core 3框架揭秘] 配置[3]:配置模型总体设计 在<读取配置数据>([上篇],[下篇])上面一节中,我们通过实例的方式演示了几种典型的配置读取方式,接下来我们从设计的维度来重写认识配置模型.配置的编程模型涉及到三个核心对象,分别通过三个对应的接口(IConfiguration.IConfigurationSource和IConfigurationBuilder)来表示.如果从设计层面来审视背后的配置模型,还缺少另一个名通过IConfigurationProvide

[ASP.NET Core 3框架揭秘] 配置[6]:多样化的配置源[上篇]

.NET Core采用的这个全新的配置模型的一个主要的特点就是对多种不同配置源的支持.我们可以将内存变量.命令行参数.环境变量和物理文件作为原始配置数据的来源.如果采用物理文件作为配置源,我们可以选择不同的格式(比如XML.JSON和INI等).如果这些默认支持的配置源形式还不能满足你的需求,我们还可以通过注册自定义IConfigurationSource的方式将其他形式数据作为配置来源. 一.MemoryConfigurationSource 在之前的实例演示都在使用MemoryConfigu

[ASP.NET Core 3框架揭秘] 依赖注入:控制反转

ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样会频繁地使用到它们.对于这里提到的这几个基础框架,依赖注入尤为重要.ASP.NET Core应用在启动以及后续针对请求的处理过程中,它会依赖各种的组件提供服务.为了便于定制,这些组件一般会以接口的形式进行"标准化",我们将这些标准化的组件统一称为"服务(Service)"

[ASP.NET Core 3框架揭秘] 依赖注入[5]: 利用容器提供服务

毫不夸张地说,整个ASP.NET Core框架是建立在依赖注入框架之上的.ASP.NET Core应用在启动时构建管道以及利用该管道处理每个请求过程中使用到的服务对象均来源于依赖注入容器.该依赖注入容器不仅为ASP.NET Core框架自身提供必要的服务,同时也是应用程序的服务提供者,依赖注入已经成为了ASP.NET Core应用的基本编程模式. 一.服务的注册与消费 为了让读者朋友们能够更加容易地认识.NET Core提供的依赖注入框架,我在"<一个迷你版DI框架>"中特

[ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [上篇]

微软在千禧年推出 .NET战略,并在两年后推出第一个版本的.NET Framework和IDE(Visual Studio.NET 2002,后来改名为Visual Studio),如果你是一个资深的.NET程序员,相信传统的.NET应用的开发方式已经深深地烙印在你的脑子里面..NET Core带来了全新的开发体验,但开发方式的差异根本不足以成为你快速跨入.NET Core 世界的门槛,因为在.NET Core在很多方面比传统的.NET Framework应用开发要简单.为了消除很多尚未接触过.

[ASP.NET Core 3框架揭秘] 跨平台开发体验: Linux

如果想体验Linux环境下开发.NET Core应用,我们有多种选择.一种就是在一台物理机上安装原生的Linux,我们可以根据自身的喜好选择某种Linux Distribution,目前来说像RHEL.Ubuntu.Debian.Fedora.CentOS和SUSE这些主流的Distribution都是支持的.如果读者朋友们觉得这种方式比较麻烦,我们也可以采用虚拟机的形式安装相应的Linux Distribution,比如我经常使用的都是安装在VirtualBox上的Ubuntu.对于X64 W