Frage maxlength-Attribut eines Textfelds aus der DataAnnotations StringLength in Asp.Net MVC


Ich arbeite an einer MVC2-Anwendung und möchte die Maxlength-Attribute der Texteingaben festlegen.

Ich habe das stringlength-Attribut für das Model-Objekt bereits mit Datenanmerkungen definiert und validiert die Länge der eingegebenen Strings korrekt.

Ich möchte nicht dieselbe Einstellung in meinen Ansichten wiederholen, indem ich das Attribut für die maximale Länge manuell festlege, wenn das Modell bereits über die Informationen verfügt. Gibt es eine Möglichkeit, dies zu tun?

Codefragmente unten:

Aus dem Modell:

[Required, StringLength(50)]
public string Address1 { get; set; }

Aus der Sicht:

<%= Html.LabelFor(model => model.Address1) %>
<%= Html.TextBoxFor(model => model.Address1, new { @class = "text long" })%>
<%= Html.ValidationMessageFor(model => model.Address1) %>

Was ich vermeiden möchte, ist:

<%= Html.TextBoxFor(model => model.Address1, new { @class = "text long", maxlength="50" })%>

Ich möchte diese Ausgabe erhalten:

<input type="text" name="Address1" maxlength="50" class="text long"/>

Gibt es eine Möglichkeit, dies zu tun?


76
2018-03-05 11:36


Ursprung


Antworten:


Mir ist keine Möglichkeit bekannt, dies ohne Reflexion zu erreichen. Sie könnten eine Hilfsmethode schreiben:

public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expression, 
    object htmlAttributes
)
{
    var member = expression.Body as MemberExpression;
    var stringLength = member.Member
        .GetCustomAttributes(typeof(StringLengthAttribute), false)
        .FirstOrDefault() as StringLengthAttribute;

    var attributes = (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes);
    if (stringLength != null)
    {
        attributes.Add("maxlength", stringLength.MaximumLength);
    }
    return htmlHelper.TextBoxFor(expression, attributes);
}

was könntest du so benutzen:

<%= Html.CustomTextBoxFor(model => model.Address1, new { @class = "text long" })%>

50
2018-03-05 12:00



Wenn Sie eine unauffällige Validierung verwenden, können Sie auch diese Client-Seite behandeln:

$(document).ready(function ()
{
    $("input[data-val-length-max]").each(function ()
    {
        var $this = $(this);
        var data = $this.data();
        $this.attr("maxlength", data.valLengthMax);
    });
});

56
2018-03-14 20:45



Ich verwende den CustomModelMetaDataProvider, um dies zu erreichen

Schritt 1. Fügen Sie die neue CustomModelMetadataProvider-Klasse hinzu

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{   
    protected override ModelMetadata CreateMetadata(
        IEnumerable<Attribute> attributes,
        Type containerType,
        Func<object> modelAccessor,
        Type modelType,
        string propertyName)
    {
        ModelMetadata metadata = base.CreateMetadata(attributes,
            containerType,
            modelAccessor,
            modelType,
            propertyName);

        //Add MaximumLength to metadata.AdditionalValues collection
        var stringLengthAttribute = attributes.OfType<StringLengthAttribute>().FirstOrDefault();
        if (stringLengthAttribute != null)
            metadata.AdditionalValues.Add("MaxLength", stringLengthAttribute.MaximumLength);

        return metadata;
    }
}

Schritt 2. In Global.asax Registrieren Sie den CustomModelMetadataProvider

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    ModelMetadataProviders.Current = new CustomModelMetadataProvider();
}

Schritt 3. In Views / Shared / EditorTemplates Fügen Sie eine Teilansicht namens String.ascx hinzu

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%if (!ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) { %>
    <%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue,  new { @class = "text-box single-line" }) %>
<% } else {
    int maxLength = (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"];
    %>
    <%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", MaxLength = maxLength  })%>
<% } %>

Erledigt...

Bearbeiten. Der Schritt 3 kann beginnen, hässlich zu werden, wenn Sie mehr Sachen zum Textkasten hinzufügen möchten. Wenn dies der Fall ist, können Sie Folgendes tun:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
    IDictionary<string, object> Attributes = new Dictionary<string, object>();
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) {
        Attributes.Add("MaxLength", (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"]);
    }
    if (ViewData.ContainsKey("style")) {
        Attributes.Add("style", (string)ViewData["style"]);
    }
    if (ViewData.ContainsKey("title")) {
        Attributes.Add("title", (string)ViewData["title"]);
    }
%>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, Attributes)%>

20
2017-07-29 04:16



Wenn Sie möchten, dass dies mit einer Metadatenklasse funktioniert, müssen Sie den folgenden Code verwenden. Ich weiß, es ist nicht schön, aber es macht die Arbeit erledigt und verhindert, dass Sie Ihre maxlength Eigenschaften in der Entity-Klasse und der Ansicht schreiben müssen:

public static MvcHtmlString TextBoxFor2<TModel, TProperty>
(
  this HtmlHelper<TModel> htmlHelper,
  Expression<Func<TModel, TProperty>> expression,
  object htmlAttributes = null
)
{
  var member = expression.Body as MemberExpression;

  MetadataTypeAttribute metadataTypeAttr = member.Member.ReflectedType
    .GetCustomAttributes(typeof(MetadataTypeAttribute), false)
    .FirstOrDefault() as MetadataTypeAttribute;

  IDictionary<string, object> htmlAttr = null;

  if(metadataTypeAttr != null)
  {
    var stringLength = metadataTypeAttr.MetadataClassType
      .GetProperty(member.Member.Name)
      .GetCustomAttributes(typeof(StringLengthAttribute), false)
      .FirstOrDefault() as StringLengthAttribute;

    if (stringLength != null)
    {
      htmlAttr = new RouteValueDictionary(htmlAttributes);
      htmlAttr.Add("maxlength", stringLength.MaximumLength);
    }                                    
  }

  return htmlHelper.TextBoxFor(expression, htmlAttr);
}

Beispielklasse:

[MetadataType(typeof(Person.Metadata))]
public partial class Person
{
  public sealed class Metadata
  {

    [DisplayName("First Name")]
    [StringLength(30, ErrorMessage = "Field [First Name] cannot exceed 30 characters")]
    [Required(ErrorMessage = "Field [First Name] is required")]
    public object FirstName { get; set; }

    /* ... */
  }
}

8
2018-06-15 01:18



Während ich Jrummels jQuery-Fix ​​persönlich liebe, ist hier ein weiterer Ansatz, um eine einzige Quelle der Wahrheit in Ihrem Modell zu halten ...

Nicht schön, aber .. hat gearbeitet o.k. für mich...

Anstatt Eigenschaftsdekorationen zu verwenden, definiere ich einfach einige gut benannte öffentliche Konstanten in meiner Modellbibliothek / dll und referenziere sie dann in meiner Ansicht über die HtmlAttributes, z.

Public Class MyModel

    Public Const MAX_ZIPCODE_LENGTH As Integer = 5

    Public Property Address1 As String

    Public Property Address2 As String

    <MaxLength(MAX_ZIPCODE_LENGTH)>
    Public Property ZipCode As String

    Public Property FavoriteColor As System.Drawing.Color

End Class

Verwenden Sie dann in der Rasator-Ansichtsdatei im EditorFür ein HtmlAttrirubte-Objekt in der Überladung, geben Sie die gewünschte maximale Länge-Eigenschaft ein und verweisen Sie auf die Konstante. Sie müssen die Konstante über einen vollständig qualifizierten Namespace-Pfad bereitstellen. .. MyCompany.MyModel.MAX_ZIPCODE_LENGTH .. wie es nicht direkt vom Modell hängt, aber es funktioniert.


3
2017-11-19 17:18



Ich fand Darins reflexionsbasierten Ansatz als besonders hilfreich. Ich fand, dass es etwas zuverlässiger war, die Metadaten zu verwenden ContainerType als Grundlage, um die Eigenschafteninformationen zu erhalten, da diese Methode innerhalb von mvc Editor / Display Templates (wo TModel endet als eine einfache Art wie string).

public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expression, 
    object htmlAttributes
)
{
    var metadata = ModelMetadata.FromLambdaExpression( expression, new ViewDataDictionary<TModel>( htmlHelper.ViewDataContainer.ViewData ) );
    var stringLength = metadata.ContainerType.GetProperty(metadata.PropertyName)
        .GetCustomAttributes(typeof(StringLengthAttribute), false)
        .FirstOrDefault() as StringLengthAttribute;

    var attributes = (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes);
    if (stringLength != null)
    {
        attributes.Add("maxlength", stringLength.MaximumLength);
    }
    return htmlHelper.TextBoxFor(expression, attributes);
}

1
2017-12-21 17:13



Hier sind einige statische Methoden, die Sie verwenden können, um die StringLength oder ein anderes Attribut zu erhalten.

using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

public static class AttributeHelpers {

public static Int32 GetStringLength<T>(Expression<Func<T,string>> propertyExpression) {
    return GetPropertyAttributeValue<T,string,StringLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}

//Optional Extension method
public static Int32 GetStringLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
    return GetStringLength<T>(propertyExpression);
}


//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
    var expression = (MemberExpression)propertyExpression.Body;
    var propertyInfo = (PropertyInfo)expression.Member;
    var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;

    if (attr==null) {
        throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
    }

    return valueSelector(attr);
}

}

Mit der statischen Methode ...

var length = AttributeHelpers.GetStringLength<User>(x => x.Address1);

Oder die optionale Erweiterungsmethode für eine Instanz verwenden ...

var player = new User();
var length = player.GetStringLength(x => x.Address1);

Oder die vollständige statische Methode für jedes andere Attribut verwenden ...

var length = AttributeHelpers.GetPropertyAttributeValue<User,string,StringLengthAttribute,Int32>(prop => prop.Address1,attr => attr.MaximumLength);

Inspiriert von der Antwort hier ... https://stackoverflow.com/a/32501356/324479


1
2018-03-28 19:10