2011-12-02 28 views
14

Tôi có một mô hình đơn giản:Làm thế nào để vô hiệu hóa ModelMetadata.IsRequired từ luôn luôn là đúng đối với không nullable kiểu giá trị

public class Sample 
{ 
    public bool A { get; set; } 

    [Required] 
    public bool B { get; set; } 
} 

A được rõ ràng là không cần thiết. Do đó, để xác nhận đã thiết lập DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false trong Global.asax.

Tôi cũng có một helper html đơn giản mà in đúng hay sai nếu mô hình được yêu cầu:

public static class HtmlHelperExtensions 
{ 
    public static MvcHtmlString IsRequired<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) 
    { 
     var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);   
     return new MvcHtmlString(metadata.IsRequired.ToString()); 
    } 
} 

Tôi cũng đã viết một cái nhìn để giới thiệu vấn đề của tôi:

@model MvcApplication10.Models.Sample 

A: @Html.IsRequired(m => m.A), B: @Html.IsRequired(m => m.B) 

tôi lại có thể ngờ tuy nhiên, điều này để in A: false, B: true, tuy nhiên, nó thực sự in A: true, B: true.

Có cách nào để in kết quả mong đợi của tôi không? IsRequired dường như luôn trả về true mặc dù tôi chưa đặt rõ ràng RequiredAttribute. Theo mặc định, trạng thái docs là đúng cho các loại giá trị không thể vô hiệu hóa. Làm thế nào đến không có cách dễ dàng để thiết lập này để sai như chúng ta có thể với xác nhận?

EDIT: Tôi có thể viết một nhà cung cấp tùy chỉnh như thế này, nhưng tôi đã tự hỏi nếu có một cách "dễ dàng" xung quanh này:

public class ExtendedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    private static bool addImplicitRequiredAttributeForValueTypes = false; 

    public static bool AddImplicitRequiredAttributeForValueTypes 
    { 
     get 
     { 
      return addImplicitRequiredAttributeForValueTypes; 
     } 
     set 
     { 
      addImplicitRequiredAttributeForValueTypes = value; 
     } 
    } 

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) 
    { 
     var result = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 

     if (!AddImplicitRequiredAttributeForValueTypes && modelType.IsValueType && !attributes.OfType<RequiredAttribute>().Any()) 
     { 
      result.IsRequired = false; 
     } 

     return result; 
    } 
} 
+2

Trong MVC5 chỉ đơn giản là thiết lập 'DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false' sao bây giờ có tác dụng dự kiến ​​không tự động thêm' RequiredAttribute' cho giá trị không nullable loại. – Cocowalla

Trả lời

3

Tôi đoán bạn đang phải đối mặt với một lỗi MVC. Cần sẽ luôn kích hoạt vào tình hình đó, không có vấn đề gì và thậm chí nếu bạn sử dụng

DataAnnotationsModelValidatorProvider 
    .AddImplicitRequiredAttributeForValueTypes = false; 

Đây là đã thảo luận và báo cáo herehere. Ví dụ này đi một bước xa hơn và cho thấy rằng khi một yêu cầu tiềm ẩn kích hoạt nó không ngăn không cho IValidatableObject thực thi. Nếu bạn chạy bản trình diễn từ liên kết thứ hai, bạn có thể tạo lại trường hợp của mình, khi được yêu cầu luôn đúng.

Dù sao, điều này rất dễ dàng để giải quyết bởi vì nếu bạn đang nói rằng A is obviously not required cũng giống như nói rằng nó là nullable, vì vậy chỉ cần làm theo cách đó:

public bool? A { get; set; } 
+0

Đặt thuộc tính thành 'bool?' Có nghĩa là tôi không thể sử dụng trình trợ giúp html tích hợp như 'CheckBoxFor' yêu cầu boolean. Có - Tôi có thể viết trình trợ giúp html của riêng mình, nhưng tôi vẫn tò mò muốn xem liệu viết một nhà cung cấp siêu dữ liệu mô hình như tôi đã làm trong OP có ý nghĩa hơn không. – TheCloudlessSky

+0

Là hành vi mong đợi của bạn, và xem xét rằng MVC hiện đang cư xử theo cách này, tôi đoán rằng một nhà cung cấp tùy chỉnh là lựa chọn duy nhất của bạn. – Joao

+0

Thuộc tính 'A' có kích hoạt xác thực không? Bởi vì 'IsRequired' là' true' không có nghĩa là thuộc tính không hợp lệ. – Joao

0

Tôi đã có vấn đề này trong một số địa điểm và đã thực hiện một sửa chữa đơn giản như thế này

if (metadata.ModelType == typeof(System.Boolean)) 
{ 
    metadata.IsRequired = false; 
} 
10

Như bạn đã biết, ValueTypes sẽ mặc định là đúng. Để giải quyết vấn đề đó, bạn có thể kiểm tra RequiredAttribute nếu loại là ValueType.

ModelMetadata metaData = ModelMetadata.FromLambdaExpression<TModel, TValue>(expression, html.ViewData); 

if ((metaData.ModelType.IsValueType && metaData.ModelType.GetCustomAttributes(typeof(RequiredAttribute), false).Any()) || 
    (!metaData.ModelType.IsValueType && metaData.IsRequired)) 
{ ... } 
+0

Điều này thật tuyệt vời. Trong trường hợp nó giúp bất cứ ai, tôi đã phải đặt cùng một phương pháp mở rộng nhãn được đặt chuỗi html "*" thích hợp ở phía trước của trường lable nếu trường được yêu cầu. Đó là MVC5 và tôi vẫn đang gặp một số vấn đề với ValueTypes trả về true. Có rất nhiều trường biểu mẫu (49), vì vậy tôi đã thay đổi ở trên để sử dụng sự phản chiếu để tìm kiếm siêu dữ liệu.ContainerType để định vị thuộc tính mong muốn: metaData.ModelType.IsValueType && metadata.ContainerType.GetProperty (metadata.PropertyName) .GetCustomAttributes (typeof (RequiredAttribute), false) .Bất kỳ(). – bphillips

1

Sau đây sẽ trả về true hoặc false tùy thuộc vào việc bạn có [Bắt buộc] hay không.

typeof(<YourModel>).GetProperty(<PropertyName>).GetCustomAttributes(typeof(RequiredAttribute), false).Any()

3

Nếu bạn đang làm việc trong một EditorTemplate, như tôi là, bạn sẽ cần thêm một bước:

var metaData = ModelMetadata.FromLambdaExpression(Model => Model, ViewData); 

var required = metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof (RequiredAttribute), false).Any(); 

Bạn cần phải nhận được loại container từ các siêu dữ liệu mô hình để kiểm tra các thuộc tính của thuộc tính cụ thể của bạn; nếu không, bạn chỉ cần kiểm tra các thuộc tính thuộc loại dữ liệu của thuộc tính, không phải thuộc tính của thuộc tính.

+0

bạn lưu ngày của tôi: D – senzacionale

+0

Điều này cũng làm việc trên MVC5.2. @ ViewData.ModelMetadata.IsRequired –

0

Nếu bạn muốn nó để làm việc với nhiều loại nullable quá:

private static bool RequiredAttrExists(ModelMetadata metaData) 
{ 
    if(!metaData.ModelType.IsValueType && metaData.IsRequired) 
     return true; 
    else if (metaData.ModelType.IsValueType && metaData.ContainerType.GetProperty(metaData.PropertyName).GetCustomAttributes(typeof(RequiredAttribute), false).Any()) 
     return true; 
    return false; 
} 
Các vấn đề liên quan