diff --git a/OptionsPattern.Sutdy.Experience/OptionsPattern.Sutdy.Experience.csproj b/OptionsPattern.Sutdy.Experience/OptionsPattern.Sutdy.Experience.csproj
index 5ee861d..95983b8 100644
--- a/OptionsPattern.Sutdy.Experience/OptionsPattern.Sutdy.Experience.csproj
+++ b/OptionsPattern.Sutdy.Experience/OptionsPattern.Sutdy.Experience.csproj
@@ -20,6 +20,7 @@
+
diff --git a/OptionsPattern.Sutdy.Experience/OptionsPatternTest.cs b/OptionsPattern.Sutdy.Experience/OptionsPatternTest.cs
index d4f8906..d6dabe5 100644
--- a/OptionsPattern.Sutdy.Experience/OptionsPatternTest.cs
+++ b/OptionsPattern.Sutdy.Experience/OptionsPatternTest.cs
@@ -1,13 +1,13 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Hosting.Internal;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Xunit;
namespace OptionsPattern.Sutdy.Experience
{
///
- /// 6.1 Option模式 编程体验
+ /// 6.1 配置选项 编程体验
///
public class OptionsPatternTest:IDisposable
{
@@ -20,7 +20,225 @@ namespace OptionsPattern.Sutdy.Experience
[Fact]
public void Test()
{
- testOutput.WriteLine("Option模式 编程体验");
+ testOutput.WriteLine("6.1 配置选项 编程体验");
+ }
+
+ ///
+ /// 将配置绑定为 Option 对象
+ ///
+ [Fact]
+ public void BindConfiguration_As_OptionsObject_Test()
+ {
+ var configuration = new ConfigurationBuilder().AddJsonFile("Configs/appsettings.json",false,true).Build();
+
+ var appOption = new ServiceCollection()
+ .AddOptions()
+ .Configure(configuration)
+ .BuildServiceProvider()
+ .GetRequiredService>().Value;
+
+ Assert.NotNull(configuration);
+ Assert.NotNull(appOption);
+
+ Assert.Equal("JsonAppNmae", appOption.AppName);
+ Assert.Equal(new Version(0,0,0,1), appOption.AppVersion);
+ Assert.Equal("json@163.com", appOption.EMail?.ReceiveAddress);
+ Assert.Equal("json", appOption.EMail?.Recipient);
+
+ testOutput.WriteLine("将配置绑定为 Option 对象");
+ }
+
+ ///
+ /// 提供具名的 Options 对象
+ ///
+ [Fact]
+ public void Provide_NamedOptionsObject_Test()
+ {
+ var memoryData = new Dictionary()
+ {
+ ["One:AppName"] = "OneAppName",
+ ["One:AppVersion"] = "1.1.1.1",
+ ["One:EMail:ReceiveAddress"] = "One@163.com",
+ ["One:EMail:Recipient"] = "One",
+
+ ["Two:AppName"] = "TwoAppName",
+ ["Two:AppVersion"] = "2.2.2.2",
+ ["Two:EMail:ReceiveAddress"] = "Two@163.com",
+ ["Two:EMail:Recipient"] = "Two",
+ };
+
+ var configuration = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
+
+ var serviceProvider = new ServiceCollection()
+ .AddOptions()
+ .Configure("One", configuration.GetSection("One"))
+ .Configure("Two", configuration.GetSection("Two"))
+ .BuildServiceProvider();
+
+ var optionsSnapshot = serviceProvider.GetRequiredService>();
+
+ var one = optionsSnapshot.Get("One");
+ var two = optionsSnapshot.Get("Two");
+
+ Assert.NotNull(one);
+ Assert.NotNull(two);
+
+ Assert.Equal("OneAppName", one.AppName);
+ Assert.Equal(new Version(1,1,1,1), one.AppVersion);
+ Assert.Equal("One@163.com", one.EMail?.ReceiveAddress);
+ Assert.Equal("One", one.EMail?.Recipient);
+
+ Assert.Equal("TwoAppName", two.AppName);
+ Assert.Equal(new Version(2, 2, 2, 2), two.AppVersion);
+ Assert.Equal("Two@163.com", two.EMail?.ReceiveAddress);
+ Assert.Equal("Two", two.EMail?.Recipient);
+
+ testOutput.WriteLine("提供具名的 Options 对象");
+ }
+
+ ///
+ /// 直接初始化 Options 对象
+ /// (不使用IConfiguration)
+ ///
+ [Fact]
+ public void IniOptions_NoConfiguration_Test()
+ {
+ var appOption = new ServiceCollection()
+ .AddOptions()
+ .Configure(configOption =>
+ {
+ configOption.AppName = "NoConfigurationAppName";
+ configOption.AppVersion = new Version(0, 0, 0, 1);
+ configOption.EMail = new ReceiveMailOption()
+ {
+ ReceiveAddress = "NoConfigurationAppName@163.com",
+ Recipient = "NoConfigurationAppName",
+ };
+ })
+ .BuildServiceProvider()
+ .GetRequiredService>().Value;
+
+ Assert.NotNull(appOption);
+
+ Assert.Equal("NoConfigurationAppName", appOption.AppName);
+ Assert.Equal(new Version(0, 0, 0, 1), appOption.AppVersion);
+ Assert.Equal("NoConfigurationAppName@163.com", appOption.EMail?.ReceiveAddress);
+ Assert.Equal("NoConfigurationAppName", appOption.EMail?.Recipient);
+
+ testOutput.WriteLine("直接初始化 Options 对象");
+ }
+
+ ///
+ /// 根据依赖服务的 Options 设置
+ ///
+ [Theory]
+ [InlineData("pro")]
+ [InlineData("dev")]
+ [InlineData("test")]
+ public void SetOptions_By_DependentService_Test(string environmentName)
+ {
+ var services = new ServiceCollection();
+ services
+ .AddSingleton(new HostingEnvironment() { EnvironmentName = environmentName })
+ .AddOptions()// AddOptions() 与 AddOptions() 返回的类型不一样。之后的 Configure 扩展不一样
+ .Configure((appOption, hostEnv) => // 泛型参数确定 Action 参数
+ {
+ appOption.AppName = hostEnv.EnvironmentName + nameof(appOption.AppName);
+ appOption.AppVersion = new Version();
+ appOption.EMail = new ReceiveMailOption()
+ {
+ ReceiveAddress = $"{hostEnv.EnvironmentName}@163.com",
+ Recipient = hostEnv.EnvironmentName,
+ };
+ });
+ var appOption = services
+ .BuildServiceProvider()
+ .GetRequiredService< IOptions >()
+ .Value;
+
+
+ Assert.NotNull(appOption);
+ Assert.Equal($"{environmentName}AppName",appOption.AppName);
+ Assert.Equal(new Version(),appOption.AppVersion);
+ Assert.Equal($"{environmentName}@163.com",appOption.EMail?.ReceiveAddress);
+ Assert.Equal($"{environmentName}",appOption.EMail?.Recipient);
+
+ testOutput.WriteLine("根据依赖服务的 Options 设置");
+ }
+
+ ///
+ /// 验证 Options 的有效性:通过
+ ///
+ [Fact]
+ public void Validate_Options_Success_Test()
+ {
+ var services = new ServiceCollection();
+ services
+ .AddOptions()
+ .Configure(configOption =>
+ {
+ configOption.AppName = "ValidateAppName";
+ configOption.AppVersion = new Version(0, 0, 0, 1);
+ configOption.EMail = new ReceiveMailOption()
+ {
+ ReceiveAddress = "Validate@163.com",
+ Recipient = "Validate",
+ };
+ })
+ .Validate(option =>
+ {
+ return true;
+ });
+
+ //不发生异常
+ Action codeSnippet = () =>
+ {
+ _ = services
+ .BuildServiceProvider()
+ .GetService>()
+ ?.Value;
+ };
+
+ var exception = Record.Exception(codeSnippet);
+ Assert.Null(exception);
+
+ testOutput.WriteLine("验证 Options 的有效性:通过");
+ }
+
+ ///
+ /// 验证 Options 的有效性:无效并引发异常
+ ///
+ [Fact]
+ public void Validate_Options_Fail_Test()
+ {
+ var services = new ServiceCollection();
+ services
+ .AddOptions()
+ .Configure(configOption =>
+ {
+ configOption.AppName = "ValidateAppName";
+ configOption.AppVersion = new Version(0, 0, 0, 1);
+ configOption.EMail = new ReceiveMailOption()
+ {
+ ReceiveAddress = "Validate@163.com",
+ Recipient = "Validate",
+ };
+ })
+ .Validate(option => //返回false,表示验证错误,会抛出异常
+ {
+ return false;
+ });
+
+ //引发异常
+ Assert.Throws(() =>
+ {
+ _ = services
+ .BuildServiceProvider()
+ .GetService>()
+ ?.Value;
+ });
+
+ testOutput.WriteLine("验证 Options 的有效性:无效并引发异常");
}
public void Dispose()
diff --git a/OptionsPattern.Sutdy.Experience/Startup.cs b/OptionsPattern.Sutdy.Experience/Startup.cs
index 04de861..6e95ca1 100644
--- a/OptionsPattern.Sutdy.Experience/Startup.cs
+++ b/OptionsPattern.Sutdy.Experience/Startup.cs
@@ -34,31 +34,16 @@ namespace OptionsPattern.Sutdy.Experience
//设置主机配置
hostBuilder.ConfigureHostConfiguration(builder =>
{
-
+
});
//设置应用配置
hostBuilder.ConfigureAppConfiguration((context, builder) =>
{
-
+
});
-
- //集成 Opentelemetry
- //var tracerProvider = Sdk.CreateTracerProviderBuilder()
- // .AddSource("Xunit.DependencyInjection")
- // .AddConsoleExporter();
-
}
- ///
- /// 配置服务方法
- /// (不支持重载)
- ///
- //public void ConfigureServices(IServiceCollection services)
- //{
-
- //}
-
///
/// 配置服务方法
/// 注入或用途 IConfiguration IHostEnvironment 请使用 context.xx;
@@ -66,7 +51,6 @@ namespace OptionsPattern.Sutdy.Experience
public void ConfigureServices(IServiceCollection services, HostBuilderContext context)
{
-
}
///
diff --git a/OptionsPattern.Sutdy.Experience/Usings.cs b/OptionsPattern.Sutdy.Experience/Usings.cs
index ce36fb1..7c4f0e9 100644
--- a/OptionsPattern.Sutdy.Experience/Usings.cs
+++ b/OptionsPattern.Sutdy.Experience/Usings.cs
@@ -7,6 +7,8 @@ global using System.Collections.Generic;
global using System.Collections.Concurrent;
global using System.Collections.Specialized;
+global using Microsoft.Extensions.DependencyInjection;
+
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.Configuration.Memory;
global using Microsoft.Extensions.Configuration.EnvironmentVariables;