-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Initial discussion - #44493 (comment)
cc @eerhardt @ericstj @davidfowl
Extensibility for Configuration Binding Source Generator
Background
The configuration binding source generator provides AOT and trim-friendly configuration in ASP.NET Core. It is an alternative to the pre-exising reflection-based implementation. For each type to bind, the reflection implementation checks whether a TypeConverter instance exists and uses it if so. This was mainly applicable as a convenient abstraction to bind to built-in primitives such as int and string which are parsable from string. However, the TypeConverter mechanism is not friendly for AOT usage. As a result, the binding generator does not look up TypeConverter usage.
TypeConverter inadvertently provided a way for developers to convert binding behavior. We've seen partner teams use it to parse non-primitive types such as security certificates. This begs the question of whether we do need to support it, or provide a replacement mechanism to cover customization scenarios.
Proposed customization strategies
We don't want to honor TypeConverter in the generator implementation. References to it would largely undo the major benefit of the generator, which is AOT and linking friendliness. Since the generator is new, we have an opportunity to provide a better customization experience.
Check and honor IParsable<T> implementations.
This only works for design-time customization. Does not work for non-owned types.
API proposal: new API for runtime configuration
We would add a new converters dictionary to register converter instances. This would be last one wins.
namespace Microsoft.Extensions.Configuration
{
public class BinderOptions
{
public bool BindNonPublicProperties { get; set; }
public bool ErrorOnUnknownConfiguration { get; set; }
// New
// Note: last one wins, just like with current `TypeConverter` look up behavior.
// Note: boxing for custom structs. Should be okay since binding generally isn't in hot path.
public IDictionary<Type, Func<string, object>> Converters { get; }
}
}Customization restrictions
- Like the reflection implementation, and with
IParsable<T>, we would only support types directly parsable from string. - We would throw an exception if we detect a converter for a type that is included in the list of "intrinsic" types that
TypeConvertersupports & the generator now handles with hand-written logic.
Order of customization preference
- Honor runtime converter.
- Use
IParsable<T>implementation if detected (replacing generators handwritten logic for intrinsic types). - Fallback to built-in binding logic.