I went looking for a way to get the built-in Html.EditorFor to do it, but didn't find any.
Here's a new helper called "LimitedEditorFor" which automatically adds the correct MAXLENGTH attribute to the text input tag. Call this exactly the same way you would call Html.EditorFor.
namespace ExtensionMethods
{
public static class MyExtensions
{
public static MvcHtmlString LimitedEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
{
string S = htmlHelper.EditorFor(expression).ToString().Replace("/>", "MAXLENGTH=\"" + GetLengthLimit(expression) + "\"/>");
return new MvcHtmlString(S);
}
private static int GetLengthLimit(Expression expression)
{
MemberExpression ME = GetMemberInfo(expression);
Type type = ME.Member.ReflectedType;
string field = ME.Member.Name;
PropertyInfo prop = type.GetProperty(field);
// Find the Linq 'Column' attribute
// e.g. [Column(Storage="_FileName", DbType="NChar(256) NOT NULL", CanBeNull=false)]
object[] info = prop.GetCustomAttributes(typeof(ColumnAttribute), true);
if (info.Length != 1) return 0; // Assume there is just one
ColumnAttribute ca = (ColumnAttribute)info[0];
string dbtype = ca.DbType;
if (!dbtype.StartsWith("NChar") && !dbtype.StartsWith("NVarChar")) return 0;
Regex pattern = new Regex("\\((.+)\\)");
Match m = pattern.Match(dbtype);
if (!m.Success) return 0;
return Convert.ToInt16(m.Groups[1].Value);
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null) throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null) throw new ArgumentException("method");
return memberExpr;
}
}
}
This was a huge help: http://joaodepaula.com/articles/columnsizereflection.html