与服务注册一样,针对配置的设置同样可以采用三种不同的编程模式。第一种是利用WebApplicationBuilder的Host属性返回的IHostBuilder对象,它可以帮助我们设置面向宿主和应用的配置。IWebHostBuilder接口上面同样提供了一系列用来对配置进行设置的方法,我们可以将这些方法应用到WebApplicationBuilder的WebHost属性返回的IWebHostBuilder对象上。不过还是那句话,既然推荐使用Mininal API,最好还是采用最新的编程方式。(本篇提供的实例已经汇总到《ASP.NET Core 6框架揭秘-实例演示版》)

[S1513]基于环境变量的配置初始化(源代码

[S1514]以键值对形式读取和修改配置(源代码

[S1515]注册配置源(利用IWebHostBuilder)(源代码

[S1516]注册配置源(Minimal API)(源代码

[S1517]默认的承载环境(源代码

[S1518]通过配置定制承载环境(源代码

[S1519]利用WebApplicationOptions定制承载环境(源代码

[S1513]基于环境变量的配置初始化

应用启动的时候会将当前的环境变量作为配置源来创建承载最初配置数据的IConfiguration对象,但它只会选择名称以“ASPNETCORE_”为前缀的环境变量(通过静态类型Host的CreateDefaultBuilder方法创建的HostBuilder默认选择的是前缀为“DOTNET_”的环境变量)。在演示针对环境变量的初始化配置之前,需要先解决配置的消费问题,即如何获取配置数据。如下面的代码片段所示,我们设置两个环境变量,它们的名称分别为"ASPNETCORE_FOO"和"ASPNETCORE_BAR"。在调用WebApplication的CreateBuilder方法创建出WebApplicationBuilder对象之后,我们将它的Configuration属性提取出来。由调试断言可以看出这两个环境变量被成功转移到配置中了。代表承载应用的WebApplication构建出来后,其Configuration属性返回的IConfiguration对象上同样包含着相同的配置。

using System.Diagnostics;

Environment.SetEnvironmentVariable("ASPNETCORE_FOO", "123");
Environment.SetEnvironmentVariable("ASPNETCORE_BAR", "456"); var builder = WebApplication.CreateBuilder(args);
IConfiguration configuration = builder.Configuration;
Debug.Assert(configuration["foo"] == "123");
Debug.Assert(configuration["bar"] == "456"); var app = builder.Build();
configuration = app.Configuration;
Debug.Assert(configuration["foo"] == "123");
Debug.Assert(configuration["bar"] == "456");

[S1514]以键值对形式读取和修改配置

我们知道IConfiguration对象是以字典的结构来存储配置数据的,我们可以利用该对象提供的索引以键值对的形式来读取和修改配置。在ASP.NET Core应用中,我们可以通过调用定义在IWebHostBuilder接口的GetSetting方法和UseSetting方法达到相同的目的。

public interface IWebHostBuilder
{
string GetSetting(string key);
IWebHostBuilder UseSetting(string key, string value);
...
}

如下面的代码片段所示,我们可以通过利用WebApplicationBuilder的WebHost属性将对应的IWebHostBuilder对象提取出来,通过调用其GetSetting方法将以环境变量设置的配置提取出来。通过调用其UseSetting方法提供的键值对会保存到应用的配置中。配置最终的状态被固定下来后转移到了构建的WebApplication对象上。

using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseSetting("foo", "abc");
builder.WebHost.UseSetting("bar", "xyz"); Debug.Assert(builder.WebHost.GetSetting("foo") == "abc");
Debug.Assert(builder.WebHost.GetSetting("bar") == "xyz"); IConfiguration configuration = builder.Configuration;
Debug.Assert(configuration["foo"] == "abc");
Debug.Assert(configuration["bar"] == "xyz"); var app = builder.Build();
configuration = app.Configuration;
Debug.Assert(configuration["foo"] == "abc");
Debug.Assert(configuration["bar"] == "xyz");

[S1515]注册配置源(利用IWebHostBuilder)

配置系统最大的特点是可以注册不同的配置源。针对配置源的注册同样可以利用三种编程方式来实现,第一种就是利用WebApplicationBuilder的Host属性返回的IHostBuilder对象,并调用其的ConfigureHostConfiguration和ConfigureAppConfiguration方法完成针对宿主和应用的配置,其中自然包含针对配置源的注册。IWebHostBuilder接口也提供如下这个等效的ConfigureAppConfiguration方法。如代码片段所示,该方法提供的参数是一个Action<WebHostBuilderContext, IConfigurationBuilder>委托,这意味着我们可以就承载上下文对配置做针对性设置。如果提供的设置与当前承载上下文无关,我们还可以调用另一个参数类型为Action<IConfigurationBuilder>的ConfigureAppConfiguration方法重载。

public interface IWebHostBuilder
{
IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate);
} public static class WebHostBuilderExtensions
{
public static IWebHostBuilder ConfigureAppConfiguration(this IWebHostBuilder hostBuilder, Action<IConfigurationBuilder> configureDelegate);
}

我们可以利用WebApplicationBuilder的WebHost属性返回对应的IWebHostBuilder对象,并采用如下的方式利用这个对象注册配置源。

using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureAppConfiguration(config => config.AddInMemoryCollection(new Dictionary<string, string>
{
["foo"] = "123",
["bar"] = "456"
}));
var app = builder.Build();
Debug.Assert(app.Configuration["foo"] == "123");
Debug.Assert(app.Configuration["bar"] == "456");

[S1516]注册配置源(Minimal API)

由于WebApplicationBuilder的Configuration属性返回的ConfigurationManager自身就是一个IConfigurationBuilder对象,所以最直接的方式就是按照如下的方式将配置源注册到它上面,这也是我们提供的编程方式。值得一提的是,如果调用WebApplication类型的CreateBuilder或者Create方法时传入了命令行参数,会自动添加针对命令行参数的配置源。

using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string>
{
["foo"] = "123",
["bar"] = "456"
});
var app = builder.Build();
Debug.Assert(app.Configuration["foo"] == "123");
Debug.Assert(app.Configuration["bar"] == "456");

[S1517]默认的承载环境

如下面的代码片段所示,派生于IHostEnvironment接口的IWebHostEnvironment接口定义了WebRootPath和WebRootFileProvider属性,前者表示用于存放Web资源文件根目录的路径,后者则返回该路径对应的IFileProvider对象。如果我们希望外部可以采用HTTP请求的方式直接访问某个静态文件(如JavaScript、CSS和图片文件等),只需要将它存放于WebRootPath属性表示的目录之下即可。当前承载环境之间反映在WebApplicationBuilder类型如下所示的Environment属性中。代表承载应用的WebApplication类型同样具有这样一个属性。

public interface IWebHostEnvironment : IHostEnvironment
{
string WebRootPath { get; set; }
IFileProvider WebRootFileProvider { get; set; }
} public sealed class WebApplicationBuilder
{
public IWebHostEnvironment Environment { get; }
...
} public sealed class WebApplication
{
public IWebHostEnvironment Environment { get; }
...
}

我们简单介绍与承载环境相关的六个属性(包含定义在IHostEnvironment接口中的四个属性)是如何设置的。IHostEnvironment 接口的ApplicationName代表当前应用的名称,它的默认值为入口程序集的名称。EnvironmentName表示当前应用所处部署环境的名称,其中开发(Development)、预发(Staging)和产品(Production)是三种典型的部署环境。根据不同的目的可以将同一个应用部署到不同的环境中,在不同环境中部署的应用往往具有不同的设置。在默认情况下,环境的名称为“Production”。ASP.NET Core应用会将所有的内容文件存储在同一个目录下,这个目录的绝对路径通过IWebHostEnvironment接口的ContentRootPath属性来表示,而ContentRootFileProvider属性则返回针对这个目录的PhysicalFileProvider对象。部分内容文件可以直接作为Web资源(如JavaScript、CSS和图片等)供客户端以HTTP请求的方式获取,存放此种类型内容文件的绝对目录通过IWebHostEnvironment接口的WebRootPath属性来表示,而针对该目录的PhysicalFileProvider自然可以通过对应的WebRootFileProvider属性来获取。

在默认情况下,由ContentRootPath属性表示的内容文件的根目录就是当前工作目录。如果该目录下存在一个名为“wwwroot”的子目录,那么它将用来存放Web资源,WebRootPath属性将返回这个目录。如果这样的子目录不存在,那么WebRootPath属性会返回Null。针对这两个目录的默认设置体现在如下所示的代码片段中。

using System.Diagnostics;
using System.Reflection; var builder = WebApplication.CreateBuilder();
var environment = builder.Environment; Debug.Assert(Assembly.GetEntryAssembly()?.GetName().Name == environment.ApplicationName);
var currentDirectory = Directory.GetCurrentDirectory(); Debug.Assert(Equals( environment.ContentRootPath, currentDirectory));
Debug.Assert(Equals(environment.ContentRootPath, currentDirectory)); var wwwRoot = Path.Combine(currentDirectory, "wwwroot");
if (Directory.Exists(wwwRoot))
{
Debug.Assert(Equals(environment.WebRootPath, wwwRoot));
}
else
{
Debug.Assert(environment.WebRootPath == null);
} static bool Equals(string path1, string path2) =>string.Equals(path1.Trim(Path.DirectorySeparatorChar), path2.Trim(Path.DirectorySeparatorChar),StringComparison.OrdinalIgnoreCase);

[S1518]通过配置定制承载环境

IWebHostEnvironment对象承载的与承载环境相关的属性(ApplicationName、EnvironmentName、ContentRootPath和WebRootPath)可以通过配置的方式进行定制,对应配置项的名称分别为“applicationName”、“environment”、“contentRoot”和“webroot”。静态类WebHostDefaults为它们定义了对应的属性。通过第14章“服务承载”可知,前三个配置项的名称同样以静态只读字段的形式定义在HostDefaults类型中。

public static class WebHostDefaults
{
public static readonly string EnvironmentKey = "environment";
public static readonly string ContentRootKey = "contentRoot";
public static readonly string ApplicationKey = "applicationName";
public static readonly string WebRootKey = "webroot";;
} public static class HostDefaults
{
public static readonly string EnvironmentKey = "environment";
public static readonly string ContentRootKey = "contentRoot";
public static readonly string ApplicationKey = "applicationName";
}

由于应用初始化过程中的很多操作都与当前的承载环境有关,所以承载环境必须在启动应用最初的环境就被确定下来,并在整个应用生命周期内都不能改变。如果我们希望采用配置的方式来控制当前应用的承载环境,相应的设置必须在WebApplicationBuilder对象创建之前执行,在之后试图修改相关的配置都会抛出异常。按照这个原则,我们可以采用命令行参数的方式对承载环境进行设置。

var app = WebApplication.Create(args);
var environment = app.Environment; Console.WriteLine($"ApplicationName:{environment.ApplicationName}");
Console.WriteLine($"ContentRootPath:{environment.ContentRootPath}");
Console.WriteLine($"WebRootPath:{environment.WebRootPath}");
Console.WriteLine($"EnvironmentName:{environment.EnvironmentName}");

上面的演示程序利用命令行参数的方式控制承载环境的四个属性。如代码片段所示,我们将命令行参数传入WebApplication类型的Create方法创建了一个WebApplication对象,然后从中提取出代表承载环境的IWebHostEnvironment对象并将其携带信息输出到控制台上。我们命令行的方式启动该程序,并指定了与承载环境相关的四个参数。


图1 利用命令行参数定义承载环境

除了命令行参数,使用环境变量同样能达到相同的目的,当时应用的名称目前无法通过对应的配置进行设置。对于上面创建的这个演示程序,我们现在换一种方式启动它。如图2所示,在执行“dotnet run”命令启动程序之前,我们为承载环境的四个属性设置了对应的环境变量。从输出的结果可以看出,除了应用名称依然是入口程序集名称外,承载环境的其他三个属性与我们设置的环境变量是一致的。


图2 利用环境变量定义承载环境

[S1519]利用WebApplicationOptions定制承载环境

承载环境除了可以采用利用上面演示的两种方式进行设置外,我们也可以使用如下这个WebApplicationOptions配置选项。如代码片段所示,WebApplicationOptions定义了四个属性,分别代表命令行参数数组、环境名称、应用名称和内容根目录路径。WebApplicationBuilder具有如下这个参数类型为WebApplicationOptions的CreateBuilder方法。

public class WebApplicationOptions
{
public string[] Args { get; set; }
public string EnvironmentName { get; set; }
public string ApplicationName { get; set; }
public string ContentRootPath { get; set; }
} public sealed class WebApplication
{
public static WebApplicationBuilder CreateBuilder(WebApplicationOptions options);
...
}

如果利用WebApplicationOptions来对应用所在的承载环境进行设置,上面演示的程序可以改写成如下的形式。由于WebApplicationOptions并不包含WebRootPath对应的配置选项,如果程序运行后会发现承载环境的这个属性为空。由于IWebHostEnvironment服务提供的应用名称会被视为一个程序集名称,针对它的设置会影响类型的加载,所以我们基本上不会设置应用的名称。

var options = new WebApplicationOptions
{
Args = args,
ApplicationName = "MyApp",
ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "contents"),
EnvironmentName = "staging"
};
var app = WebApplication.CreateBuilder(options).Build();
var environment = app.Environment;
Console.WriteLine($"ApplicationName:{environment.ApplicationName}");
Console.WriteLine($"ContentRootPath:{environment.ContentRootPath}");
Console.WriteLine($"WebRootPath:{environment.WebRootPath}");
Console.WriteLine($"EnvironmentName:{environment.EnvironmentName}");

ASP.NET Core 6框架揭秘实例演示[25]:配置与承载环境的应用的更多相关文章

  1. ASP.NET Core 6框架揭秘实例演示[21]:如何承载你的后台服务

    借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中.任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,A ...

  2. ASP.NET Core 6框架揭秘实例演示[22]:如何承载你的后台服务[补充]

    借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中.任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,A ...

  3. ASP.NET Core 6框架揭秘实例演示[07]:文件系统

    ASP.NET Core应用具有很多读取文件的场景,如读取配置文件.静态Web资源文件(如CSS.JavaScript和图片文件等).MVC应用的视图文件,以及直接编译到程序集中的内嵌资源文件.这些文 ...

  4. ASP.NET Core 6框架揭秘实例演示[08]:配置的基本编程模式

    .NET的配置支持多样化的数据源,我们可以采用内存的变量.环境变量.命令行参数.以及各种格式的配置文件作为配置的数据来源.在对配置系统进行系统介绍之前,我们通过几个简单的实例演示一下如何将具有不同来源 ...

  5. ASP.NET Core 6框架揭秘实例演示[09]:配置绑定

    我们倾向于将IConfiguration对象转换成一个具体的对象,以面向对象的方式来使用配置,我们将这个转换过程称为配置绑定.除了将配置树叶子节点配置节的绑定为某种标量对象外,我们还可以直接将一个配置 ...

  6. ASP.NET Core 6框架揭秘实例演示[10]:Options基本编程模式

    依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式注入消费该功能的组件或者服务中.除了可以采用依赖注入的形式消费承载某种功能的服务,还可以采用相同的方式消费承载配置数据的Options对 ...

  7. ASP.NET Core 6框架揭秘实例演示[11]:诊断跟踪的几种基本编程方式

    在整个软件开发维护生命周期内,最难的不是如何将软件系统开发出来,而是在系统上线之后及时解决遇到的问题.一个好的程序员能够在系统出现问题之后马上定位错误的根源并找到正确的解决方案,一个更好的程序员能够根 ...

  8. ASP.NET Core 6框架揭秘实例演示[12]:诊断跟踪的进阶用法

    一个好的程序员能够在系统出现问题之后马上定位错误的根源并找到正确的解决方案,一个更好的程序员能够根据当前的运行状态预知未来可能发生的问题,并将问题扼杀在摇篮中.诊断跟踪能够帮助我们有效地纠错和排错&l ...

  9. ASP.NET Core 6框架揭秘实例演示[13]:日志的基本编程模式[上篇]

    <诊断跟踪的几种基本编程方式>介绍了四种常用的诊断日志框架.其实除了微软提供的这些日志框架,还有很多第三方日志框架可供我们选择,比如Log4Net.NLog和Serilog 等.虽然这些框 ...

随机推荐

  1. Hadoop文件操作常用命令

    1.创建目录 #hdfs dfs -mkidr /test 2.查询目录结构 #hdfs dfs -ls / 子命令 -R递归查看//查看具体的某个目录:例如#hdfs dfs -ls /test 3 ...

  2. C语言中各种输入函数之间的区别

    以下内容全部来自Bay(百度百科) scanf的返回值 scanf()函数返回成功赋值的数据项数,读到文件末尾出错时则返回EOF. 如: scanf("%d%d", &a, ...

  3. Solution -「AGC 019F」「AT 2705」Yes or No

    \(\mathcal{Description}\)   Link.   有 \(n+m\) 个问题,其中 \(n\) 个答案为 yes,\(m\) 个答案为 no.每次你需要回答一个问题,然后得知这个 ...

  4. 内网安全---隐藏通信隧道基础&&网络通信隧道之一ICMP隧道

    一,隐藏通信隧道基础知识 在完成信息收集之后,我们要判断流量是否出的去.进的来.隐藏通信隧道技术常用于在受限的网络环境中追踪数据流向和在非受信任的网络中实现安全的数据传输. 1.常见的隧道: .网络层 ...

  5. bugku 神秘的文件

      题目链接: https://ctf.bugku.com/challenges#%E7%A5%9E%E7%A7%98%E7%9A%84%E6%96%87%E4%BB%B6 工具准备: 1.PC 2. ...

  6. Google发布跨云Serverless管理平台Knative

    企业只要使用由Google与Pivotal.IBM.红帽和SAP等企业共同开发的跨云Serverless管理平台Knative,就能在支持Kubernetes的云平台上自由的迁移工作负载,无论是跨私有 ...

  7. Windows11中如何使用旧版本IE浏览器打开网页

    Windows11删除了旧版本IE浏览器,完全采用了Edge,但是我们进行网站测试时有时仍会用到IE浏览器,那么可以按照以下步骤启用: 1.进入Edge浏览器中,打开设置,进入默认浏览器选项下: 修改 ...

  8. QT:异常、错误

    1.Unknown module(s) in QT: xxx 原因1:我们的QT中没有安装这个Module 解决方法:Unknown module(s) 与MaintenanceTool.exe更新. ...

  9. java内存区域模型和详解

    一,概述 java虚拟机运行时数据区模型图: 主要包括:程序计数器,java虚拟机栈,本地方法栈,java 堆,方法区(元空间). 其中堆和方法区由所有线程共享的数据区:程序计数器,java虚拟机栈, ...

  10. Bugku CTF_web3

    1.打开网页,得到信息如下 2.在hackbar里构造url如下 3.得到flag 4.本题的考点在于读的懂PHP代码,并且学会构造get参数.