[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应用仅仅是该系统承载的一种服务而已.承载系统总是采用依赖注入的方式来消费它在服务承载过 ...
随机推荐
- vue3——vue数据循环渲染
博客地址 :https://www.cnblogs.com/sandraryan/ vue循环渲染 <!DOCTYPE html> <html lang="en" ...
- 第二次 C++作业
1.为什么要用函数? 函数是相对独立的,经常使用的功能抽象化表现形式,函数的优势在于,编写之后可以被重复使用,使用时可以只关心函数的功能和使用方法而不必关心函数的具体实现,这样可以有利于代码重用,可以 ...
- 【tensorflow】】模型优化(一)指数衰减学习率
指数衰减学习率是先使用较大的学习率来快速得到一个较优的解,然后随着迭代的继续,逐步减小学习率,使得模型在训练后期更加稳定.在训练神经网络时,需要设置学习率(learning rate)控制参数的更新速 ...
- iptables禁止ssh端口
只允许在192.168.62.1上使用ssh远程登录,从其它计算机上禁止使用ssh #iptables -A INPUT -s 192.168.62.1 -p tcp --dport 22 -j AC ...
- ACM感想、
从15年10月开始搞ACM,到如今的16年4月底,已经接近半年了. 大一下学期开始ACM组的人员就不断减少,有的因为坚持不下,有的因为不喜欢,有的没留下理由就走了, 瞬间感觉实验室空了很多很多.现在常 ...
- TP5 在模板读出Session值
模板取值: <p class="info">后台登录中心{$Request.session.username}</p> 也可以 {$Think.sessio ...
- java基本类型和String之间的转换
String → 基本类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量: 基本类型 → String,String ...
- [转]爬虫 selenium + phantomjs / chrome
目录 selenium 模块 安装 phantomjs 浏览器 安装 chromedriver 接口 安装 对比两个接口 整合使用 基本实例 常用属性方法 定位节点 节点操作 其他操作 实例解析 - ...
- H3C 动态路由协议的基本原理
- JSON怎样添加注释
今天在写一个程序的时候发现了一个问题,在json文件中添加注释之后,程序就出现bug了 于是,去搜了一下这个问题的相关解释,在这里和大家分享一下: JSON为什么不能添加注释? 这位外国友人给出的解释 ...