应用运行时元数据类型进行验证
apply runtime metadatatype for validation
我需要对同一个对象进行不同的验证。所以我想使用元数据类型来定义代码如下的不同规则:
public class ValidateObjectAttribute : ValidationAttribute
{
private readonly Type _validationMetaDataType;
public ValidateObjectAttribute(Type validationMetaDataType)
{
_validationMetaDataType = validationMetaDataType;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var modelType = value.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (_validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, _validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
var validationctx = new ValidationContext(value);
var results = new List<ValidationResult>();
Validator.TryValidateObject(value, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(value);
}
if (results.Count == 0) return ValidationResult.Success;
return new ValidationResult($"Validation fail for prop: {validationContext.DisplayName}");
}
}
public class BarMetaData1
{
[Required]
public string BarField1;
[Required]
public string BarField2;
}
public class FooMetaData1
{
[Required]
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class FooMetaData2
{
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class BaseValidation
{
public bool IsValid(Type validationMetaDataType)
{
var modelType = this.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(this);
}
var validationctx = new ValidationContext(this);
var results = new List<ValidationResult>();
Validator.TryValidateObject(this, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
return results.Count == 0;
}
}
public class Foo : BaseValidation
{
public string FooField1 { get; set; }
public string FooField2 { get; set; }
public Bar FooObject1 { get; set; }
}
public class Bar
{
public string BarField1 { get; set; }
public string BarField2 { get; set; }
}
验证是这样调用的:
public void Index()
{
Foo fooInstance = new Foo()
{
FooObject1 = new Bar()
};
fooInstance.IsValid(typeof(FooMetaData2));
fooInstance.IsValid(typeof(FooMetaData1));
Foo fooInstance2 = new Foo()
{
FooObject1 = new Bar()
};
fooInstance2.IsValid(typeof(FooMetaData2));
}
问题是什么:
- 第一次验证 [fooInstance.IsValid(typeof(FooMetaData2))] 是正确的(缺少 2 个必填字段),
- 第二次验证调用 [fooInstance.IsValid(typeof(FooMetaData1))] 结果错误(缺少 3 个必填字段,但代码仅通知我 2),似乎代码应用了 FooMetaData2 中描述的验证class 而不是 FooMetaData1
谁能给我解释一下为什么?
谢谢
我使用 fluentValidator 插件解决了
我需要对同一个对象进行不同的验证。所以我想使用元数据类型来定义代码如下的不同规则:
public class ValidateObjectAttribute : ValidationAttribute
{
private readonly Type _validationMetaDataType;
public ValidateObjectAttribute(Type validationMetaDataType)
{
_validationMetaDataType = validationMetaDataType;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var modelType = value.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (_validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, _validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
var validationctx = new ValidationContext(value);
var results = new List<ValidationResult>();
Validator.TryValidateObject(value, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(value);
}
if (results.Count == 0) return ValidationResult.Success;
return new ValidationResult($"Validation fail for prop: {validationContext.DisplayName}");
}
}
public class BarMetaData1
{
[Required]
public string BarField1;
[Required]
public string BarField2;
}
public class FooMetaData1
{
[Required]
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class FooMetaData2
{
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class BaseValidation
{
public bool IsValid(Type validationMetaDataType)
{
var modelType = this.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(this);
}
var validationctx = new ValidationContext(this);
var results = new List<ValidationResult>();
Validator.TryValidateObject(this, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
return results.Count == 0;
}
}
public class Foo : BaseValidation
{
public string FooField1 { get; set; }
public string FooField2 { get; set; }
public Bar FooObject1 { get; set; }
}
public class Bar
{
public string BarField1 { get; set; }
public string BarField2 { get; set; }
}
验证是这样调用的:
public void Index()
{
Foo fooInstance = new Foo()
{
FooObject1 = new Bar()
};
fooInstance.IsValid(typeof(FooMetaData2));
fooInstance.IsValid(typeof(FooMetaData1));
Foo fooInstance2 = new Foo()
{
FooObject1 = new Bar()
};
fooInstance2.IsValid(typeof(FooMetaData2));
}
问题是什么:
- 第一次验证 [fooInstance.IsValid(typeof(FooMetaData2))] 是正确的(缺少 2 个必填字段),
- 第二次验证调用 [fooInstance.IsValid(typeof(FooMetaData1))] 结果错误(缺少 3 个必填字段,但代码仅通知我 2),似乎代码应用了 FooMetaData2 中描述的验证class 而不是 FooMetaData1
谁能给我解释一下为什么? 谢谢
我使用 fluentValidator 插件解决了