Asp.net mvc 带有MVC验证的CustomTypeDescriptor-如何使用property.GetValue(组件)获取属性值?

Asp.net mvc 带有MVC验证的CustomTypeDescriptor-如何使用property.GetValue(组件)获取属性值?,asp.net-mvc,validation,validationattribute,typedescriptor,customtypedescriptor,Asp.net Mvc,Validation,Validationattribute,Typedescriptor,Customtypedescriptor,我已经为我的一个MVC模型创建了自定义TypeDescriptionProvider。我使用它动态分配ValidationAttribute 我使用一个属性的值来决定向其他属性添加哪些属性。在我使用DataAnnotationsValidationRunner的web服务中,验证工作正常 转轮来源: 内部静态类DataAnnotationsValidationRunner { 公共静态IEnumerable GetErrors(对象实例) { 从TypeDescriptor.GetPropert

我已经为我的一个MVC模型创建了自定义TypeDescriptionProvider。我使用它动态分配ValidationAttribute

我使用一个属性的值来决定向其他属性添加哪些属性。在我使用DataAnnotationsValidationRunner的web服务中,验证工作正常

转轮来源:

内部静态类DataAnnotationsValidationRunner
{
公共静态IEnumerable GetErrors(对象实例)
{
从TypeDescriptor.GetProperties(instance.Cast()中的prop返回
来自类型()的prop.Attributes.of中的属性
其中!attribute.IsValid(prop.GetValue(实例))
选择新的ErrorInfo(prop.Name,attribute.FormatErrorMessage(string.Empty),instance);
}
}
要获取属性值,我使用以下代码(在MyCustomTypeDescriptor中)

public override PropertyDescriptorCollection GetProperties()
{
var originalProperties=base.GetProperties();
var newProperties=newlist();
var myProperty=originalProperties.Find(“CountryCodeID”,false)
var myId=(int)countryProperty.GetValue(base.GetPropertyOwner(myProperty));
foreach(原始属性中的属性描述符pd)
{
AttributeCollection runtimeAttributes=pd.Attributes;
//基于myId值添加新属性
....
}
返回新的PropertyDescriptorCollection(newProperties.ToArray());
}
在MVC视图中将此模型与此描述符一起使用时,出现以下异常:

值不能为null。参数名称:主要描述:一个 执行当前网站时发生未处理的异常 要求请查看堆栈跟踪以了解有关堆栈的更多信息 错误及其在代码中的起源

异常详细信息:System.ArgumentNullException:值不能为null。 参数名称:主

在TypeDescriptor中获取属性值的正确方法是什么?我通过模型类型上的提供者使用这个描述符,而不是实例(例如global.asax)

编辑:我找到了解决办法。在MyTypeDescriptorProvider的GetTypeDescriptor方法中,我使用实例参数并将其传递给MyCustomTypeDescriptor的构造函数。然而,MVC验证并不可行。我认为它会自动使用这些动态数据(类似于上面提到的runner)

编辑2:使用变通方法,我几乎总是看到实例为空。所以不可能在那个里得到值并把它交给TypeDescriptor的构造函数


谢谢大家!

最后,我能够使用customTypeDescriptor生成客户端验证和绑定期间验证模型所需的HTML标记

第一个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;
    }
}
//
///在MVC Web和WCF服务中提供验证的CustomTypeDescriptor。
/// 
公共类MyCustomTypeDescriptionProvider:TypeDescriptionProvider
{
公共MyCustomTypeDescriptionProvider(TypeDescriptionProvider父级)
:基(父)
{
}
公共重写ICustomTypeDescriptor GetTypeDescriptor(类型objectType,对象实例)
{
返回新的MyCustomTypeDescriptor(base.GetTypeDescriptor(objectType,instance));
}
}
公共类MyCustomTypeDescriptor:CustomTypeDescriptor
{
公共MyCustomTypeDescriptor(ICustomTypeDescriptor父级)
:基(父)
{ }
公共重写PropertyDescriptorCollection GetProperties()
{
var originalProperties=base.GetProperties();
如果(这是必需的(原始财产))
{
var newProperties=newlist();
foreach(原始属性中的PropertyDescriptor属性)
{
var attrs=property.Attributes;
var newAttrs=新属性[attrs.Count+1];
属性CopyTo(newAttrs,0);
newAttrs[attrs.Count]=新的RequiredAttribute();
添加(TypeDescriptor.CreateProperty(property.ComponentType,property,newAttrs));
}
返回新的PropertyDescriptorCollection(newProperties.ToArray());
}
其他的
{
返回原始属性;
}
}
/// 
///IsRequired只是模拟更复杂的验证规则(取决于模型中的另一个值)
/// 
/// 
/// 
需要私人房产(房产描述或集合原始房产)
{
if(originalProperties==null | | originalProperties.Count==0)
{
抛出新ArgumentNullException();
}
var dependentProperty=originalProperties.Find(“dependentValue”,false);
if(dependentProperty==null)
{
抛出新的InvalidOperationException();
}
var value=(int)dependentProperty.GetValue(base.GetPropertyOwner(dependentProperty));
返回值>0;
}
}
然后要绑定此描述符(每个实例!),我使用MyModelValidatorProvider:

/// <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);
    }
}
//
///验证程序提供程序仅用于不引人注目的验证
/// 
公共类MyModelValidatorProvider:DataAnnotationsModelValidatorProvider
{
受保护的重写IEnumerable GetValidators(ModelMetadata元数据、ControllerContext上下文、IEnumerable


欢迎任何有助于使此解决方案更加优雅的改进。谢谢。

我已提交了此功能的请求,请参阅:
/// <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;
    }
}
/// <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);
    }
}
/// <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);
            }
        }
    }
}