Say I have a model like this
public class User
{
[Required]
[StringLength(14, ErrorMessage = "Can only be 14 characters long")]
public string UserName;
}
I want to create a Html helper like this:
@Html.ValidatableEditorFor(m => m.UserName)
so that it spits out a text field with the correct format for jQuery Vaidation plugin to be able to validate, like this:
<input type="text" class="required" maxlength="14" />
From my research, it seems that there is no way to iterate over all the data annotations in a MetaDataModel so that I can check to see which one's are applicable to jQuery Validation.
How I envision it working in pseudo code:
var tag = new TagBuilder("input");
tag.mergeAttribute("type", "text");
foreach(var attribute in metadata.attributes)
{
CheckForValidatableAttribute(attribute, tag);
}
...
private void CheckForValidatableAttribute(DataAnnotation attribute, TagBuilder tag)
{
switch(attribute.type)
{
case Required:
tag.addClass("required");
break;
case StringLength
tag.mergeAttribute("maxlength", attribute.value)
break;
}
}
How could I go about achieving a helper like this? I want it to work on data annotations so that I don't have to duplicate the validation literals.
For instance, the current Html helpers like TextEditorFor do append validatable attributes to their output fields. How does it do this, and how can I make my own implementation?
Cheers
Data annotations (available as part of the System. ComponentModel. DataAnnotations namespace) are attributes that can be applied to classes or class members to specify the relationship between classes, describe how the data is to be displayed in the UI, and specify validation rules.
In MVC, HTML Helper can be considered as a method that returns you a string. This string can describe the specific type of detail of your requirement. Example: We can utilize the HTML Helpers to perform standard HTML tags, for example HTML<input>, and any <img> tags.
DataAnnotations is used to configure your model classes, which will highlight the most commonly needed configurations. DataAnnotations are also understood by a number of . NET applications, such as ASP.NET MVC, which allows these applications to leverage the same annotations for client-side validations.
Data Annotations attributes are . NET attributes which can be applied on an entity class or properties to override default conventions in EF 6 and EF Core. Data annotation attributes are included in the System. ComponentModel.
You may use this simple condition:
if(attribute.Type is ValidationAttribute)
{
string className = attribute.Type.Name.Replace("Attribute", "").ToLower();
}
Define an Html helper:
public static MvcHtmlString ValidationEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
....
}
Create this helper method:
private static string GetPropertyNameFromExpression<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
MemberExpression memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
throw new InvalidOperationException("Not a memberExpression");
if (!(memberExpression.Member is PropertyInfo))
throw new InvalidOperationException("Not a property");
return memberExpression.Member.Name;
}
Now use this in ValidationEditorFor
:
var propertyName = GetPropertyNameFromExpression(htmlHelper, expression);
var propertyType = typeof(TModel).GetProperties().Where(x=>x.Name == propertyName).First().PropertyType;
var attributes = propertyType.GetCustomAttributes(true).OfType<ValidationAttribute>();
Now you can check the attributes.... rest is easy.
Slightly altered and extracted into a helper.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Payntbrush.Infrastructure.Web.Mvc
{
public static class ReflectionHelper
{
public static IEnumerable<ValidationAttribute> GetAttributes<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
Type type = typeof(TModel);
var prop = type.GetProperty(GetPropertyNameFromExpression(expression));
return prop.GetCustomAttributes(true).OfType<ValidationAttribute>();
}
private static string GetPropertyNameFromExpression<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
throw new InvalidOperationException("Not a memberExpression");
if (!(memberExpression.Member is PropertyInfo))
throw new InvalidOperationException("Not a property");
return memberExpression.Member.Name;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With