-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Allow ConfigBinder to bind arrays to Singular elements #57204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
beb621a
c9e7ef1
64c8ee2
01cbca8
c77ff33
cfb5c69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ public static class ConfigurationBinder | |
| private const string TrimmingWarningMessage = "In case the type is non-primitive, the trimmer cannot statically analyze the object's type so its members may be trimmed."; | ||
| private const string InstanceGetTypeTrimmingWarningMessage = "Cannot statically analyze the type of instance so its members may be trimmed"; | ||
| private const string PropertyTrimmingWarningMessage = "Cannot statically analyze property.PropertyType so its members may be trimmed."; | ||
| private const string BindSingleElementsToArraySwitch = "Microsoft.Extensions.Configuration.BindSingleElementsToArray"; | ||
|
|
||
| /// <summary> | ||
| /// Attempts to bind the configuration instance to a new instance of type T. | ||
|
|
@@ -362,7 +363,7 @@ private static object BindInstance( | |
| return convertedValue; | ||
| } | ||
|
|
||
| if (config != null && config.GetChildren().Any()) | ||
| if (config != null && (config.GetChildren().Any() || (configValue != null && ShouldBindSingleElementsToArray()))) | ||
| { | ||
| // If we don't have an instance, try to create one | ||
| if (instance == null) | ||
|
|
@@ -495,7 +496,7 @@ private static void BindCollection( | |
| Type itemType = collectionType.GenericTypeArguments[0]; | ||
| MethodInfo addMethod = collectionType.GetMethod("Add", DeclaredOnlyLookup); | ||
|
|
||
| foreach (IConfigurationSection section in config.GetChildren()) | ||
| foreach (IConfigurationSection section in GetChildrenOrSelf(config)) | ||
| { | ||
| try | ||
| { | ||
|
|
@@ -518,7 +519,7 @@ private static void BindCollection( | |
| [RequiresUnreferencedCode("Cannot statically analyze what the element type is of the Array so its members may be trimmed.")] | ||
| private static Array BindArray(Array source, IConfiguration config, BinderOptions options) | ||
| { | ||
| IConfigurationSection[] children = config.GetChildren().ToArray(); | ||
| IConfigurationSection[] children = GetChildrenOrSelf(config).ToArray(); | ||
| int arrayLength = source.Length; | ||
| Type elementType = source.GetType().GetElementType(); | ||
| var newArray = Array.CreateInstance(elementType, arrayLength + children.Length); | ||
|
|
@@ -702,5 +703,38 @@ private static string GetPropertyName(MemberInfo property) | |
|
|
||
| return property.Name; | ||
| } | ||
|
|
||
| private static IEnumerable<IConfigurationSection> GetChildrenOrSelf(IConfiguration config) | ||
| { | ||
| if (!ShouldBindSingleElementsToArray()) | ||
| { | ||
| return config.GetChildren(); | ||
| } | ||
|
|
||
|
|
||
| IEnumerable<IConfigurationSection> children; | ||
| // If configuration's children is an array, the configuration key will be a number | ||
| if (config.GetChildren().Any(a => long.TryParse(a.Key, out _))) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @HaoK let us know if you know of a better way for this condition
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If any of the children is an integer (key:999), this assumes the actual object is an array. In real world, either all children are integers or all are not. But doing "Any" prevents usages in weird cases where someone used both things
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the old behavior always used the children correct? Why does this need to check if any children are a number? What doesn't work if this is just returning the children if there are any, otherwise the config.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This used to always return children for arrays/collections. But as part of my change, I might have to return the parent object or children object (when it contains array as a children vs non-array). |
||
| { | ||
| children = config.GetChildren(); | ||
| } | ||
| else | ||
| { | ||
| children = new[] { config as IConfigurationSection }; | ||
| } | ||
|
|
||
| return children; | ||
| } | ||
|
|
||
| private static bool ShouldBindSingleElementsToArray() | ||
| { | ||
| if (AppContext.TryGetSwitch(BindSingleElementsToArraySwitch, out bool bindSingleElementsToArray)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be cached? Reading from AppContext each time in a loop might be a perf issue. |
||
| { | ||
| return bindSingleElementsToArray; | ||
| } | ||
|
|
||
| // Enable this switch by default. | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.