Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用PropertyDescriptor确定属性是否为复杂对象_C#_Wcf_Reflection_Data Annotations - Fatal编程技术网

C# 使用PropertyDescriptor确定属性是否为复杂对象

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(

我试图在WCF服务中进行一些验证,为此,我使用了通过

问题是它不能递归地进行验证,所以对于嵌套对象它不起作用。这么说吧

[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