企业库对象验证:获取有关验证失败的更多信息

时间:2013-08-01 21:27:49

标签: .net validation enterprise-library

我正在尝试对没有绑定到UI的对象执行某些验证。例如,我有这三个类:

public class XDeftable {
    [ObjectCollectionValidator(typeof(XSchedGroup))]
    public List<XSchedGroup> SCHED_GROUP { get; set; }
}

[IdentifyingProperty("TABLE_NAME")]
public class XSchedGroup {
    [ObjectCollectionValidator(typeof(XJob))]
    public List<XJob> JOB { get; set; }
    [Required]
    public string TABLE_NAME { get; set; }
}

[IdentifyingProperty("JOBNAME")]
public class XJob : ICalendar {
    [Required]
    public string JOBNAME { get; set; }
    [Range(-62, 62)]
    public string SHIFTNUM { get; set; }
    [ObjectCollectionValidator(typeof(XTagNames))]
    public List<XTagNames> TAG_NAMES { get; set; }
}

XDeftable - &gt; XSchedGroup - &gt; XJob - &gt; XTagNames

当一个对象验证失败时,事情就像人们期望的那样工作,但如果我只是检查ValidationResult的 Key Message ,我最终得到的结果如下:“JOBNAME |字段是必需的。”

问题在于,考虑到我可能在一个调度组中有数百个作业,验证是无用的,因为我不知道哪个特定的作业失败了。我搜索了有关验证和C#的所有文档,但没有找到任何获取更多数据的方法。我创建了属性IdentifyingProperty,以允许我标记类的哪个属性标识类的特定实例。我有一个以前的自定义验证解决方案,我根据这个Git Repo嘲笑:https://github.com/reustmd/DataAnnotationsValidatorRecursive/tree/master/DataAnnotationsValidator/DataAnnotationsValidator。它工作正常,但我想交换更强大的东西。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class IdentifyingProperty : Attribute {
    public string Name { get; set; }

    public IdentifyingProperty(string name) {
        this.Name = name;
    }
}

到目前为止,我已经能够提出以下建议:

public ValidationResults Validate(XDeftable deftable) {
    var results = new ObjectValidator(typeof(XDeftable)).Validate(deftable);
    var detailedResults = new ValidationResults();

    foreach (var item in results) {
        var targetType = item.Target.GetType();

        var identProp = targetType.GetCustomAttribute<IdentifyingProperty>();
        if (identProp != null) {
            var pi = targetType.GetProperty(identProp.Name);
            var newKey = String.Format("{0}[{1}].{2}", targetType.Name, pi.GetValue(item.Target).ToString(), item.Key);
            detailedResults.AddResult(new ValidationResult(item.Message, item.Target, newKey, item.Tag, item.Validator));
        }
        else {
            detailedResults.AddResult(item);
        }
    }

    return detailedResults;
}

这至少会让我“XJob [JOBNAME] .SHIFTNUM |字段SHIFTNUM必须在-62到62之间。”如果我有办法,我仍然会喜欢它获得跟随容器链的结果,例如: XSchedGroup [TABLE_NAME] .XJob [JOBNAME] .SHIFTNUM

2 个答案:

答案 0 :(得分:1)

我不会操纵Key,而是捎带Tag属性,因为这就是它的用途(“标记的含义由消耗ValidationResults的客户端代码决定”)。

坚持你的方法,如:

public ValidationResults Validate(XDeftable deftable)
{
    var results = new ObjectValidator(typeof(XDeftable)).Validate(deftable);
    var detailedResults = new ValidationResults();

    Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResult result = null;

    foreach (var item in results)
    {
        result = item;

        var targetType = item.Target.GetType();

        var attribute = (IdentifyingPropertyAttribute)
                            targetType.GetCustomAttributes(
                                typeof(IdentifyingPropertyAttribute), 
                                false)
                            .SingleOrDefault();

        if (attribute != null)
        {
            var propertyInfo = targetType.GetProperty(attribute.Name);

            if (propertyInfo != null)
            {
                object propertyValue = propertyInfo.GetValue(item.Target) ?? "";

                result = new Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResult(
                            item.Message, 
                            item.Target, 
                            item.Key, 
                            propertyValue.ToString(), 
                            item.Validator);
            }
        }

        detailedResults.AddResult(result);
    }

    return detailedResults;
}

答案 1 :(得分:0)

我曾经使用类似的东西

        public class RequiredPropertyAttribute : Attribute
        {
            public bool Required { get { return true; } }
        }
        public class RequiredListAttribute : Attribute
        {
            public bool Required { get { return true; } }
        }

以及以下用于验证。它检查我指定的属性,并返回未填充的那些属性。

            public List<string> IterateProperties(object _o)
            {
                List<string> problems = new List<string>();

                foreach (PropertyInfo info in _o.GetType().GetProperties())
                {
                    bool isGenericType = info.PropertyType.IsGenericType;
                    Type infoType = info.PropertyType;

                    if (infoType.IsGenericType && infoType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        infoType = infoType.GetGenericArguments()[0];

                        if (infoType.IsNested)
                        {
                            System.Collections.IList subObjects = (System.Collections.IList)info.GetValue(_o, null);

                            object[] requiredListAttributes = info.GetCustomAttributes(typeof(RequiredListAttribute), true);
                            if (requiredListAttributes.Length > 0 && subObjects.Count == 0)
                            {
                                problems.Add(String.Format("List {0} in class {1} must have at least 1 row", info.Name, info.PropertyType.ToString()));
                            }
                            else
                            {
                                foreach (object sub in subObjects)
                                {
                                    problems.AddRange(this.IterateProperties(sub));
                                }
                            }
                        }
                    }
                    else
                    {
                        if (infoType.IsNested)
                        {
                            object sub = info.GetValue(_o, null);
                            if (sub != null)
                            {
                                problems.AddRange(this.IterateProperties(sub));
                            }
                        }
                    }


                    object[] attributes = info.GetCustomAttributes(typeof(RequiredPropertyAttribute), true);
                    foreach (object o in attributes)
                    {
                        if (info.GetValue(_o, null) == null)
                        {
                            problems.Add(String.Format("Attribute {0} in class {1} cannot be null", info.Name, info.PropertyType.ToString()));
                        }
                    }
                }

                return problems;
            }
        }