[ASP.NET Core 3框架揭秘] Options[2]: 配置选项的正确使用方式[下篇]
四、直接初始化Options对象
前面演示的几个实例具有一个共同的特征,即都采用配置系统来提供绑定Options对象的原始数据,实际上,Options框架具有一个完全独立的模型,可以称为Options模型。这个独立的Options模型本身并不依赖于配置系统,让配置系统来提供配置数据仅仅是通过Options模型的一个扩展点实现的。在很多情况下,可能并不需要将应用的配置选项定义在配置文件中,在应用启动时直接初始化可能是一种更方便快捷的方式。
class Program
{
static void Main()
{
var profile = new ServiceCollection()
.AddOptions()
.Configure<Profile>(it =>
{
it.Gender = Gender.Male;
it.Age = 18;
it.ContactInfo = new ContactInfo
{
PhoneNo = "123456789",
EmailAddress = "foobar@outlook.com"
};
})
.BuildServiceProvider()
.GetRequiredService<IOptions<Profile>>()
.Value; Console.WriteLine($"Gender: {profile.Gender}");
Console.WriteLine($"Age: {profile.Age}");
Console.WriteLine($"Email Address: {profile.ContactInfo.EmailAddress}");
Console.WriteLine($"Phone No: {profile.ContactInfo.PhoneNo}\n");
}
}
我们依然沿用前面演示的应用场景,现在摒弃配置文件,转而采用编程的方式直接对用户信息进行初始化,所以需要对程序做如上改写。在调用IServiceCollection接口的Configure<Profile>扩展方法时,不需要再指定一个IConfiguration对象,而是利用一个Action<Profile>类型的委托对作为参数的Profile对象进行初始化。程序运行后会在控制台上产生下图所示的输出结果。

具名Options同样可以采用类似的方式进行初始化。如果需要根据指定的名称对Options进行初始化,那么调用方法时就需要指定一个Action<TOptions,String>类型的委托对象,该委托对象的第二个参数表示Options的名称。在如下所示的代码片段中,我们通过类似的方式设置了两个用户(foo和bar)的信息,然后利用IOptionsSnapshot<TOptions>服务将它们分别提取出来。
class Program
{
static void Main()
{
var optionsAccessor = new ServiceCollection()
.AddOptions()
.Configure<Profile>("foo", it =>
{
it.Gender = Gender.Male;
it.Age = 18;
it.ContactInfo = new ContactInfo
{
PhoneNo = "123",
EmailAddress = "foo@outlook.com"
};
})
.Configure<Profile>("bar", it =>
{
it.Gender = Gender.Female;
it.Age = 25;
it.ContactInfo = new ContactInfo
{
PhoneNo = "456",
EmailAddress = "bar@outlook.com"
};
})
.BuildServiceProvider()
.GetRequiredService<IOptionsSnapshot<Profile>>(); Print(optionsAccessor.Get("foo"));
Print(optionsAccessor.Get("bar")); static void Print(Profile profile)
{
Console.WriteLine($"Gender: {profile.Gender}");
Console.WriteLine($"Age: {profile.Age}");
Console.WriteLine($"Email Address: {profile.ContactInfo.EmailAddress}");
Console.WriteLine($"Phone No: {profile.ContactInfo.PhoneNo}\n");
};
}
}
该程序运行后会在控制台上产生下图所示的输出结果。在前面的演示中,我们利用依赖注入框架提供IOptions<TOptions>服务、IOptionsSnapshot<TOptions>服务和IOptionsMonitor<TOptions>服务,然后进一步利用它们来提供对应的Options对象。既然作为依赖注入容器的IServiceProvider对象能够提供这3个对象,我们就能够将它们注入消费Options对象的类型中。所谓的Options模式就是通过注入这3个服务来提供对应Options对象的编程模式。

五、根据依赖服务的Options设置
在很多情况下需要针对某个依赖的服务动态地初始化Options的设置,比较典型的就是根据当前的承载环境(开发、预发和产品)对Options做动态设置。《上篇》演示了一系列针对时间日期输出格式的配置,下面沿用这个场景演示如何根据当前的承载环境设置对应的Options。将DateTimeFormatOptions的定义进行简化,只保留如下所示的表示日期和时间格式的两个属性。
public class DateTimeFormatOptions
{
public string DatePattern { get; set; }
public string TimePattern { get; set; }
public override string ToString() => $"Date: {DatePattern}; Time: {TimePattern}";
}
如下所示的代码片段是整个演示实例的完整定义。我们利用第6章介绍的配置系统来设置当前的承载环境,具体采用的是基于命令行参数的配置源。.NET Core的承载系统通过IHostEnvironment接口表示承载环境,具体实现类型为HostingEnvironment。如下面的代码片段所示,我们利用获取的环境名称创建了一个HostingEnvironment对象,并针对IHostEnvironment接口采用Singleton生命周期做了相应的注册。
class Program
{
public static void Main(string[] args)
{
var environment = new ConfigurationBuilder()
.AddCommandLine(args)
.Build()["env"]; var services = new ServiceCollection();
services
.AddSingleton<IHostEnvironment>(new HostingEnvironment { EnvironmentName = environment })
.AddOptions<DateTimeFormatOptions>().Configure<IHostEnvironment>( (options, env) => {
if (env.IsDevelopment())
{
options.DatePattern = "dddd, MMMM d, yyyy";
options.TimePattern = "M/d/yyyy";
}
else
{
options.DatePattern = "M/d/yyyy";
options.TimePattern = "h:mm tt";
}
}); var options = services
.BuildServiceProvider()
.GetRequiredService<IOptions<DateTimeFormatOptions>>().Value;
Console.WriteLine(options);
}
}
上面调用IServiceCollection接口的AddOptions<DateTimeFormatOptions>扩展方法完成了针对Options模型核心服务的注册和针对DateTimeFormatOptions的设置。该方法返回的是一个封装了IServiceCollection集合的OptionsBuilder<DateTimeFormatOptions>对象,可以调用其Configure<IHostEnvironment>方法利用提供的Action<DateTimeFormatOptions, IHostEnvironment>委托对象针对依赖的IHostEnvironment服务对DateTimeFormatOptions做相应的设置。具体来说,我们针对开发环境和非开发环境设置了不同的日期时间格式。如果采用命令行的方式启动这个应用程序,并利用命令行参数设置不同的环境名称,就可以在控制台上看到下图所示的针对DateTimeFormatOptions的不同设置。

六、验证Options的有效性
由于配置选项是整个应用的全局设置,为了尽可能避免错误的设置造成的影响,最好能够对内容进行有效性验证。接下来我们将上面的程序做了如下改动,从而演示如何对设置的日期和时间格式做最后的有效性验证。
class Program
{
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var datePattern = config["date"];
var timePattern = config["time"]; var services = new ServiceCollection();
services.AddOptions<DateTimeFormatOptions>()
.Configure(options =>
{
options.DatePattern = datePattern;
options.TimePattern = timePattern;
})
.Validate(options => Validate(options.DatePattern) && Validate(options.TimePattern),"Invalid Date or Time pattern.");
try
{
var options = services
.BuildServiceProvider()
.GetRequiredService<IOptions<DateTimeFormatOptions>>().Value;
Console.WriteLine(options);
}
catch (OptionsValidationException ex)
{
Console.WriteLine(ex.Message);
} static bool Validate(string format)
{
var time = new DateTime(1981, 8, 24,2,2,2);
var formatted = time.ToString(format);
return DateTimeOffset.TryParseExact(formatted, format, null, DateTimeStyles.None, out var value) && (value.Date == time.Date || value.TimeOfDay == time.TimeOfDay);
}
}
}
上述演示实例借助配置系统以命令行的形式提供了日期和时间格式化字符串。在创建了OptionsBuilder<DateTimeFormatOptions>对象并对DateTimeFormatOptions做了相应设置之后,我们调用Validate<DateTimeFormatOptions>方法利用提供的Func<DateTimeFormatOptions,bool>委托对象对最终的设置进行验证。运行该程序并按照下图所示的方式指定不同的格式化字符串,系统会根据我们指定的规则来验证其有效性。

[ASP.NET Core 3框架揭秘] Options[1]: 配置选项的正确使用方式[上篇]
[ASP.NET Core 3框架揭秘] Options[2]: 配置选项的正确使用方式[下篇]
[ASP.NET Core 3框架揭秘] Options[3]: Options模型[上篇]
[ASP.NET Core 3框架揭秘] Options[4]: Options模型[下篇]
[ASP.NET Core 3框架揭秘] Options[5]: 依赖注入
[ASP.NET Core 3框架揭秘] Options[6]: 扩展与定制
[ASP.NET Core 3框架揭秘] Options[7]: 与配置系统的整合
[ASP.NET Core 3框架揭秘] Options[2]: 配置选项的正确使用方式[下篇]的更多相关文章
- [ASP.NET Core 3框架揭秘] Options[1]: 配置选项的正确使用方式[上篇]
依赖注入不仅是支撑整个ASP.NET Core框架的基石,也是开发ASP.NET Core应用采用的基本编程模式,所以依赖注入十分重要.依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式 ...
- 《ASP.NET Core 3框架揭秘》博文汇总
在过去一段时间内,写了一系列关于ASP.NET Core 3相关的文章,其中绝大部分来源于即将出版的<ASP.NET Core 3框架揭秘>(博文只能算是"初稿",与书 ...
- ASP.NET Core 6框架揭秘实例演示[10]:Options基本编程模式
依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式注入消费该功能的组件或者服务中.除了可以采用依赖注入的形式消费承载某种功能的服务,还可以采用相同的方式消费承载配置数据的Options对 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[5]: 利用容器提供服务
毫不夸张地说,整个ASP.NET Core框架是建立在依赖注入框架之上的.ASP.NET Core应用在启动时构建管道以及利用该管道处理每个请求过程中使用到的服务对象均来源于依赖注入容器.该依赖注入容 ...
- [ASP.NET Core 3框架揭秘] 文件系统[1]:抽象的“文件系统”
ASP.NET Core应用 具有很多读取文件的场景,比如配置文件.静态Web资源文件(比如CSS.JavaScript和图片文件等)以及MVC应用的View文件,甚至是直接编译到程序集中的内嵌资源文 ...
- [ASP.NET Core 3框架揭秘] 配置[1]:读取配置数据[上篇]
提到"配置"二字,我想绝大部分.NET开发人员脑海中会立即浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化 ...
- [ASP.NET Core 3框架揭秘] 配置[2]:读取配置数据[下篇]
[接上篇]提到“配置”二字,我想绝大部分.NET开发人员脑海中会立即浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义 ...
- [ASP.NET Core 3框架揭秘] 配置[6]:多样化的配置源[上篇]
.NET Core采用的这个全新的配置模型的一个主要的特点就是对多种不同配置源的支持.我们可以将内存变量.命令行参数.环境变量和物理文件作为原始配置数据的来源.如果采用物理文件作为配置源,我们可以选择 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[10]:与第三方依赖注入框架的适配
.NET Core具有一个承载(Hosting)系统,承载需要在后台长时间运行的服务,一个ASP.NET Core应用仅仅是该系统承载的一种服务而已.承载系统总是采用依赖注入的方式来消费它在服务承载过 ...
随机推荐
- linux自动挂载NTFS格式移动硬盘
转自:http://blog.163.com/cmh_lj/blog/static/100812304201252522119264/ 由于移动硬盘还有不少的资料,刚插入移动硬盘的时候发现只能自动挂载 ...
- oracle 识别’低效执行’的SQL语句
用下列SQL工具找出低效SQL: SELECT EXECUTIONS , DISK_READS, BUFFER_GETS, ROUND((BUFFER_GETS-DISK_READS)/BUFFER_ ...
- iptables禁止QQ端口
#iptables -D FORWARD -p udp --dport 8000 -j REJECT
- HDU1711 Number Sequence 题解 KMP算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 题目大意:最基础的字符串匹配,只不过这里用整数数组代替了字符串. 给你两个数组 \(a[1..N ...
- JavaScript 按位与和逻辑与
逻辑与操作符有两个和好(&&)表示,有两个操作数,如下面的例子所示: var result = true && false; 第一个操作数 第二个操作数 结果 tr ...
- Spring Cloud探路(二) Erueka客户端的建立
接上篇 1.pom.xml与上篇一致 2.新建包及Application启动类 @Configuration @ComponentScan @EnableEurekaClient @EnableAut ...
- java编程规范大全
JAVA编程规范大全 命名规范 定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,减少项目组中因为换人而带来的损失.(这些规范并不是一定要绝对遵守,但是一定要让程序有良好的可读性 ...
- Linux 内核引用计数的操作
一个 kobject 的其中一个关键函数是作为一个引用计数器, 给一个它被嵌入的对象. 只 要对这个对象的引用存在, 这个对象( 和支持它的代码) 必须继续存在. 来操作一个 kobject 的引用计 ...
- CSS兼容性问题的解决方式(更新中···)
1.清除浮动的兼容性(低版本的浏览器不兼容问题) .clearfix:after{ content:""; clear:both; display:block; visibilit ...
- 第二阶段:4.商业需求文档MRD:6.PRD-其他需求