0

The PropertyInfo has a property (CustomAttributes) which returns the attributes applied to the property for which html helper is being created. How do we add another annotation during the helper creation? For example, for every property on which this helper is called, I want to add the RangeAttribute annotation. Currently, I have done the following, but the server side validation is not happening since the annotation is not being added.

public static MvcHtmlString DateTimeWithIntervalFor<TModel, TProperty>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes = null, string format = "{0:yyyy-MM-dd hh:mm:ss tt}")
{
    var routeValueDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    var metadata = HtmlHelperExtensions.GetModelMetadata(helper, expression);
    var propertyInfo = HtmlHelperExtensions.GetModelPropertyInfoFromMetadata(metadata);
    RangeAttribute rangeAttribute = propertyInfo.GetCustomAttributes(typeof(RangeAttribute), false).FirstOrDefault() as RangeAttribute;
    if (rangeAttribute != null)
    {
        AddMinimumAndMaximumAttributeValues(routeValueDictionary, rangeAttribute.Minimum, rangeAttribute.Maximum);
    }
    else
    {
        var minimumValue = new DateTime(2000, 1, 1);
        var maximumValue = new DateTime(2018, 1, 1);
        string formattedMinimumValue = string.Format(format, minimumValue);
        string formattedMaximumValue = string.Format(format, maximumValue);

        /* This is where I am struggling, I have tried setting the attribute
         * using SetCustomAttribute, but it isn't accessible/defined on 
         * PropertyInfo.
         * What I have done currently doesn't work too.
         */
        metadata.AdditionalValues.Add("RangeAttribute", new RangeAttribute(typeof(RangeAttribute), formattedMinimumValue, formattedMaximumValue));

        /* 
         * This is for adding client side attributes, which work fine with 
         * jQuery Validation, but since the annotation is not added to the 
         * property, on the server ModelState is valid, even if the value 
         * doesn't fall in the range.
         */
        AddMinimumAndMaximumAttributeValues(
            routeValueDictionary, formattedMinimumValue, formattedMaximumValue
        );
    }

    return helper.TextBoxFor(expression, format, routeValueDictionary);
}
ZerosAndOnes
  • 1,083
  • 1
  • 13
  • 25
  • Attributes are metadata and must be known at compile time. You cannot just 'add' a `[Range]` attribute in code. And your `metadata.AdditionalValues.Add(...)` code makes no sense. Its not clear what your trying to do here (or why) –  Aug 08 '18 at 10:43
  • And your `AddMinimumAndMaximumAttributeValues()` method has nothing at all to do with jQuery Validation (unless its adding `data-val-min` and `data-val-max` attributes - but if its doing that, then using that inside your `if (rangeAttribute != null)` block makes no sense, because its already been added) –  Aug 08 '18 at 10:49
  • @StephenMuecke Thanks to your first comment I was able to find https://stackoverflow.com/a/24413055/6671838 through which we can metadata to a class at runtime. However, research on how to add it to a property that's not virtual required more time and due to time constraint, I was not able to research it. Eventually, we went with adding the annotation on each property. – ZerosAndOnes Sep 14 '18 at 04:59
  • And yes the `AddMinimumAndMaximumAttributeValues()` is actually adding the validation attributes. Plus, you are also correct about the `if (rangeAttribute != null)` part. – ZerosAndOnes Sep 14 '18 at 05:04

0 Answers0