9

DataAnnotations không hoạt động với lớp bạn thân. Mã sau luôn xác thực đúng. Tại sao ?Xác thực không hoạt động khi tôi sử dụng Validator.TryValidateObject

var isValid = Validator.TryValidateObject (Khách hàng mới(), Ngữ cảnh, kết quả, đúng);

và đây là lớp bạn thân.

public partial class Customer 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

[MetadataType(typeof(CustomerMetaData))] 
public partial class Customer 
{ 
    public class CustomerMetaData 
    { 
     [Required(ErrorMessage = "You must supply a name for a customer.")]   
     public string Name { get; set; } 
    } 
} 

Đây là một chuỗi khác có cùng câu hỏi, nhưng không có câu trả lời. link text

+0

Tôi không hề lo lắng về điều này, nhưng tôi nghĩ bạn không nên tổ chức các lớp học. Ngoài ra tôi nghĩ rằng điều này có thể làm cho lớp CustomMetaData không thể tiếp cận mà không có từ khóa công cộng. Hãy thử di chuyển CustomerMetaData ra khỏi lớp Khách hàng và đặt nó ở chế độ công khai. – Alxandr

+0

Nó sẽ không hoạt động ngay cả khi tôi di chuyển CustomerMetaData ra khỏi lớp Customer và khai báo là public. Tôi có mối quan tâm mà TryValidateObject hỗ trợ buddyclass (MetadataType)? – ashraf

Trả lời

27

Tôi tìm thấy câu trả lời ở đây: http://forums.silverlight.net/forums/p/149264/377212.aspx

MVC nhận thuộc tính MetaDataType, nhưng các dự án khác thì không. Trước khi xác nhận, bạn cần phải tự đăng ký lớp siêu dữ liệu:

TypeDescriptor.AddProviderTransparent(
      new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetadata)), typeof(Customer)); 

var isValid = Validator.TryValidateObject(new Customer(), context, results, true); 
+1

Cảm ơn. Nếu tôi chọn chú thích dữ liệu làm khung Xác thực của tôi thì Validator.TryValidaeObject sẽ xác thực từ mọi nơi. – ashraf

+0

cảm ơn câu trả lời hay! +1 – Karamafrooz

+0

Không có quá tải khởi tạo cho lớp AssociatedMetadataTypeTypeDescriptionProvider mất ba đối số. Tôi thấy vấn đề này với đoạn mã. – RBT

1

Mặc dù tôi đã không kiểm tra mã của bạn trong .NET 4.0, trong .NET 3.5/Silverlight 3, lớp siêu dữ liệu của bạn sẽ giống như thế này:

[MetadataType(typeof(Customer.CustomerMetaData))] 
public partial class Customer 
{ 
    internal sealed class CustomerMetaData 
    { 
     private CustomerMetaData() 
     { 
     } 

     [Required(ErrorMessage = "You must supply a name for a customer.")]   
     public string Name; 
    } 
} 
+0

Không, nó vẫn không hoạt động. Tôi nghĩ đó là một lỗi. – ashraf

4

Sau khi một số nghiên cứu tôi không thể tìm thấy bất kỳ lý do tại sao TryValidateObject luôn trả về true nếu tôi sử dụng MetadataType (lớp buddy). Nhưng nó hoạt động với đoạn mã sau (xVal).

public static IEnumerable<ErrorInfo> GetErrors(object instance, string name) 
    { 
     var metadataAttrib = instance.GetType() 
       .GetCustomAttributes(typeof(MetadataTypeAttribute), true) 
       .OfType<MetadataTypeAttribute>().FirstOrDefault(); 
     var buddyClassOrModelClass = metadataAttrib != null 
       ? metadataAttrib.MetadataClassType 
       : instance.GetType(); 
     var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass) 
      .Cast<PropertyDescriptor>(); 
     var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()) 
      .Cast<PropertyDescriptor>(); 

     var list = from buddyProp in buddyClassProperties 
        join modelProp in modelClassProperties on 
          buddyProp.Name equals modelProp.Name 
        from attribute in buddyProp.Attributes.OfType<ValidationAttribute>() 
        where !attribute.IsValid(modelProp.GetValue(instance)) 
        select new ErrorInfo(
         buddyProp.Name, 
         attribute.FormatErrorMessage(modelProp.Name), 
         instance); 

     if (name != null) 
      list = list.Where(x => x.PropertyName == name); 

     return list; 
    } 
1

Có một vấn đề mà các thuộc tính MetadataType không được công nhận bởi các bối cảnh đối tượng. Trong khi bạn có thể tự thêm các mô tả loại trước khi xác nhận: TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetaData)), typeof(Customer));

một cách ngắn gọn hơn để xử lý nó sẽ được cập nhật các tập tin .tt Entity Model, để thêm dòng sau vào mỗi DTO:

Type currentType = MethodBase.GetCurrentMethod().DeclaringType; 
    object[] attributes = currentType.GetCustomAttributes(typeof(MetadataTypeAttribute),false); 
    if(attributes.Length > 0) 
    { 
     //MetadataType attribute found! 
     MetadataTypeAttribute metaDataAttribute = (MetadataTypeAttribute)attributes[0]; 
     TypeDescriptor.AddProviderTransparent(
      new AssociatedMetadataTypeTypeDescriptionProvider(
       currentType, metaDataAttribute.MetadataClassType),currentType); 
    } 

Điều này sẽ cho phép bạn thêm thuộc tính vào các lớp học một phần:

[MetadataType(typeof(CustomerMetaData))] 
public partial class Customer 
{ 

} 

public partial class CustomerMetaData 
{ 
    [Required] 
    public string CustomerName { get; set; } 
} 
+0

Xin chào @Gareth Suarez, tôi nghĩ đây là một ý tưởng tuyệt vời, bạn có thể cung cấp thêm thông tin về cách chỉnh sửa tệp Entity Model.tt không? –

+1

Tôi thực sự đã cố gắng làm điều đó, nhưng tôi không biết tôi nên đưa đoạn mã của bạn vào đâu. Tôi đã thử bao gồm nó trong các nhà xây dựng của mỗi DTO nhưng tôi không có may mắn cả. Bất kỳ ý tưởng? BTW, tôi đang cố gắng để thiết lập IgnoreDataMember trong một số các thuộc tính thông qua MetadataType, phương pháp này sẽ làm việc, phải không? –

Các vấn đề liên quan