ASP.NET Core : 二十三. 深入聊一聊配置的内部处理机制(一)

简介: 上一章介绍了配置的多种数据源被注册、加载和获取的过程,本节看一下这个过程系统是如何实现的。

一、数据源的注册

在上一节介绍的数据源设置中,appsettings.json、命令行、环境变量三种方式是被系统自动加载的,这是因为系统在webHost.CreateDefaultBuilder(args)中已经为这三种数据源进了注册,那么就从这个方法说起。这个方法中同样调用了ConfigureAppConfiguration方法,代码如下:

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
    var builder = newWebHostBuilder();
    //省略部分代码
    builder.UseKestrel((builderContext, options) =>
        {
            options.Configure(builderContext.Configuration.GetSection("Kestrel"));
        })
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            var env = hostingContext.HostingEnvironment;
            config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional:true, reloadOnChange: true);
            if(env.IsDevelopment())
            {
                var appAssembly = Assembly.Load(newAssemblyName(env.ApplicationName));
                if(appAssembly != null)
                {
                    config.AddUserSecrets(appAssembly, optional: true);
                }
            }
            config.AddEnvironmentVariables();
            if(args != null)
            {
                config.AddCommandLine(args);
            }
       })
       //省略部分代码
    return builder;
}

看一下其中的ConfigureAppConfiguration方法,加载的内容主要有四种,首先加载的是appsettings.json和appsettings.{env.EnvironmentName}.json两个JSON文件,关于env.EnvironmentName在前面的章节已经说过,常见的有Development、Staging 和 Production三种值,在我们开发调试时一般是Development,也就是会加载appsettings.json和appsettings. Development.json两个JSON文件。第二种加载的是用户机密文件,这仅限于Development状态下,会通过config.AddUserSecrets方法加载。第三种是通过config.AddEnvironmentVariables方法加载的环境变量,第四种是通过config.AddCommandLine方法加载的命令行参数。


注意:这里的ConfigureAppConfiguration方法这时候是不会被执行的,只是将这个方法作为一个Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate添加到了WebHostBuilder的_configureServicesDelegates属性中。configureServicesDelegates是一个List<Action<WebHostBuilderContext, IConfigurationBuilder>>类型的集合。对应代码如下:

public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
{
    if(configureDelegate == null)
    {
        throw new ArgumentNullException(nameof(configureDelegate));
    }
    _configureAppConfigurationBuilderDelegates.Add(configureDelegate);
    returnthis;
}

上一节的例子中,我们在webHost.CreateDefaultBuilder(args)方法之后再次调用ConfigureAppConfiguration方法添加了一些自定义的数据源,这个方法也是没有执行,同样被添加到了这个集合中。直到WebHostBuilder通过它的Build()方法创建WebHost的时候,才会遍历这个集合逐一执行。这段代码写在被Build()方法调用的BuildCommonServices()中:

private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
{
    //省略部分代码
    var builder = new ConfigurationBuilder()
        .SetBasePath(_hostingEnvironment.ContentRootPath)
        .AddConfiguration(_config);
    foreach (var configureAppConfiguration in _configureAppConfigurationBuilderDelegates)
    {
        configureAppConfiguration(_context, builder);
    }
    var configuration = builder.Build();
    services.AddSingleton<IConfiguration>(configuration);
    _context.Configuration = configuration;
//省略部分代码
    return services;
}

首先创建了一个ConfigurationBuilder对象,然后通过foreach循环逐一执行被添加到集合_configureAppConfigurationBuilderDelegates中的configureAppConfiguration方法,那么在执行的时候,这些不同的数据源是如何被加载的呢?这部分功能在namespace Microsoft.Extensions.Configuration命名空间中。


以appsettings.json对应的config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)方法为例,进一步看一下它的实现方式。首先介绍的是IConfigurationBuilder接口,对应的实现类是ConfigurationBuilder,代码如下:

public class ConfigurationBuilder : IConfigurationBuilder
    {
        public IList<IConfigurationSource> Sources { get; } = new List<IConfigurationSource>();
        public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();
        public IConfigurationBuilder Add(IConfigurationSource source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            Sources.Add(source);
            return this;
        }
        //省略了IConfigurationRoot Build()方法,下文介绍
    }

ConfigureAppConfiguration方法中调用的AddJsonFile方法来自JsonConfigurationExtensions类,代码如下:

public static class JsonConfigurationExtensions
{
//省略部分代码
    public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }
        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
        }
        return builder.AddJsonFile(s =>
        {
            s.FileProvider = provider;
            s.Path = path;
            s.Optional = optional;
            s.ReloadOnChange = reloadOnChange;
            s.ResolveFileProvider();
        });
    }
    public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, Action<JsonConfigurationSource> configureSource)
        => builder.Add(configureSource);
}

AddJsonFile方法会创建一个JsonConfigurationSource并通过ConfigurationBuilder的Add(IConfigurationSource source)方法将这个JsonConfigurationSource添加到ConfigurationBuilder的IList<IConfigurationSource> Sources集和中去。


同理,针对环境变量,存在对应的EnvironmentVariablesExtensions,会创建一个对应的EnvironmentVariablesConfigurationSource添加到ConfigurationBuilder的IList<IConfigurationSource> Sources集和中去。这样的还有CommandLineConfigurationExtensions和CommandLineConfigurationSource等,最终结果就是会根据数据源的加载顺序,生成多个XXXConfigurationSource对象(它们都直接或间接实现了IConfigurationSource接口)添加到ConfigurationBuilder的IList<IConfigurationSource> Sources集和中。


目录
相关文章
|
2月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
3月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
3月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
100 3
|
2月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
|
3月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
43 7
|
3月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
63 0
|
4月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
49 0
|
4月前
|
开发框架 前端开发 安全
ASP.NET MVC 如何使用 Form Authentication?
ASP.NET MVC 如何使用 Form Authentication?
|
4月前
|
开发框架 .NET
Asp.Net Core 使用X.PagedList.Mvc.Core分页 & 搜索
Asp.Net Core 使用X.PagedList.Mvc.Core分页 & 搜索
129 0
|
7月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
195 0
下一篇
无影云桌面