Ich arbeite an einer MVC2-Anwendung und möchte die MaxLängenattribute der Texteingaben festlegen.
Ich habe das Attribut stringlength für das Model-Objekt bereits mithilfe von Datenanmerkungen definiert und es überprüft die Länge der eingegebenen Zeichenfolgen korrekt.
Ich möchte dieselbe Einstellung in meinen Ansichten nicht wiederholen, indem ich das Attribut für die maximale Länge manuell einstelle, wenn das Modell bereits über die Informationen verfügt. Gibt es eine Möglichkeit, dies zu tun?
Code-Schnipsel 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?
asp.net-mvc
validation
Pervez Choudhury
quelle
quelle
Antworten:
Mir ist kein Weg bekannt, dies zu erreichen, ohne auf Reflexion zurückzugreifen. 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 Sie so verwenden könnten:
<%= Html.CustomTextBoxFor(model => model.Address1, new { @class = "text long" })%>
quelle
Wenn Sie eine unauffällige Validierung verwenden, können Sie auch diese Clientseite behandeln:
$(document).ready(function () { $("input[data-val-length-max]").each(function () { var $this = $(this); var data = $this.data(); $this.attr("maxlength", data.valLengthMax); }); });
quelle
Ich benutze den CustomModelMetaDataProvider, um dies zu erreichen
Schritt 1. Fügen Sie eine 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. Registrieren Sie in Global.asax den CustomModelMetadataProvider
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); ModelMetadataProviders.Current = new CustomModelMetadataProvider(); }
Schritt 3. Fügen Sie in Views / Shared / EditorTemplates eine Teilansicht mit dem Namen 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. Schritt 3 kann hässlich werden, wenn Sie dem Textfeld weitere Inhalte hinzufügen möchten. In diesem Fall 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)%>
quelle
Wenn dies mit einer Metadatenklasse funktionieren soll, müssen Sie den folgenden Code verwenden. Ich weiß, dass es nicht schön ist, aber es erledigt den Job und verhindert, dass Sie Ihre Eigenschaften für die maximale Länge sowohl in der Entity-Klasse als auch in 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; } /* ... */ } }
quelle
Während ich persönlich jrummels jquery fix liebe, ist hier ein anderer Ansatz, um eine einzige Quelle der Wahrheit in Ihrem Modell aufrechtzuerhalten ...
Nicht schön, aber ... hat bei mir gut funktioniert ...
Anstatt Eigenschaftsdekorationen zu verwenden, definiere ich einfach einige gut benannte öffentliche Konstanten in meiner Modellbibliothek / DLL und verweise 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 Rasiereransichtsdatei im EditorFor ... ein HtmlAttirubte-Objekt in der Überladung, geben Sie die gewünschte Eigenschaft für die maximale Länge an und verweisen Sie auf die Konstante. Sie müssen die Konstante über einen vollständig qualifizierten Namespace-Pfad angeben. .. MyCompany.MyModel.MAX_ZIPCODE_LENGTH .. da es nicht direkt am Modell hängt, aber es funktioniert.
quelle
Ich fand Darins auf Reflexion basierenden Ansatz besonders hilfreich. Ich fand, dass es etwas zuverlässiger war, die Metadaten
ContainerType
als Grundlage für das Abrufen der Eigenschaftsinformationen zu verwenden, da diese Methode in MVC-Editor- / Anzeigevorlagen aufgerufen werden kann (wobei es sich letztendlich umTModel
einen einfachen Typ wie z. B. handeltstring
).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); }
quelle
Hier sind einige statische Methoden, mit denen Sie die StringLength oder ein anderes Attribut abrufen können.
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 verwenden Sie die optionale Erweiterungsmethode für eine Instanz ...
var player = new User(); var length = player.GetStringLength(x => x.Address1);
Oder verwenden Sie die vollständige statische Methode für jedes andere Attribut ...
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
quelle