[Asp.net 5] Configuration-新一代的配置文件(神奇的Binder)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了[Asp.net 5] Configuration-新一代的配置文件(神奇的Binder),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7681字,纯文字阅读大概需要11分钟。
内容图文
之前看过MVC4.0的源码,里面就有Binder。作用是将前台页面传递过来的键值对/字典表绑定到特定的对象。此处的Binder几乎是同样的作用——将IConfiguration映射为特定的类型<T>.
我们进入正文之前还是看一个例子比较好,这样能充分了解Binder。
public class ComplexOptions { public ComplexOptions() { Virtual = "complex"; } publicint Integer { get; set; } publicbool Boolean { get; set; } publicvirtualstring Virtual { get; set; } } publicclass Test { public IConfiguration BuildConfiguration() { var dic = new Dictionary<string, string> { {"Integer", "-2"}, {"Boolean", "TRUe"}, {"Nested:Integer", "11"} }; var builder = new ConfigurationBuilder(new MemoryConfigurationSource(dic)); return config = builder.Build(); } publicvoid BinderTest() { var config = BuildConfiguration(); var options = ConfigurationBinder.Bind<ComplexOptions>(config); Assert.True(options.Boolean); Assert.Equal(-2, options.Integer); } }
上面例子比较简单,实际上对象可能是复合对象(对象的属性还是对象),也可能是数组、枚举、结构体等。所以我们创建的过程中需要对属性遍历,如果是复合对象,还涉及到递归的过程,所以我把整个过程绘制成类似流程图的图标。如下图所示:
下面我们正式介绍工程的源码,按照惯例还是上工程结构图(就那么一个文件,搞什么搞)
整个工程只有ConfigurationBinder这一个类,调用过程上面“流程图”已经画出来了。
public static class ConfigurationBinder { public static TModel Bind<TModel>(IConfiguration configuration) where TModel : new() { var model = new TModel(); Bind(model, configuration); return model; } publicstaticvoid Bind(object model, IConfiguration configuration) { if (model == null) { return; } BindObjectProperties(model, configuration); } privatestaticvoid BindObjectProperties(object obj, IConfiguration configuration) { foreach (var property in GetAllProperties(obj.GetType().GetTypeInfo())) { BindProperty(property, obj, configuration); } } privatestaticvoid BindProperty(PropertyInfo property, object propertyOwner, IConfiguration configuration) { configuration = configuration.GetConfigurationSection(property.Name); if (property.GetMethod == null || !property.GetMethod.IsPublic) { // We don‘t support set only propertiesreturn; } var propertyValue = property.GetValue(propertyOwner); var hasPublicSetter = property.SetMethod != null && property.SetMethod.IsPublic; if (propertyValue == null && !hasPublicSetter) { // Property doesn‘t have a value and we cannot set it so there is no // point in going further down the graphreturn; } propertyValue = BindType( property.PropertyType, propertyValue, configuration); if (propertyValue != null && hasPublicSetter) { property.SetValue(propertyOwner, propertyValue); } } privatestaticobject BindType(Type type, object typeInstance, IConfiguration configuration) { var configValue = configuration.Get(null); var typeInfo = type.GetTypeInfo(); if (configValue != null) { // Leaf nodes are always reinitializedreturn CreateValueFromConfiguration(type, configValue, configuration); } else { var subkeys = configuration.GetConfigurationSections(); if (subkeys.Count() != 0) { if (typeInstance == null) { if (typeInfo.IsInterface || typeInfo.IsAbstract) { thrownew InvalidOperationException(Resources.FormatError_CannotActivateAbstractOrInterface(type)); } bool hasParameterlessConstructor = typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); if (!hasParameterlessConstructor) { thrownew InvalidOperationException(Resources.FormatError_MissingParameterlessConstructor(type)); } try { typeInstance = Activator.CreateInstance(type); } catch (Exception ex) { thrownew InvalidOperationException(Resources.FormatError_FailedToActivate(type), ex); } } var collectionInterface = GetGenericOpenInterfaceImplementation(typeof(IDictionary<,>), type); if (collectionInterface != null) { // Dictionary BindDictionary(typeInstance, collectionInterface, configuration); } else { collectionInterface = GetGenericOpenInterfaceImplementation(typeof(ICollection<>), type); if (collectionInterface != null) { // ICollection BindCollection(typeInstance, collectionInterface, configuration); } else { // Something else BindObjectProperties(typeInstance, configuration); } } } return typeInstance; } } privatestaticvoid BindDictionary(object dictionary, Type iDictionaryType, IConfiguration configuration) { var iDictionaryTypeInfo = iDictionaryType.GetTypeInfo(); // It is guaranteed to have a two and only two parameters // because this is an IDictionary<K,V>var keyType = iDictionaryTypeInfo.GenericTypeArguments[0]; var valueType = iDictionaryTypeInfo.GenericTypeArguments[1]; if (keyType != typeof(string)) { // We only support string keysreturn; } var addMethod = iDictionaryTypeInfo.GetDeclaredMethod("Add"); var subkeys = configuration.GetConfigurationSections().ToList(); foreach (var keyProperty in subkeys) { var keyConfiguration = keyProperty.Value; var item = BindType( type: valueType, typeInstance: null, configuration: keyConfiguration); if (item != null) { addMethod.Invoke(dictionary, new[] { keyProperty.Key, item }); } } } privatestaticvoid BindCollection(object collection, Type iCollectionType, IConfiguration configuration) { var iCollectionTypeInfo = iCollectionType.GetTypeInfo(); // It is guaranteed to have a one and only one parameter // because this is an ICollection<T>var itemType = iCollectionTypeInfo.GenericTypeArguments[0]; var addMethod = iCollectionTypeInfo.GetDeclaredMethod("Add"); var subkeys = configuration.GetConfigurationSections().ToList(); foreach (var keyProperty in subkeys) { var keyConfiguration = keyProperty.Value; try { var item = BindType( type: itemType, typeInstance: null, configuration: keyConfiguration); if (item != null) { addMethod.Invoke(collection, new[] { item }); } } catch { } } } privatestaticobject CreateValueFromConfiguration(Type type, string value, IConfiguration configuration) { var typeInfo = type.GetTypeInfo(); if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { return CreateValueFromConfiguration(Nullable.GetUnderlyingType(type), value, configuration); } var configurationValue = configuration.Get(key: null); try { if (typeInfo.IsEnum) { return Enum.Parse(type, configurationValue); } else { return Convert.ChangeType(configurationValue, type); } } catch (Exception ex) { thrownew InvalidOperationException(Resources.FormatError_FailedBinding(configurationValue, type), ex); } } privatestatic Type GetGenericOpenInterfaceImplementation(Type expectedOpenGeneric, Type actual) { var interfaces = actual.GetTypeInfo().ImplementedInterfaces; foreach (var interfaceType in interfaces) { if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == expectedOpenGeneric) { return interfaceType; } } returnnull; } privatestatic IEnumerable<PropertyInfo> GetAllProperties(TypeInfo type) { var allProperties = new List<PropertyInfo>(); do { allProperties.AddRange(type.DeclaredProperties); type = type.BaseType.GetTypeInfo(); } while (type != typeof(object).GetTypeInfo()); return allProperties; } }
我们对其中几个方法,进行简单的说明:
- GetAllProperties。系统获取属性的时候,不光要获取当前类的属性也要获取基类的属性。
- 绑定属性时,将需要被绑定的对象作为参数传入进去,由于是引用类型,所以不用返回值也能更改其属性、类似的还有ArrayList等。
- BindProperty(PropertyInfo property, object propertyOwner, IConfiguration configuration)。此处的propertyOwner值会被调用方法中修改。
- 将字符串转换成枚举的方法:
- Enum.Parse(type, configurationValue);、
- 将对象转变类型的方法:
- Convert.ChangeType(configurationValue, type);
- 判断泛型的方法
privatestatic Type GetGenericOpenInterfaceImplementation(Type expectedOpenGeneric, Type actual) { var interfaces = actual.GetTypeInfo().ImplementedInterfaces; foreach (var interfaceType in interfaces) { if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == expectedOpenGeneric) { return interfaceType; } } returnnull; }
原文:http://www.cnblogs.com/watermoon2/p/4530621.html
内容总结
以上是互联网集市为您收集整理的[Asp.net 5] Configuration-新一代的配置文件(神奇的Binder)全部内容,希望文章能够帮你解决[Asp.net 5] Configuration-新一代的配置文件(神奇的Binder)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。