更新:配置绑定

master
bicijinlian 2 years ago
parent ba684e5056
commit 95ce7980b6

@ -58,7 +58,7 @@ namespace OptionStudy.Next
Action run = () =>
{
provider.Set("TestName", "UpdateName");
if (!provider.TryGet("Demo", out string _v))
if (!provider.TryGet("Demo", out var _v))
{
provider.Add("Demo", "demo");
}
@ -88,7 +88,7 @@ namespace OptionStudy.Next
};
var provider = source.Build(null);
var provider = source.Build(new ConfigurationBuilder());
var hasName = provider.TryGet("AppName", out _);
Assert.NotNull(provider);

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OptionStudy.Next
{
[TypeConverter(typeof(PointTypeConverter))]
public readonly record struct Point(double x, double y);
}

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OptionStudy.Next
{
public class PointTypeConverter: TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
var split = (value.ToString()??"0.0,0.0").Split(',');
double x = double.Parse(split[0].Trim().TrimStart('('));
double y = double.Parse(split[1].Trim().TrimEnd(')'));
return new Point(x, y);
}
}
}

@ -0,0 +1,265 @@

using OptionStudy.UnitApp.Next;
namespace OptionStudy.Next._3
{
/// <summary>
/// 配置绑定 测试
/// 引用 Microsoft.Extensions.Configuration.Binder 包
/// </summary>
public class ConfigBinderTest : IDisposable
{
private readonly ITestOutputHelper testOutput;
public ConfigBinderTest(ITestOutputHelper testOutputHelper)
{
this.testOutput = testOutputHelper;
}
/// <summary>
/// 绑定配置项的值
/// </summary>
[Fact]
public void Binder_ConfigItem_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["AppName"] = "MemoryAppName",
["AppVersion"] = "0.0.0.1",
["EMail:ReceiveAddress"] = "memory@163.com",
["EMail:Recipient"] = "memory",
["foo"] = null,
["bar"] = "",
["baz"] = "123",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
//针对 object : 直接返回原始值字符串或null
Assert.Null(root.GetValue<object>("foo"));
Assert.Equal(string.Empty, root.GetValue<object>("bar"));
Assert.Equal("123", root.GetValue<object>("baz"));
//针对普通类型: 针对类型的 TypeConverter 来 完成类型转换
Assert.Equal(0,root.GetValue<int>("foo"));
Assert.Equal(123, root.GetValue<int>("baz"));
//针对 Nullable<T> 类型:原始值为""或null时返回null,否则转换成基础类型。匹配不了了,则借值为 Default(T)
Assert.Null(root.GetValue<int?>("foo"));
Assert.Null(root.GetValue<int?>("bar"));
testOutput.WriteLine("绑定配置项的值");
}
/// <summary>
/// 绑定配置项的值,使用自定义转换器
/// </summary>
[Fact]
public void Binder_ConfigItem_CustomConverter_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["Point"] = "(123,456)",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var point = root.GetValue<Point>("Point");
Assert.Equal(123, point.x);
Assert.Equal(456,point.y);
testOutput.WriteLine("绑定配置项的值,使用自定义转换器");
}
/// <summary>
/// 绑定复合对象
/// 自定义的类或结构等对象
/// </summary>
[Fact]
public void Binder_ComplexObject_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["AppName"] = "MemoryAppName",
["AppVersion"] = "0.0.0.1",
["EMail:ReceiveAddress"] = "memory@163.com",
["EMail:Recipient"] = "memory",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var appOption = root.Get<AppOption>();
Assert.Equal("MemoryAppName", appOption.AppName);
Assert.Equal("0.0.0.1", appOption.AppVersion.ToString());
Assert.Equal("memory@163.com", appOption.EMail?.ReceiveAddress);
Assert.Equal("memory", appOption.EMail?.Recipient);
var email = root.GetSection("EMail").Get<ReceiveMailOption>();
Assert.Equal("memory@163.com", email.ReceiveAddress);
Assert.Equal("memory", email.Recipient);
testOutput.WriteLine("绑定复合对象");
}
/// <summary>
/// 绑定集合(包括数组)
/// </summary>
[Fact]
public void Binder_Set_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["0:AppName"] = "MemoryAppName",
["0:AppVersion"] = "0.0.0.1",
["0:EMail:ReceiveAddress"] = "memory@163.com",
["0:EMail:Recipient"] = "memory",
["1:AppName"] = "MemoryAppName",
["1:AppVersion"] = "0.0.0.1",
["1:EMail:ReceiveAddress"] = "memory@163.com",
["1:EMail:Recipient"] = "memory",
["2;AppName"] = "MemoryAppName",
["2;AppVersion"] = "0.0.0.1",
["2;EMail:ReceiveAddress"] = "memory@163.com",
["2;EMail:Recipient"] = "memory",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var appOptions = root.Get<IList<AppOption>>();
Assert.Equal("MemoryAppName", appOptions[0].AppName);
Assert.Equal("0.0.0.1", appOptions[0].AppVersion.ToString());
Assert.Equal("memory@163.com", appOptions[0].EMail?.ReceiveAddress);
Assert.Equal("memory", appOptions[0].EMail?.Recipient);
Assert.Equal("MemoryAppName", appOptions[1].AppName);
Assert.Equal("0.0.0.1", appOptions[1].AppVersion.ToString());
Assert.Equal("memory@163.com", appOptions[1].EMail?.ReceiveAddress);
Assert.Equal("memory", appOptions[1].EMail?.Recipient);
Assert.Equal("MemoryAppName", appOptions[1].AppName);
Assert.Equal("0.0.0.1", appOptions[1].AppVersion.ToString());
Assert.Equal("memory@163.com", appOptions[1].EMail?.ReceiveAddress);
Assert.Equal("memory", appOptions[1].EMail?.Recipient);
testOutput.WriteLine("绑定集合(包括数组)");
}
/// <summary>
/// 绑定集合与数组的差别
/// 某项绑定失败,不影响其它项绑定,但是数组表现为空项而集合表现为忽略失败项
/// </summary>
[Fact]
public void Binder_CollectionAndArray_Differences_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["0:AppName"] = "0MemoryAppName",
["0:AppVersion"] = "0.0.0.1",
["1:AppName"] = "1MemoryAppName",
["1:AppVersion"] = "A.B.C.D", //此项改为非版本数值,故意出错
["2:AppName"] = "2MemoryAppName",
["2:AppVersion"] = "2.1.2.3",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var list = root.Get<IList<AppOption>>();
var array = root.Get<AppOption[]>();
Assert.Equal(2, list.Count);
Assert.Equal(3, array.Length);
Assert.Null(array[1]);
testOutput.WriteLine("绑定集合与数组的差别");
}
/// <summary>
/// 绑定字典
/// </summary>
[Fact]
public void Binder_Dictionary_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["One:AppName"] = "0MemoryAppName",
["One:AppVersion"] = "0.0.0.1",
["One:EMail:ReceiveAddress"] = "memory@163.com",
["One:EMail:Recipient"] = "memory",
["Two:AppName"] = "1MemoryAppName",
["Two:AppVersion"] = "1.2.3.4",
["Two:EMail:ReceiveAddress"] = "1@163.com",
["Two:EMail:Recipient"] = "memory1",
["Three:AppName"] = "2MemoryAppName",
["Three:AppVersion"] = "2.0.0.0",
["Three:EMail:ReceiveAddress"] = "2@163.com",
["Three:EMail:Recipient"] = "memory2",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
var dic = root.Get<IDictionary<string,AppOption>>();
Assert.Equal(3, dic.Count);
Assert.Equal("0MemoryAppName", dic["One"].AppName);
Assert.Equal("1MemoryAppName", dic["Two"].AppName);
Assert.Equal("2MemoryAppName", dic["Three"].AppName);
testOutput.WriteLine("绑定字典");
}
/// <summary>
/// 绑定字典有错
/// 存在转换错误时,抛出异常
/// </summary>
[Fact]
public void Binder_Dictionary_HasError_Test()
{
IDictionary<string, string?> memoryData = new Dictionary<string, string?>()
{
["One:AppName"] = "0MemoryAppName",
["One:AppVersion"] = "0.0.0.1",
["One:EMail:ReceiveAddress"] = "memory@163.com",
["One:EMail:Recipient"] = "memory",
["Two:AppName"] = "1MemoryAppName",
["Two:AppVersion"] = "A.B.C.D", //此项改为非版本数值,故意出错
["Two:EMail:ReceiveAddress"] = "1@163.com",
["Two:EMail:Recipient"] = "memory1",
["Three:AppName"] = "2MemoryAppName",
["Three:AppVersion"] = "2.0.0.0",
["Three:EMail:ReceiveAddress"] = "2@163.com",
["Three:EMail:Recipient"] = "memory2",
};
var root = new ConfigurationBuilder().AddInMemoryCollection(memoryData).Build();
//["Two:AppVersion"] = "A.B.C.D"值不能转换成版本类,会抛出异常
Action getConfigDic = () =>
{
root.Get<IDictionary<string, AppOption>>();
};
Assert.Throws<InvalidOperationException>(getConfigDic);
testOutput.WriteLine("绑定字典:存在转换错误时,抛出异常!");
}
public void Dispose()
{
}
}
}

@ -20,7 +20,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Xml" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="Moq" Version="4.18.3" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="Xunit.DependencyInjection" Version="8.6.1" />
@ -62,7 +62,6 @@
<ItemGroup>
<Folder Include="5多样性配置源\" />
<Folder Include="4配置同步\" />
<Folder Include="3配置绑定\" />
</ItemGroup>
</Project>

@ -16,7 +16,7 @@ namespace OptionStudy.UnitApp.Next
/// <summary>
/// 软件版本
/// </summary>
public string AppVersion { get; set; } = "0.0.0.1";
public Version AppVersion { get; set; } = new Version( "0.0.0.1");
/// <summary>
/// 接收邮箱配置对象

Loading…
Cancel
Save