6

Tôi đã tạo thuộc tính xác thực CompareLessThan tùy chỉnh bằng cách sao chép ASP.NET MVC 3 CompareAttribute và thay vì kiểm tra tính bình đẳng, tôi kiểm tra xem một thuộc tính có nhỏ hơn giá trị khác không. Nếu có lỗi phía máy khách, thông báo '{0} phải nhỏ hơn {1}' được hiển thị cho người dùng.ASP.NET MVC ValidationAttribute Nhận Tên Hiển thị Thuộc tính Khác

Mô hình của tôi được thiết lập như sau với thuộc tính Hiển thị tham chiếu tệp tài nguyên.

[CompareLessThan("AmountAvailable", ErrorMessageResourceName="CompareLessThan", ErrorMessageResourceType = typeof(Resources.ValidationMessages))] 
[Display(Name = "Amount", ResourceType = typeof(Resources.Labels))] 
public decimal Amount { get; set; } 

[Display(Name = "AmountAvailable", ResourceType = typeof(Resources.Labels))] 
public decimal AmountAvailable { get; set; } 

Sau đó, tùy chỉnh GetClientValidationRules xác nhận phương pháp là chính xác giống như trong CompareAttribute

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
{    
    yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(OtherProperty), this.AllowEquality); 
} 

Ở đây chúng ta đang tạo ra các thông báo lỗi sẽ được hiển thị cho người dùng nếu có một vấn đề. Tôi có thể lấy tên hiển thị từ tệp tài nguyên cho thuộc tính được trang trí với thuộc tính CompareLessThan tùy chỉnh của tôi, nhưng câu hỏi của tôi là làm cách nào để tôi lấy tên hiển thị của thuộc tính 'khác' mà chúng ta so sánh? Trong phương thức IsValid chúng ta có một tham chiếu đến validationContext mà từ đó tôi có thể tạo ra một đối tượng PropertyInfo cho thuộc tính 'other' và tôi nghĩ rằng có tên hiển thị. Nhưng, trong GetClientValidationRules tôi không có quyền truy cập vào đó.

Tôi luôn có thể chuyển giá trị khác cho tên hiển thị của thuộc tính khác nhưng tôi đã hy vọng sẽ có cách để lấy nó như tôi đã chỉ định nó bằng chú thích dữ liệu.

Bất kỳ ý tưởng nào?

Trả lời

5

Câu trả lời được cung cấp bởi nemesv đã không làm việc là tài sản metadata.Model có giá trị 0. Nhưng, qua siêu dữ liệu chúng tôi có tên đầy đủ của các mô hình để nó có thể tạo ra một mới ví dụ của mô hình đó và sau đó tạo một DataAnnonationsModelMetadataProvider mới từ cá thể tạo đó. Từ đó chúng ta có thể lấy tên hiển thị của thuộc tính khác.

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
{ 
    Type type = Type.GetType(metadata.ContainerType.FullName); 
    var model = Activator.CreateInstance(type); 

    var provider = new DataAnnotationsModelMetadataProvider(); 
    var otherMetaData = provider.GetMetadataForProperty(() => model, type, this.OtherProperty); 

    this.otherPropertyDisplayName = otherMetaData.DisplayName; 

    yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality); 
} 

Tôi thực sự không thích giải pháp này (mặc dù nó hoạt động) vì có vẻ như nên có cách tốt hơn. Có ai khác có ý tưởng nào khác không?

4

tôi đã không thử nó ra nhưng bạn có thể nhận được các thuộc tính mô hình với metadata.Properties tài sản

metadata.Properties.Single(p => p.PropertyName == "OtherPropName").DisplayName; 

EDIT: Bởi vì thuộc tính là trống gì bạn luôn có thể làm (mặc dù nó rất tao nhã). Bạn có thể tạo siêu dữ liệu cho chính mình.

var provider = new DataAnnotationsModelMetadataProvider(); 
var otherMetaData = provider.GetMetadataForProperty(() => metaData.Model, metaData.ModelType, "OtherPropertyName"); 
+0

Suy nghĩ tốt nhưng bộ sưu tập Thuộc tính luôn trống. –

+0

@NickOlsen Thật đáng buồn. Tôi đã cập nhật câu trả lời của mình với một số cách giải quyết khác. – nemesv

+0

Điều đó không làm việc hoặc là siêu dữ liệu.Model tài sản chỉ là giá trị 0. Sử dụng logic của bạn tôi đã có thể tìm ra một cách khác để làm điều đó (xem câu trả lời khác) nhưng tôi không thực sự thích nó. Tôi hy vọng có một cách tốt hơn mà người khác có thể cung cấp. –

6

Tính đến ASP.NET MVC 4 đây là cách tôi quản lý để có được những tài sản khác:

PropertyInfo otherPropertyInfo = 
        this.Metadata.ContainerType.GetProperty(attribute.DependentProperty); 

Sau đó, tôi nhận được Display attribute từ bất động sản:

var displayAttribute = 
    otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true). 
    FirstOrDefault() as DisplayProperty; 

Trong trường hợp của bạn:

// GetName() is important to get the translated name if you're using a resource file... 
this.otherPropertyDisplayName = displayAttribute.GetName(); 

GetName() tham chiếu:

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.name%28v=vs.95%29.aspx

+0

Điều đó có nghĩa là "là DisplayProperty" hay "là DisplayAttribute"? Tôi đã không làm việc cho DisplayProperty nhưng làm việc tốt cho DisplayAttribute. Giải pháp tuyệt vời khác. – MVCKarl

+0

@MVCKarl: Tôi nghĩ bạn nói đúng ... Có lẽ đó là một chút nhầm lẫn khi gõ câu trả lời ở đây. Tôi không thể ghi lại những gì tôi đã làm chính xác tại thời điểm đó. :) –