private List <RuleParameter> FindConditionParameters(Type containerType, RuleParameterValueResolver containerResolver, string prefix)
{
var parameters = new List <RuleParameter>();
foreach (var property in containerType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var refAttr = property.GetCustomAttribute <ReferenceAttribute>(false);
if (refAttr != null)
{
var resolver = new ChainedRuleParameterValueResolver().Chain(containerResolver, new PropertyBackedRuleParameterValueResolver(property));
var referencingType = refAttr.ReferencingType ?? property.PropertyType;
// Indirect reference
if (referencingType != property.PropertyType)
{
if (refAttr.ReferenceResolver == null)
{
throw new InvalidOperationException("Indirect reference must speicify a reference resolver. Property: " + property.ReflectedType.FullName + "." + property.Name + ".");
}
resolver.Chain(new IndirectReferenceAdapter(referencingType, refAttr.ReferenceResolver));
}
var newPrefix = prefix;
// refAttr.Prefix == null: Generate a default prefix
// refAttr.Prefix == String.Empty: Do not use prefix
// otherwise, use the specified prefix
if (refAttr.Prefix != null)
{
if (refAttr.Prefix.Length > 0)
{
newPrefix = prefix + (refAttr.Prefix.EndsWith(".") ? refAttr.Prefix : refAttr.Prefix + ".");
}
}
else
{
// Try to get a smart default preifx if developer doesn't specify one.
// If the property name is like BrandId,
// then we use 'Brand' instead of 'BrandId'.
// So when we are investigating Brand.Name property, we can get a better parameter name 'BrandName' instead of 'BrandIdName'
if (property.Name.EndsWith("Id"))
{
newPrefix = prefix + property.Name.Substring(0, property.Name.Length - 2);
}
else
{
newPrefix = prefix + property.Name;
}
newPrefix = newPrefix + ".";
}
parameters.AddRange(FindConditionParameters(referencingType, resolver, newPrefix));
// Add also extended parameters
foreach (var provider in Providers)
{
if (provider.GetType() != typeof(DefaultRuleParameterProvider))
{
var additionalParams = provider.GetParameters(referencingType);
foreach (var param in additionalParams)
{
var valueResolver = new ChainedRuleParameterValueResolver();
valueResolver.Chain(resolver);
valueResolver.Chain(param.ValueResolver);
var adaptedParam = new RuleParameter(newPrefix + param.Name, param.ValueType, valueResolver, param.SupportedOperators)
{
ValueSource = param.ValueSource
};
parameters.Add(adaptedParam);
}
}
}
}
else
{
var paramAttr = property.GetCustomAttribute <ParamAttribute>(false);
if (paramAttr != null)
{
parameters.Add(CreateConditionParameter(containerType, containerResolver, prefix, property, paramAttr));
}
}
}
return(parameters);
}