1

내 MVC 모델 중 하나에 대해 사용자 정의 TypeDescriptionProvider를 만들었습니다. ValidationAttribute를 동적으로 할당하는 데 사용합니다.MVC 유효성 검사 기능이있는 CustomTypeDescriptor - property.GetValue (구성 요소)를 사용하여 속성 값을 얻는 방법?

하나의 속성 값을 사용하여 다른 속성에 추가 할 속성을 결정합니다. DataAnnotationsValidationRunner를 사용하는 웹 서비스에서 유효성 검사가 올바르게 작동합니다. 주자의

출처 : here

internal static class DataAnnotationsValidationRunner 
{ 
    public static IEnumerable<ErrorInfo> GetErrors(object instance) 
    { 
     return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>() 
       from attribute in prop.Attributes.OfType<ValidationAttribute>() 
       where !attribute.IsValid(prop.GetValue(instance)) 
       select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance); 
    } 
} 

이 MVC보기에서이 설명과 함께이 모델을 사용하는 경우 내가 (MyCustomTypeDescriptor에서) 코드

public override PropertyDescriptorCollection GetProperties() 
    { 
     var originalProperties = base.GetProperties(); 
     var newProperties = new List<PropertyDescriptor>(); 
     var myProperty = originalProperties.Find("CountryCodeID", false) 

     var myId = (int)countryProperty.GetValue(base.GetPropertyOwner(myProperty)); 

     foreach (PropertyDescriptor pd in originalProperties) 
     { 
      AttributeCollection runtimeAttributes = pd.Attributes; 

      // add new attributes based on myId value 
      .... 
     } 

     return new PropertyDescriptorCollection(newProperties.ToArray()); 
    } 

를 다음을 사용 속성 값을 얻으려면, 나는 다음과 같은 예외가 :

값은 null 일 수 없습니다. 매개 변수 이름 : 기본 설명 : 현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다. 오류 및 코드에서 시작된 위치에 대한 자세한 내용은 스택 추적을 검토하십시오.

예외 정보 : System.ArgumentNullException : 값은 null 일 수 없습니다. 매개 변수 이름 : 기본

TypeDescriptor 내에서 값의 올바른 값을 가져 오는 올바른 방법은 무엇입니까? 이 설명자는 인스턴스가 아닌 모델 유형의 공급자를 통해 사용됩니다 (예 : global.asax).

편집 : 해결 방법을 찾았습니다. MyTypeDescriptorProvider의 GetTypeDescriptor 메소드에서 인스턴스 매개 변수를 사용하여 MyCustomTypeDescriptor의 consctructor로 전달합니다. 그러나 MVC 유효성 검사는 작동하지 않습니다. 나는 자동으로 이러한 동적 데이터를 사용하지만 (위에서 언급 한 러너와 비슷 함).

편집 2 : workaroud를 사용하면 거의 항상 인스턴스 null이 표시됩니다. 그래서 거기에 가치를 부여하고 TypeDescriptor의 consctructor에 넣는 것은 불가능합니다 ...

고마워요!

답변

1

마지막으로 클라이언트 검증에 필요한 HTML 태그 생성과 바인딩 중에 모델 유효성 검사 모두에 대해 customTypeDescriptor를 사용할 수있었습니다.

먼저 MyCustomTypeDescriptor.cs :

/// <summary> 
/// CustomTypeDescriptor that provides validation in both MVC Web and WCF services. 
/// </summary> 
public class MyCustomTypeDescriptionProvider : TypeDescriptionProvider 
{ 
    public MyCustomTypeDescriptionProvider(TypeDescriptionProvider parent) 
     :base(parent) 
    { 

    } 

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
    { 
     return new MyCustomTypeDescriptor(base.GetTypeDescriptor(objectType, instance)); 
    } 
} 

public class MyCustomTypeDescriptor : CustomTypeDescriptor 
{ 
    public MyCustomTypeDescriptor(ICustomTypeDescriptor parent) 
     : base(parent) 
    { } 

    public override PropertyDescriptorCollection GetProperties() 
    { 
     var originalProperties = base.GetProperties(); 

     if (this.IsRequired(originalProperties)) 
     { 
      var newProperties = new List<PropertyDescriptor>(); 

      foreach (PropertyDescriptor property in originalProperties) 
      { 
       var attrs = property.Attributes; 
       var newAttrs = new Attribute[attrs.Count + 1]; 
       attrs.CopyTo(newAttrs, 0); 
       newAttrs[attrs.Count] = new RequiredAttribute(); 
       newProperties.Add(TypeDescriptor.CreateProperty(property.ComponentType, property, newAttrs)); 
      } 

      return new PropertyDescriptorCollection(newProperties.ToArray()); 
     } 
     else 
     { 
      return originalProperties; 
     } 
    } 

    /// <summary> 
    /// IsRequired just simulates more complex validation rule (dependant on another value in model) 
    /// </summary> 
    /// <param name="originalProperties"></param> 
    /// <returns></returns> 
    private bool IsRequired(PropertyDescriptorCollection originalProperties) 
    { 
     if (originalProperties == null || originalProperties.Count == 0) 
     { 
      throw new ArgumentNullException(); 
     } 

     var dependantProperty = originalProperties.Find("DependantValue", false); 

     if (dependantProperty == null) 
     { 
      throw new InvalidOperationException(); 
     } 

     var value = (int)dependantProperty.GetValue(base.GetPropertyOwner(dependantProperty)); 

     return value > 0; 
    } 
} 

그런 다음 (인스턴스 당!)이 기술자를 결합하는 내가 MyModelValidatorProvider 사용이 ModelBinding 동안 그러나, 잘 작동

/// <summary> 
/// validator provider is used only for unobtrusive validation 
/// </summary> 
public class MyModelValidatorProvider : DataAnnotationsModelValidatorProvider 
{ 
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) 
    { 
     var isPropertyValidation = metadata.ContainerType != null && !String.IsNullOrEmpty(metadata.PropertyName); 
     var model = context.Controller.ViewData.Model as TestCustomizedModel;    

     if (isPropertyValidation && model != null) 
     { 
      TypeDescriptor.AddProvider(new MyCustomTypeDescriptionProvider(TypeDescriptor.GetProvider(model)), model); 

      AttributeCollection newAttributes; 

      newAttributes = TypeDescriptor.GetProperties(model).Find(metadata.PropertyName, false).Attributes; 

      var attrArray = new Attribute[newAttributes.Count]; 

      newAttributes.CopyTo(attrArray, 0); 

      attributes = attrArray; 
     } 

     return base.GetValidators(metadata, context, attributes); 
    } 
} 

, 어떤을 ViewData가 설정되어 있지를 , ValidatorProvider는 후크하지 않습니다. 이에 대한 해결책은 내가 MyModelBinder에 사용 된 바와 같이 :

/// <summary> 
/// Model binder that attaches CustomTypeDescriptor and validates model. 
/// </summary> 
public class MyModelBinder : DefaultModelBinder 
{ 
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     base.OnModelUpdated(controllerContext, bindingContext); 

     TypeDescriptor.AddProvider(new MyCustomTypeDescriptionProvider(TypeDescriptor.GetProvider(bindingContext.Model)), bindingContext.Model); 

     var errors = DataAnnotationRunner.GetErrors(bindingContext.Model); 

     if (errors != null) 
     { 
      foreach (var error in errors) 
      { 
       bindingContext.ModelState.AddModelError(error.MemberNames.FirstOrDefault() ?? string.Empty, error.ErrorMessage); 
      } 
     } 
    } 
} 

는 지금은 모든 MVC 웹, 컨트롤러 이외 MVC 다른 클래스, HTML 헬퍼 (눈에 띄지 검증) 및 WCF 서비스와 같은 다른 프로젝트에서 유효성을 검사 DataAnnotationRunner와 MyCustomTypeDescriptor를 사용할 수 있습니다. ..

이 모든 것이 괜찮지 만, 옳다고 느끼지는 않습니다.MyCustomTypeDescriptor를 MVC에 직접 연결할 수 있다면 좋겠지 만,이 링크가 주장하는 것처럼 가능하지는 않습니다. 이 솔루션은 더 우아하게 도움을 줄 수

How can I provide my own ICustomTypeDescriptor in ASP.NET MVC?

모든 개선은 환영합니다. 고맙습니다.

+0

이 기능에 대한 요청을 제출했습니다. http : //aspnetwebstack.codeplex.com/SourceControl/network/forks/Flowster/aspnetwebstack/contribution/8164를 참조하십시오. – LunicLynx