0

我正在尝试对未绑定到 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 -> XSchedGroup -> XJob -> XTagNames

当一个对象验证失败时,事情会完全按照预期工作,但如果我只是检查 ValidationResult 中的KeyMessage,我最终会得到类似:“JOBNAME | Field is required”。

这样做的问题是,考虑到我可能在一个调度组中有数百个作业,验证是无用的,因为我不知道哪个特定作业失败了。我搜索了所有我能找到的关于验证和 C# 的文档,但没有找到任何获取更多数据的方法。我创建了属性 IdentificationingProperty 以允许我标记该类的哪个属性标识该类的特定实例。我有一个以前的自定义验证解决方案,我根据这个 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

4

2 回答 2

1

我不会操纵密钥,而是搭载 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;
}
于 2013-08-02T20:05:48.750 回答
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;
            }
        }
于 2013-08-01T21:34:56.720 回答