.NET Core 3.0之深入源码理解Configuration(二)

原文:.NET Core 3.0之深入源码理解Configuration(二)

文件型配置基本内容

上一篇文章讨论了Configuration的几个核心对象,本文继续讨论Configuration中关于文件型配置的相关内容。相比较而言,文件型配置的使用场景更加广泛,用户自定义配置扩展也可以基于文件型配置进行扩展。如果需要查看上一篇文章,可以点击移步

.NET Core文件型配置中我们提供了三种主要的实现,分别是JSON、XML、INI,请查看下图

由图可知,这三种配置的实现方式是一样的,当然了其他的配置比如命令行配置、环境变量配置等也是大同小异,理解了改配置类型的实现方式,后面我们再扩展基于Consul或者ZK的实现,就非常简单了。

文件型配置的抽象扩展

文件型配置的抽象扩展位于Microsoft.Extensions.Configuration.FileExtensions组件中,该扩展是一个基础实现。不过其命名空间是Microsoft.Extensions.Configuration,而Micros oft.Extensions.Configuration扩建本身又是整个.NET Core Configuration的基础实现。将File扩展独立于外部,体验了.NET Core的模块化设计。

FileConfigurationSource

Configuration.FileExtensions组件中,FileConfigurationSource是继承于IConfigurationSource的一个抽象类,包含了一个IConfigurationProvider类型的抽象方法,如下所示

   1:  /// <summary>
   2:  /// Builds the <see cref="IConfigurationProvider"/> for this source.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
   5:  /// <returns>A <see cref="IConfigurationProvider"/></returns>
   6:  public abstract IConfigurationProvider Build(IConfigurationBuilder builder);

该抽象类中还包括了几个比较重要的参数,分别用于配置性行为、文件内容访问以及异常处理。

string Path:文件的路径

bool Optional:标识加载的文件是否是可选的

bool ReloadOnChange:如果文件发生修改,是否重新加载配置源

int ReloadDelay:加载延迟,单位是毫秒,默认是250毫秒

IFileProvider FileProvider:用于获取文件内容

Action<FileLoadExceptionContext> OnLoadException:文件加载异常处理

该类对FileProvider有特殊处理,就是如果没有提供FileProvider实例,则会基于绝对路径,在最近的现有目录中创建物理文件提供程序。源码如下,

   1:  /// <summary>
   2:  /// If no file provider has been set, for absolute Path, this will creates a physical file provider 
   3:  /// for the nearest existing directory.
   4:  /// </summary>
   5:  public void ResolveFileProvider()
   6:  {
   7:      if (FileProvider == null && 
   8:          !string.IsNullOrEmpty(Path) &&
   9:          System.IO.Path.IsPathRooted(Path))
  10:      {
  11:      

var directory = System.IO.Path.GetDirectoryName(Path);

  12:          var pathToFile = System.IO.Path.GetFileName(Path);
  13:          while (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
  14:          {
  15:              pathToFile = System.IO.Path.Combine(System.IO.Path.GetFileName(directory), pathToFile);
  16:              directory = System.IO.Path.GetDirectoryName(directory);
  17:          }
  18:          if (Directory.Exists(directory))
  19:          {
  20:              FileProvider = new PhysicalFileProvider(directory);
  21:              Path = pathToFile;
  22:          }
  23:      }
  24:  }

FileConfigurationProvider

该类是继承于ConfigurationProvider的抽象类,是从文件系统加载配置的基类,同时还继承了IDisposable,其抽象方法是Load方法,用于从当前的Provider中以Stream方式加载数据

   1:  /// <summary>
   2:  /// Loads this provider‘s data from a stream.
   3:  /// </summary>
   4:  /// <param name="stream">The stream to read.</param>
   5:  public abstract void Load(Stream stream);

该类还重写了ConfigurationProvider的Load方法,并对文件加载中的异常做了处理,Data属性在前文有提到过,此处不再做其他说明。方法源码如下所示:

   1:  private void Load(bool reload)
   2:  {
   3:      var file = Source.FileProvider?.GetFileInfo(Source.Path);
   4:      if (file == null || !file.Exists)
   5:      {
   6:          if (Source.Optional || reload) // Always optional on reload
   7:          {
   8:              Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
   9:          }
  10:          else
  11:          {
  12:              var error = new StringBuilder($"The configuration file ‘{Source.Path}‘ was not found and is not optional.");
  13:              if (!string.IsNullOrEmpty(file?.PhysicalPath))
  14:              {
  15:                  error.Append($" The physical path is ‘{file.PhysicalPath}‘.");
  16:              }
  17:              HandleException(new FileNotFoundException(error.ToString()));
  18:          }
  19:      }
  20:      else
  21:      {
  22:          // Always create new Data on reload to drop old keys
  23:          if (reload)
  24:          {
  25:              Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  26:          }
  27:          using (var stream = file.CreateReadStream())
  28:          {
  29:              try
  30:              {
  31:                  Load(stream);
  32:              }
  33:              catch (Exception e)
  34:              {
  35:                  HandleException(e);
  36:              }
  37:          }
  38:      }
  39:      // REVIEW: Should we raise this in the base as well / instead?,通过注释,我们可以知道OnReload()方法可能会在新版中发生变化
  40:      OnReload();
  41:  }
  42:   
  43:  /// <summary>
  44:  /// Loads the contents of the file at <see cref="Path"/>.
  45:  /// </summary>
  46:  /// <exception cref="FileNotFoundException">If Optional is <c>false</c> on the source and a
  47:  /// file does not exist at specified Path.</exception>
  48:  public override void Load()
  49:  {
  50:      Load(reload: false);
  51:  }

另外它还有一个特殊方法,就是参数类型为FileConfigurationSource的构造函数,其主要功能是监控文件,并在FileConfigurationSource.ReloadDelay设置的时间里重新加载文件并返回一个IDisposable类型的值,以下是该构造函数的源码:

   1:  /// <summary>
   2:  /// Initializes a new instance with the specified source.
   3:  /// </summary>
   4:  /// <param name="source">The source settings.</param>
   5:  public FileConfigurationProvider(FileConfigurationSource source)
   6:  {
   7:      if (source == null)
   8:      {
   9:          throw new ArgumentNullException(nameof(source));
  10:      }
  11:      Source = source;
  12:   
  13:      if (Source.ReloadOnChange && Source.FileProvider != null)
  14:      {
  15:          _changeTokenRegistration = ChangeToken.OnChange(
  16:              () => Source.FileProvider.Watch(Source.Path),
  17:              () => {
  18:                  Thread.Sleep(Source.ReloadDelay);
  19:                  Load(reload: true);
  20:              });
  21:      }
  22:  }

FileConfigurationExtensions

该类是一个静态类,其提供了的多个扩展方法,主要基于

  • IConfigurationBuilder
  • IFileProvider
  • Action<FileLoadExceptionContext>

包括主要用于设置或获取IFileProvider对象,前文有介绍过,是存储于字典之中,需要注意的是,在Get的时候如果字典中并不存在IFileProvider对象,则会实例化一个PhysicalFileProvider对象出来,该类位于Microsoft.Extensions.FileProviders.PhysicalFileProvider

   1:  /// <summary>
   2:  /// Sets the default <see cref="IFileProvider"/> to be used for file-based providers.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="fileProvider">The default file provider instance.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetFileProvider(this IConfigurationBuilder builder, IFileProvider fileProvider)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      builder.Properties[FileProviderKey] = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
  15:      return builder;
  16:  }
  17:   
  18:  /// <summary>
  19:  /// Gets the default <see cref="IFileProvider"/> to be used for file-based providers.
  20:  /// </summary>
  21:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
  22:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
  23:  public static IFileProvider GetFileProvider(this IConfigurationBuilder builder)
  24:  {
  25:      if (builder == null)
  26:      {
  27:          throw new ArgumentNullException(nameof(builder));
  28:      }
  29:   
  30:      if (builder.Properties.TryGetValue(FileProviderKey, out object provider))
  31:      {
  32:          return provider as IFileProvider;
  33:      }
  34:   
  35:      return new PhysicalFileProvider(AppContext.BaseDirectory ?? string.Empty);
  36:  }

为指定路径的物理文件设置文件型Provider,该方法同样基于PhysicalFileProvider,并返回IConfigurationBuilder对象

   1:  /// <summary>
   2:  /// Sets the FileProvider for file-based providers to a PhysicalFileProvider with the base path.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="basePath">The absolute path of file-based providers.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetBasePath(this IConfigurationBuilder builder, string basePath)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      if (basePath == null)
  15:      {
  16:          throw new ArgumentNullException(nameof(basePath));
  17:      }
  18:   
  19:      return builder.SetFileProvider(new PhysicalFileProvider(basePath));
  20:  }

以及异常处理,可以看到其异常处理也会存放于字典中,如果字典中找不到,就会返回空,这个地方如果直接使用,需要注意空指针问题。

   1:  /// <summary>
   2:  /// Sets a default action to be invoked for file-based providers when an error occurs.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="handler">The Action to be invoked on a file load exception.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetFileLoadExceptionHandler(this IConfigurationBuilder builder, Action<FileLoadExceptionContext> handler)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      builder.Properties[FileLoadExceptionHandlerKey] = handler;
  15:      return builder;
  16:  }
  17:   
  18:  /// <summary>
  19:  /// Gets the default <see cref="IFileProvider"/> to be used for file-based providers.
  20:  /// </summary>
  21:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
  22:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
  23:  public static Action<FileLoadExceptionContext> GetFileLoadExceptionHandler(this IConfigurationBuilder builder)
  24:  {
  25:      if (builder == null)
  26:      {
  27:          throw new ArgumentNullException(nameof(builder));
  28:      }
  29:   
  30:      if (builder.Properties.TryGetValue(FileLoadExceptionHandlerKey, out object handler))
  31:      {
  32:          return handler as Action<FileLoadExceptionContext>;
  33:      }
  34:      

return null;

  35:  }

该类还有两个静态私有变量,指定了文件Provider的Key以及文件加载异常处理Key。

   1:  private static string FileProviderKey = "FileProvider";
   2:  private static string FileLoadExceptionHandlerKey = "FileLoadExceptionHandler";

总结

文件型配置还依赖于.NET Core的其他组件Microsoft.Extensions.FileProviders和Microsoft.Extensions.Primitives。

FileProviders组件提供了文件处理的一般方法,Primitives组件提供了监控机制,同时还包括两个比较重要的结构体StringValues和StringSegment,本文暂时不做讨论,有兴趣的朋友,可以自行查看该组件源码。

原文地址:https://www.cnblogs.com/lonelyxmas/p/10891631.html

时间: 2024-10-08 07:21:17

.NET Core 3.0之深入源码理解Configuration(二)的相关文章

.NET Core 3.0之深入源码理解Configuration(一)

原文:.NET Core 3.0之深入源码理解Configuration(一) Configuration总体介绍 微软在.NET Core里设计出了全新的配置体系,并以非常灵活.可扩展的方式实现.从其源码来看,其运行机制大致是,根据其Source,创建一个Builder实例,并会向其添加Provider,在我们使用配置信息的时候,会从内存中获取相应的Provider实例. .NET Core采用了统一的调用方式来加载不同类型的配置信息,并通过统一的抽象接口IConfigurationSourc

.NET Core 3.0之深入源码理解Host(二)

写在前面 停了近一个月的技术博客,随着正式脱离996的魔窟,接下来也正式恢复了.本文从源码角度进一步讨论.NET Core 3.0 中关于Host扩展的一些技术点,主要讨论Long Run Program的创建与守护. 关于Host,我们最容易想到的就是程序的启动与停止,而其中隐藏着非常关键的功能,就是Host的初始化,我们所需要的所有资源都必须而且应该在程序启动过程中初始化完成,当然本文的主要内容并不是Host初始化,前文已经累述.当然,为了更好的守护与管理已经启动的Host,.NET Cor

.NET Core 3.0之深入源码理解Configuration(三)

写在前面 上一篇文章讨论了文件型配置的基本内容,本篇内容讨论JSON型配置的实现方式,理解了这一种配置类型的实现方式,那么其他类型的配置实现方式基本可以触类旁通.看过了上一篇文章的朋友,应该看得出来似曾相识.此图主要表达了文件型配置的实现,当然其他配置,包括自定义配置,都会按照这样的方式去实现. JSON配置组件的相关内容 该组件有四个类 JsonConfigurationExtensions JsonConfigurationSource JsonConfigurationFileParser

.NET Core 3.0之深入源码理解Startup的注册及运行

原文:.NET Core 3.0之深入源码理解Startup的注册及运行 写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程序的起点.通过使用Startup,可以配置化处理所有向应用程序所做的请求的管道,同时也可以减少.NET应用程序对单一服务器的依赖性,使我们在更大程度上专注于面向多服务器为中心的开发模式. 目录: Startup讨论 Starup所承担的角色 Startup编写规范 ConfigureServices C

Android7.0 Phone应用源码分析(二) phone来电流程分析

接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有来电通知时,首先接收到消息的是Modem层,然后Medoem再上传给RIL层,RIL进程通过sokcet将消息发送给RILJ(framework层的RIL),同样进入RILJ的processResponse方法,根据上一章节去电流程的分析得知,来电属于UnSolicited消息,事件ID是 RIL_

Android7.0 Phone应用源码分析(三) phone拒接流程分析

接上篇博文:Android7.0 Phone应用源码分析(二) phone来电流程分析 今天我们再来分析下Android7.0 的phone的拒接流程 下面先来看一下拒接电话流程时序图 步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法 com.android.incallui.AnswerFragment public void onDecline(Context context) { getPresenter().onDecline(context);

【春华秋实】深入源码理解.NET Core中Startup的注册及运行

原文:[春华秋实]深入源码理解.NET Core中Startup的注册及运行 写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程序的起点.通过使用Startup,可以配置化处理所有向应用程序所做的请求的管道,同时也可以减少.NET应用程序对单一服务器的依赖性,使我们在更大程度上专注于面向多服务器为中心的开发模式. 目录: Startup讨论 Starup所承担的角色 Startup编写规范 ConfigureServices

Android # 4.0.x(1-3) 源码 下载 编译

Android 4.0源码下载方法:repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1 官方下载页面:http://source.android.com/source/downloading.html Android SDK 4.0官方下载页面:http://developer.android.com/sdk/android-4.0.html android 4.0.3最新源码下载

eclipse 编译tomcat8.0.26的源码

第一次写东西, 如果有不对的地方,请大神指正,我会尽快修正…… 参考:http://www.cnblogs.com/lanxuezaipiao/p/3640923.html 1.从tomcat官网(http://tomcat.apache.org/)下载 源码 apache-tomcat-8.0.26-src.zip . 2.下载项目构建工具 ant (http://ant.apache.org/).解压后, 配置环境变量,并修改path值. 例如,ANT_HOME="D:\Program Fi