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 配置选项 编程体验 /// public class OptionsPatternTest:IDisposable { private readonly ITestOutputHelper testOutput; public OptionsPatternTest(ITestOutputHelper outputHelper) { testOutput = outputHelper; } [Fact] public void Test() { 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("JsonAppName", 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() { } } }