C# 使用PropertyDescriptor确定属性是否为复杂对象
我试图在WCF服务中进行一些验证,为此,我使用了通过 问题是它不能递归地进行验证,所以对于嵌套对象它不起作用。这么说吧C# 使用PropertyDescriptor确定属性是否为复杂对象,c#,wcf,reflection,data-annotations,C#,Wcf,Reflection,Data Annotations,我试图在WCF服务中进行一些验证,为此,我使用了通过 问题是它不能递归地进行验证,所以对于嵌套对象它不起作用。这么说吧 [DataContract] public class Model { [DataMember] [Required(ErrorMessage = "RequiredOne is required")] public string RequiredOne { get; set; } [DataMember] [StringLength(
[DataContract]
public class Model
{
[DataMember]
[Required(ErrorMessage = "RequiredOne is required")]
public string RequiredOne { get; set; }
[DataMember]
[StringLength(10, ErrorMessage = "Not Required should be at most 10 characters long")]
public string NotRequired { get; set; }
[DataMember]
[Required(ErrorMessage = "ChildModel is required")]
public ChildModel ChildModel { get; set; }
}
[DataContract]
public class ChildModel
{
[DataMember]
[Required(ErrorMessage = "RequiredValue is required")]
public string RequiredValue { get; set; }
[DataMember]
public string NotRequiredValue { get; set; }
}
它将无法获得所需的childModel RequiredValue
因此,我正在研究该dll的源代码,并试图使其正常工作。实际代码是
public class DataAnnotationsObjectValidator : IObjectValidator
{
public IEnumerable<ValidationResult> Validate(object input)
{
if (input == null) return Enumerable.Empty<ValidationResult>();
return from property in TypeDescriptor.GetProperties(input).Cast<PropertyDescriptor>()
from attribute in property.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(property.GetValue(input))
select new ValidationResult
(
attribute.FormatErrorMessage(string.Empty),
new[] { property.Name }
);
}
}
公共类DataAnnotationsObjectValidator:IOObjectValidator
{
公共IEnumerable验证(对象输入)
{
if(input==null)返回Enumerable.Empty();
从TypeDescriptor.GetProperties(input.Cast()中的属性返回
来自property.Attributes.OfType()中的属性
其中!attribute.IsValid(property.GetValue(输入))
选择新的ValidationResult
(
attribute.FormatErrorMessage(string.Empty),
新[]{property.Name}
);
}
}
所以我的想法是把它变成这样
public IEnumerable<ValidationResult> Validate(object input)
{
if (input == null) return Enumerable.Empty<ValidationResult>();
var validationResults = new List<ValidationResult>();
foreach (var prop in TypeDescriptor.GetProperties(input).Cast<PropertyDescriptor>())
{
foreach (var att in prop.Attributes.OfType<ValidationAttribute>())
{
//This doesn't work, it's one of the several
//attempts I've made
if (prop.ComponentType.IsClass)
Validate(prop.ComponentType);
if (!att.IsValid(prop.GetValue(input)))
{
validationResults.Add(new ValidationResult(
att.FormatErrorMessage(string.Empty),
new[] { prop.Name }
));
}
}
}
return validationResults;
}
public IEnumerable验证(对象输入)
{
if(input==null)返回Enumerable.Empty();
var validationResults=新列表();
foreach(TypeDescriptor.GetProperties(input.Cast()中的var prop)
{
foreach(prop.Attributes.OfType()中的var att)
{
//这不管用,这是其中之一
//我已经尝试过了
if(prop.ComponentType.IsClass)
验证(道具组件类型);
如果(!att.IsValid(prop.GetValue(输入)))
{
添加(新的ValidationResult(
att.FormatErrorMessage(string.Empty),
新[]{prop.Name}
));
}
}
}
返回验证结果;
}
其目的是检查是否有任何属性是复杂的,以及是否是递归验证自身的情况,但我不确定如何检查给定的“道具”是否被转换为类型描述符
谢谢在我看来,下面的代码应该可以做到这一点:
public IEnumerable<ValidationResult> Validate(object input)
{
return ValidateWithState(input, new HashSet<object>());
}
private IEnumerable<ValidationResult> ValidateWithState(object input, HashSet<object> traversedInputs)
{
if (input == null || traversedInputs.Contains(input))
{
return Enumerable.Empty<ValidationResult>();
}
var validationResults = new List<ValidationResult>();
foreach (var prop in TypeDescriptor.GetProperties(input).Cast<PropertyDescriptor>())
{
foreach (var att in prop.Attributes.OfType<ValidationAttribute>())
{
if (!att.IsValid(prop.GetValue(input)))
{
validationResults.Add(new ValidationResult(
att.FormatErrorMessage(string.Empty),
new[] { prop.Name }
));
}
traversedInputs.Add(input);
if (prop.PropertyType.IsClass || prop.PropertyType.IsInterface))
{
validationResults.AddRange(ValidateWithState(prop.GetValue(input), traversedInputs));
}
}
return validationResults;
}
public IEnumerable验证(对象输入)
{
返回ValidateWithState(输入,newHashSet());
}
私有IEnumerable ValidateWithState(对象输入、HashSet traversedInputs)
{
if(输入==null | | traversedInputs.Contains(输入))
{
返回可枚举的.Empty();
}
var validationResults=新列表();
foreach(TypeDescriptor.GetProperties(input.Cast()中的var prop)
{
foreach(prop.Attributes.OfType()中的var att)
{
如果(!att.IsValid(prop.GetValue(输入)))
{
添加(新的ValidationResult(
att.FormatErrorMessage(string.Empty),
新[]{prop.Name}
));
}
添加(输入);
if(prop.PropertyType.IsClass | | prop.PropertyType.IsInterface))
{
AddRange(ValidateWithState(prop.GetValue(input),transversedInputs));
}
}
返回验证结果;
}
可能不是最优雅的解决方案,但我认为它会起作用。现在我能够验证public-List-ChildModel。 参考DevTrends.WCFDataAnnotations,ValidatingParameterInspector.cs类, () 我确信ValidateCollection可以进一步修改以检查ChildModel中的集合。目前它只检查一个级别 以我为例,
[DataContract]
public class Model
{
[DataMember]
[Required(ErrorMessage = "RequiredOne is required")]
public string RequiredOne { get; set; }
[DataMember]
[StringLength(10, ErrorMessage = "Not Required should be at most 10 characters long")]
public string NotRequired { get; set; }
[DataMember]
[Required(ErrorMessage = "ChildModel is required")]
public List<ChildModel> ChildModel { get; set; }
}
[DataContract]
公共类模型
{
[数据成员]
[必需(ErrorMessage=“需要RequiredOne”)]
公共字符串RequiredOne{get;set;}
[数据成员]
[StringLength(10,ErrorMessage=“非必需的长度应最多为10个字符”)]
不需要公共字符串{get;set;}
[数据成员]
[必需(ErrorMessage=“需要儿童模型”)]
公共列表子模型{get;set;}
}
原始代码不验证列表,所以我又创建了一个函数ValidateCollection
操纵对象[]输入以提取每个ChildModel类,并将其放回对象[]输入中,就像模型类驻留在对象[]输入中一样
public object BeforeCall(string operationName, object[] inputs)
{
var validationResults = new List<ValidationResult>(); ErrorMessageGenerator.isValidationFail = false;
ErrorMessageGenerator.ErrorMessage = string.Empty;
***inputs=ValidateCollection( operationName, inputs);***
foreach (var input in inputs)
{
foreach (var validator in _validators)
{
var results = validator.Validate(input);
validationResults.AddRange(results);
}
}
if (validationResults.Count > 0)
{
return _errorMessageGenerator.GenerateErrorMessage(operationName, validationResults);
}
return null;
}
private object[] ValidateCollection(string operationName, object[] inputs)
{
object[] inputs1 = inputs;
try
{
foreach (var input in inputs)
{
foreach (var property in input.GetType().GetProperties())
{
IEnumerable enumerable = null;
if (property.PropertyType.Name.Contains("List"))
{
enumerable = property.GetValue(input, null) as IEnumerable;
int j = 0;
object[] o1 = new object[inputs.Count() + enumerable.OfType<object>().Count()];
for (int k = 0; k < inputs.Count(); k++)
{
o1[k] = inputs[k];
}
foreach (var item in enumerable)
{
o1[inputs.Count() + j] = item;
j = j + 1;
if (j == (o1.Length - inputs.Count()))
inputs = o1;
}
}
}
}
return inputs;
}
catch
{
return inputs1;
}
}
调用前公共对象(字符串操作名,对象[]输入)
{
var validationResults=new List();ErrorMessageGenerator.isValidationFail=false;
ErrorMessageGenerator.ErrorMessage=string.Empty;
***输入=ValidateCollection(操作名称,输入)***
foreach(输入中的var输入)
{
foreach(var验证器在_验证器中)
{
var结果=validator.Validate(输入);
validationResults.AddRange(结果);
}
}
如果(validationResults.Count>0)
{
返回_errorMessageGenerator.GenerateErrorMessage(operationName,validationResults);
}
返回null;
}
私有对象[]ValidateCollection(字符串操作名,对象[]输入)
{
对象[]输入1=输入;
尝试
{
foreach(输入中的var输入)
{
foreach(input.GetType().GetProperties()中的var属性)
{
IEnumerable enumerable=null;
if(property.PropertyType.Name.Contains(“列表”))
{
enumerable=property.GetValue(输入,null)作为IEnumerable;
int j=0;
object[]o1=新对象[inputs.Count()+enumerable.OfType().Count()];
对于(int k=0;k