// transforms binding data to appropriate resolver (appsetting, autoresolve, or originalValue) private BindingDataResolver GetResolver(PropertyInfo propInfo, INameResolver nameResolver, BindingDataContract contract) { object originalValue = propInfo.GetValue(_source); AppSettingAttribute appSettingAttr = propInfo.GetCustomAttribute <AppSettingAttribute>(); AutoResolveAttribute autoResolveAttr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); if (appSettingAttr != null && autoResolveAttr != null) { throw new InvalidOperationException($"Property '{propInfo.Name}' cannot be annotated with both AppSetting and AutoResolve."); } // first try to resolve with app setting if (appSettingAttr != null) { return(GetAppSettingResolver((string)originalValue, appSettingAttr, nameResolver, propInfo)); } // try to resolve with auto resolve ({...}, %...%) if (autoResolveAttr != null && originalValue != null) { _autoResolves[propInfo] = autoResolveAttr; return(GetTemplateResolver((string)originalValue, autoResolveAttr, nameResolver, propInfo, contract)); } // resolve the original value return((newAttr, bindingData) => originalValue); }
internal static IResolutionPolicy GetPolicy(PropertyInfo propInfo) { AutoResolveAttribute autoResolveAttribute = propInfo.GetCustomAttribute <AutoResolveAttribute>(); var formatterType = autoResolveAttribute.ResolutionPolicyType; if (formatterType != null) { // Special-case Table as there is no way to declare this ResolutionPolicy // and use BindingTemplate in the Core assembly if (formatterType == typeof(WebJobs.ODataFilterResolutionPolicy)) { return(new ODataFilterResolutionPolicy()); } if (!typeof(IResolutionPolicy).IsAssignableFrom(formatterType)) { throw new InvalidOperationException($"The {nameof(AutoResolveAttribute.ResolutionPolicyType)} on {propInfo.Name} must derive from {typeof(IResolutionPolicy).Name}."); } try { var obj = Activator.CreateInstance(formatterType); return((IResolutionPolicy)obj); } catch (MissingMethodException) { throw new InvalidOperationException($"The {nameof(AutoResolveAttribute.ResolutionPolicyType)} on {propInfo.Name} must derive from {typeof(IResolutionPolicy).Name} and have a default constructor."); } } // return the default policy return(new DefaultResolutionPolicy()); }
public void GetPolicy_Throws_IfPolicyHasNoDefaultConstructor() { PropertyInfo propInfo = typeof(AttributeWithResolutionPolicy).GetProperty(nameof(AttributeWithResolutionPolicy.PropWithConstructorlessPolicy)); AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); InvalidOperationException ex = Assert.Throws <InvalidOperationException>(() => AttributeCloner <AttributeWithResolutionPolicy> .GetPolicy(attr.ResolutionPolicyType, propInfo)); Assert.Equal($"The {nameof(AutoResolveAttribute.ResolutionPolicyType)} on {nameof(AttributeWithResolutionPolicy.PropWithConstructorlessPolicy)} must derive from {typeof(IResolutionPolicy).Name} and have a default constructor.", ex.Message); }
public void GetPolicy_Throws_IfPolicyDoesNotImplementInterface() { PropertyInfo propInfo = typeof(AttributeWithResolutionPolicy).GetProperty(nameof(AttributeWithResolutionPolicy.PropWithInvalidPolicy)); AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); InvalidOperationException ex = Assert.Throws <InvalidOperationException>(() => AttributeCloner <AttributeWithResolutionPolicy> .GetPolicy(attr.ResolutionPolicyType, propInfo)); Assert.Equal($"The {nameof(AutoResolveAttribute.ResolutionPolicyType)} on {nameof(AttributeWithResolutionPolicy.PropWithInvalidPolicy)} must derive from {typeof(IResolutionPolicy).Name}.", ex.Message); }
public void GetPolicy_ReturnsDefault_WhenNoSpecifiedPolicy() { PropertyInfo propInfo = typeof(AttributeWithResolutionPolicy).GetProperty(nameof(AttributeWithResolutionPolicy.PropWithoutPolicy)); AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); IResolutionPolicy policy = AttributeCloner <AttributeWithResolutionPolicy> .GetPolicy(attr.ResolutionPolicyType, propInfo); Assert.IsType <DefaultResolutionPolicy>(policy); }
public void GetPolicy_ReturnsODataFilterPolicy_ForMarkerType() { // This is a special-case marker type to handle TableAttribute.Filter. We cannot directly list ODataFilterResolutionPolicy // because BindingTemplate doesn't exist in the core assembly. PropertyInfo propInfo = typeof(AttributeWithResolutionPolicy).GetProperty(nameof(AttributeWithResolutionPolicy.PropWithMarkerPolicy)); AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); IResolutionPolicy policy = AttributeCloner <AttributeWithResolutionPolicy> .GetPolicy(attr.ResolutionPolicyType, propInfo); Assert.IsType <Host.Bindings.ODataFilterResolutionPolicy>(policy); }
// transforms binding data to appropriate resolver (appsetting, autoresolve, or originalValue) private BindingDataResolver GetResolver(PropertyInfo propInfo, INameResolver nameResolver, BindingDataContract contract) { // Do the attribute lookups once upfront, and then cache them (via func closures) for subsequent runtime usage. object originalValue = propInfo.GetValue(_source); ConnectionStringAttribute connStrAttr = propInfo.GetCustomAttribute <ConnectionStringAttribute>(); AppSettingAttribute appSettingAttr = propInfo.GetCustomAttribute <AppSettingAttribute>(); AutoResolveAttribute autoResolveAttr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); Validator validator = GetValidatorFunc(propInfo, appSettingAttr != null); if (appSettingAttr == null && autoResolveAttr == null && connStrAttr == null) { validator(originalValue); // No special attributes, treat as literal. return((newAttr, bindingData) => originalValue); } int attrCount = new Attribute[] { connStrAttr, appSettingAttr, autoResolveAttr }.Count(a => a != null); if (attrCount > 1) { throw new InvalidOperationException($"Property '{propInfo.Name}' can only be annotated with one of the types {nameof(AppSettingAttribute)}, {nameof(AutoResolveAttribute)}, and {nameof(ConnectionStringAttribute)}."); } // attributes only work on string properties. if (propInfo.PropertyType != typeof(string)) { throw new InvalidOperationException($"{nameof(ConnectionStringAttribute)}, {nameof(AutoResolveAttribute)}, or {nameof(AppSettingAttribute)} property '{propInfo.Name}' must be of type string."); } var str = (string)originalValue; // first try to resolve with connection string if (connStrAttr != null) { return(GetConfigurationResolver(str, connStrAttr.Default, propInfo, validator, s => _configuration.GetConnectionStringOrSetting(nameResolver.ResolveWholeString(s)))); } // then app setting if (appSettingAttr != null) { return(GetConfigurationResolver(str, appSettingAttr.Default, propInfo, validator, s => _configuration[s])); } // Must have an [AutoResolve] // try to resolve with auto resolve ({...}, %...%) return(GetAutoResolveResolver(str, autoResolveAttr, nameResolver, propInfo, contract, validator)); }
private bool TryCreateAutoResolveBindingTemplate(PropertyInfo propInfo, INameResolver nameResolver, out BindingTemplate template) { template = null; AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); // Return false if there is no attribute on this property. if (attr == null) { return(false); } string originalValue = (string)propInfo.GetValue(_source); // Return false if the property value is null. if (originalValue == null) { return(false); } string resolvedValue; if (!attr.AllowTokens) { resolvedValue = nameResolver.Resolve(originalValue); // If a value is non-null and cannot be found, we throw to match the behavior // when %% values are not found. if (resolvedValue == null) { string msg = string.Format(CultureInfo.CurrentCulture, "'{0}' does not resolve to a value.", originalValue); throw new InvalidOperationException(msg); } } else { resolvedValue = nameResolver.ResolveWholeString(originalValue); } template = BindingTemplate.FromString(resolvedValue); return(true); }
// Apply AutoResolve attribute internal BindingDataResolver GetAutoResolveResolver(string originalValue, AutoResolveAttribute autoResolveAttr, INameResolver nameResolver, PropertyInfo propInfo, BindingDataContract contract, Validator validator) { if (string.IsNullOrWhiteSpace(originalValue)) { if (autoResolveAttr.Default != null) { return(GetBuiltinTemplateResolver(autoResolveAttr.Default, nameResolver, validator)); } else { validator(originalValue); return((newAttr, bindingData) => originalValue); } } else { _autoResolves[propInfo] = autoResolveAttr; return(GetTemplateResolver(originalValue, autoResolveAttr, nameResolver, propInfo, contract, validator)); } }
internal static bool TryAutoResolveValue(TAttribute attribute, PropertyInfo propInfo, INameResolver nameResolver, out string resolvedValue) { resolvedValue = null; AutoResolveAttribute attr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); if (attr == null) { return(false); } string originalValue = (string)propInfo.GetValue(attribute); if (originalValue == null) { return(false); } if (!attr.AllowTokens) { resolvedValue = nameResolver.Resolve(originalValue); // If a value is non-null and cannot be found, we throw to match the behavior // when %% values are not found in ResolveWholeString below. if (resolvedValue == null) { // It's important that we only log the attribute property name, not the actual value to ensure // that in cases where users accidentally use a secret key *value* rather than indirect setting name // that value doesn't get written to logs. throw new InvalidOperationException($"Unable to resolve value for property '{propInfo.DeclaringType.Name}.{propInfo.Name}'."); } } else { // The logging consideration above doesn't apply in this case, since only tokens wrapped // in %% characters will be resolved, so they are less likely to include a secret value. resolvedValue = nameResolver.ResolveWholeString(originalValue); } return(true); }
// transforms binding data to appropriate resolver (appsetting, autoresolve, or originalValue) private BindingDataResolver GetResolver(PropertyInfo propInfo, INameResolver nameResolver, BindingDataContract contract) { // Do the attribute lookups once upfront, and then cache them (via func closures) for subsequent runtime usage. object originalValue = propInfo.GetValue(_source); AppSettingAttribute appSettingAttr = propInfo.GetCustomAttribute <AppSettingAttribute>(); AutoResolveAttribute autoResolveAttr = propInfo.GetCustomAttribute <AutoResolveAttribute>(); Validator validator = GetValidatorFunc(propInfo, appSettingAttr != null); if (appSettingAttr == null && autoResolveAttr == null) { validator(originalValue); // No special attributes, treat as literal. return((newAttr, bindingData) => originalValue); } if (appSettingAttr != null && autoResolveAttr != null) { throw new InvalidOperationException($"Property '{propInfo.Name}' cannot be annotated with both AppSetting and AutoResolve."); } // attributes only work on string properties. if (propInfo.PropertyType != typeof(string)) { throw new InvalidOperationException($"AutoResolve or AppSetting property '{propInfo.Name}' must be of type string."); } var str = (string)originalValue; // first try to resolve with app setting if (appSettingAttr != null) { return(GetAppSettingResolver(str, appSettingAttr, nameResolver, propInfo, validator)); } // Must have an [AutoResolve] // try to resolve with auto resolve ({...}, %...%) return(GetAutoResolveResolver(str, autoResolveAttr, nameResolver, propInfo, contract, validator)); }
// AutoResolve internal static BindingDataResolver GetTemplateResolver(string originalValue, AutoResolveAttribute attr, INameResolver nameResolver, PropertyInfo propInfo, BindingDataContract contract) { string resolvedValue = nameResolver.ResolveWholeString(originalValue); var template = BindingTemplate.FromString(resolvedValue); IResolutionPolicy policy = GetPolicy(attr.ResolutionPolicyType, propInfo); template.ValidateContractCompatibility(contract); return((newAttr, bindingData) => TemplateBind(policy, propInfo, newAttr, template, bindingData)); }
// AutoResolve internal static BindingDataResolver GetTemplateResolver(string originalValue, AutoResolveAttribute attr, INameResolver nameResolver, PropertyInfo propInfo, BindingDataContract contract, Validator validator) { string resolvedValue = nameResolver.ResolveWholeString(originalValue); var template = BindingTemplate.FromString(resolvedValue); if (!template.HasParameters) { // No { } tokens, bind eagerly up front. validator(resolvedValue); } IResolutionPolicy policy = GetPolicy(attr.ResolutionPolicyType, propInfo); template.ValidateContractCompatibility(contract); return((newAttr, bindingData) => TemplateBind(policy, propInfo, newAttr, template, bindingData, validator)); }