Pertanyaan atribut maxlength dari kotak teks dari DataAnnotations StringLength di Asp.Net MVC


Saya sedang mengerjakan aplikasi MVC2 dan ingin mengatur atribut maxlength dari input teks.

Saya telah mendefinisikan atribut stringlength pada objek Model menggunakan anotasi data dan memvalidasi panjang string yang dimasukkan dengan benar.

Saya tidak ingin mengulangi pengaturan yang sama dalam pandangan saya dengan mengatur atribut panjang maksimal secara manual ketika model sudah memiliki informasi. Apakah ada cara untuk melakukan ini?

Potongan kode di bawah ini:

Dari Model:

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

Dari Tampilan:

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

Yang ingin saya hindari adalah:

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

Saya ingin mendapatkan output ini:

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

Apakah ada cara untuk melakukan ini?


76
2018-03-05 11:36


asal


Jawaban:


Saya tidak menyadari cara apa pun untuk mencapai ini tanpa menggunakan refleksi. Anda bisa menulis metode pembantu:

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);
}

yang bisa Anda gunakan seperti ini:

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

50
2018-03-05 12:00



Jika Anda menggunakan validasi tidak mengganggu, Anda dapat menangani sisi klien ini juga:

$(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



Saya menggunakan CustomModelMetaDataProvider untuk mencapai ini

Langkah 1. Tambahkan kelas CustomModelMetadataProvider Baru

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;
    }
}

Langkah 2. Di Global.asax Daftarkan CustomModelMetadataProvider

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

Langkah 3. Dalam Views / Shared / EditorTemplates Tambahkan tampilan parsial bernama String.ascx

<%@ 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  })%>
<% } %>

Selesai ...

Edit. Langkah 3 bisa mulai menjadi jelek jika Anda ingin menambahkan lebih banyak barang ke kotak teks. Jika ini adalah kasus Anda, Anda dapat melakukan hal berikut:

<%@ 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



Jika Anda ingin ini bekerja dengan kelas metadata, Anda perlu menggunakan kode berikut. Saya tahu itu tidak cantik tetapi mendapat pekerjaan yang dilakukan dan mencegah Anda dari harus menulis properti maxlength Anda di kedua kelas Entity dan View:

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);
}

Kelas contoh:

[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



Sementara saya secara pribadi mencintai jazery javascript, inilah pendekatan lain untuk menjaga satu-sumber-kebenaran di model Anda ...

Tidak cantik, tapi .. telah berhasil. untuk saya...

Alih-alih menggunakan dekorasi properti, saya hanya mendefinisikan beberapa konstanta publik bernama baik di perpustakaan model saya / dll, dan kemudian referensi mereka dalam pandangan saya melalui HtmlAttributes, mis.

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

Kemudian, dalam file tampilan silet, di EditorFor ... gunakan objek HtmlAttirubte dalam overload, berikan properti panjang maksimal yang diinginkan dan referenece konstanta .. Anda harus menyediakan konstanta melalui jalur namespace yang penuh quasi. .. MyCompany.MyModel.MAX_ZIPCODE_LENGTH .. karena tidak akan digantung langsung dari model, tetapi, berfungsi.


3
2017-11-19 17:18



Saya menemukan pendekatan berbasis refleksi Darwin sangat membantu. Saya menemukan bahwa itu sedikit lebih dapat diandalkan untuk menggunakan metadata ContainerType sebagai dasar untuk mendapatkan info properti, karena metode ini dapat dipanggil dalam template editor / tampilan MVC (di mana TModel akhirnya menjadi tipe sederhana seperti 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



Berikut adalah beberapa metode statis yang dapat Anda gunakan untuk mendapatkan StringLength, atau atribut lainnya.

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);
}

}

Menggunakan metode statis ...

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

Atau menggunakan metode ekstensi opsional pada suatu instance ...

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

Atau menggunakan metode statis lengkap untuk atribut lainnya ...

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

Terinspirasi oleh jawabannya di sini ... https://stackoverflow.com/a/32501356/324479


1
2018-03-28 19:10