Câu hỏi thuộc tính maxlength của một hộp văn bản từ DataAnnotations StringLength trong Asp.Net MVC


Tôi đang làm việc trên một ứng dụng MVC2 và muốn thiết lập các thuộc tính maxlength của các đầu vào văn bản.

Tôi đã xác định thuộc tính stringlength trên đối tượng Model bằng cách sử dụng các chú thích dữ liệu và nó đang xác nhận hợp lệ độ dài của các chuỗi được nhập chính xác.

Tôi không muốn lặp lại cùng một cài đặt trong chế độ xem của mình bằng cách đặt thuộc tính độ dài tối đa theo cách thủ công khi mô hình đã có thông tin. Có cách nào để làm điều này không?

Đoạn mã dưới đây:

Từ mô hình:

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

Từ Chế độ xem:

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

Những gì tôi muốn tránh làm là:

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

Tôi muốn có được kết quả này:

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

Có cách nào để làm điều này không?


76
2018-03-05 11:36


gốc


Tôi xin lỗi, tôi không biết những gì Annonations dữ liệu là tốt cho? Ý tôi là, nếu tiêu chí độ dài thay đổi thì sao? Điều này có thể không được điều khiển động (khi chạy), dựa trên một số siêu dữ liệu không? - shahkalpesh


Các câu trả lời:


Tôi không nhận thức được bất kỳ cách nào để đạt được điều này mà không phải dùng đến sự phản chiếu. Bạn có thể viết một phương thức trợ giúp:

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

mà bạn có thể sử dụng như thế này:

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

50
2018-03-05 12:00



Tôi nhận được lỗi 1 'System.Web.Mvc.HtmlHelper <TModel>' không chứa định nghĩa cho 'TextBoxFor' và không có phương pháp mở rộng 'TextBoxFor' chấp nhận đối số đầu tiên của loại 'System.Web.Mvc.HtmlHelper <TModel > 'có thể được tìm thấy (bạn đang thiếu một chỉ thị bằng cách sử dụng hoặc một tham chiếu lắp ráp?) Tại dòng này: trả về htmlHelper.TextBoxFor <TModel> (biểu thức, thuộc tính); - sabbour
using System.Web.Mvc.Html? - Darin Dimitrov
Yeah tôi figured rằng ra đã :) Tôi có một vấn đề khác mặc dù, chú thích dữ liệu của tôi được định nghĩa trên các lớp MetaData hơn là mô hình chính nó. Sự phản chiếu không phải là chọn chúng! - sabbour
Cảm ơn câu trả lời. Tôi đang gặp vấn đề với các thuộc tính có chứa _, chúng không được tự động chuyển đổi thành -. Bạn có biết một cách khác hơn thay thế _ bằng tay và điền vào một RouteValueDictionary mới ?. - Juan


Nếu bạn đang sử dụng xác thực không phô trương, bạn cũng có thể xử lý phía máy khách này:

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



Trong khi cách tiếp cận của bạn sẽ cho phép tôi xác nhận - tôi đã thực sự sau khi đặt thuộc tính maxlength trên đầu vào vì nó sẽ ngăn người dùng thêm nhiều ký tự trong trình duyệt và sẽ hoạt động bất kể javascript đang chạy trong trình duyệt hay không. - Pervez Choudhury
Đó chính xác là điều này. Nó sử dụng thuộc tính xác thực chiều dài tối đa dữ liệu để thiết lập thuộc tính maxlenth đầu vào. - jrummell
Tôi đã thực sự vui mừng bởi câu trả lời phản ánh đầu tiên, nhưng điều này có vẻ để đạt được kết quả tương tự mà không cần bất kỳ mã máy chủ phức tạp nào. Làm tốt lắm. Bạn sẽ nhận được nhiều phiếu bầu hơn. - Brian White
+1 Ý tưởng tuyệt vời cho các biểu mẫu Ajax. Tôi đồng ý với Brian White rằng câu trả lời này xứng đáng được nhiều phiếu bầu hơn. - Waleed Eissa
Tôi bị mất một phần về OP cần xác nhận mà không có javascript. Nhưng tôi vui vì điều này đã giúp những người khác tìm kiếm một giải pháp javascript. - jrummell


Tôi sử dụng CustomModelMetaDataProvider để đạt được điều này

Bước 1. Thêm lớp CustomModelMetadataProvider mới

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

Bước 2. Trong Global.asax Đăng ký CustomModelMetadataProvider

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

Bước 3. Trong Views / Shared / EditorTemplates Thêm một khung nhìn từng phần có tên 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  })%>
<% } %>

Làm xong...

Chỉnh sửa. Bước 3 có thể bắt đầu trở nên xấu xí nếu bạn muốn thêm nhiều nội dung hơn vào hộp văn bản. Nếu đây là trường hợp của bạn, bạn có thể làm như sau:

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





Nếu bạn muốn điều này làm việc với một lớp siêu dữ liệu, bạn cần sử dụng mã sau đây. Tôi biết nó không đẹp nhưng nó được thực hiện công việc và ngăn cản bạn phải viết các thuộc tính maxlength của bạn trong cả lớp Entity và 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);
}

Lớp mẫu:

[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





Trong khi cá nhân tôi yêu thích sửa chữa jrummel của jrummel, đây là một cách tiếp cận khác để giữ một nguồn duy nhất của sự thật trong mô hình của bạn ...

Không đẹp, nhưng .. đã làm việc o.k. cho tôi...

Thay vì sử dụng trang trí thuộc tính, tôi chỉ xác định một số hằng số công khai được đặt tên trong thư viện mô hình / dll của tôi và sau đó tham chiếu chúng trong chế độ xem của tôi qua HtmlAttributes, ví dụ:

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

Sau đó, trong tệp xem dao cạo, trong EditorFor ... sử dụng đối tượng HtmlAttirubte trong quá tải, cung cấp thuộc tính độ dài tối đa mong muốn và tham chiếu hằng số .. bạn sẽ phải cung cấp hằng số thông qua đường dẫn không gian tên đầy đủ. .. MyCompany.MyModel.MAX_ZIPCODE_LENGTH .. vì nó sẽ không được treo ngay ra khỏi mô hình, nhưng, nó hoạt động.


3
2017-11-19 17:18





Tôi thấy cách tiếp cận dựa trên phản chiếu của Darin đặc biệt hữu ích. Tôi thấy rằng nó đáng tin cậy hơn một chút để sử dụng siêu dữ liệu ContainerType làm cơ sở để lấy thông tin thuộc tính, vì phương thức này có thể được gọi trong các mẫu trình soạn thảo / hiển thị mvc (ở đâu TModel kết thúc là một loại đơn giản như 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





Dưới đây là một số phương pháp tĩnh bạn có thể sử dụng để lấy StringLength hoặc bất kỳ thuộc tính nào khác.

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

}

Sử dụng phương pháp tĩnh ...

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

Hoặc sử dụng phương pháp mở rộng tùy chọn trên một cá thể ...

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

Hoặc sử dụng phương thức tĩnh hoàn chỉnh cho bất kỳ thuộc tính nào khác ...

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

Lấy cảm hứng từ câu trả lời ở đây ... https://stackoverflow.com/a/32501356/324479


1
2018-03-28 19:10