0

UI に関連付けられていないオブジェクトに対して検証を実行しようとしています。たとえば、次の 3 つのクラスがあります。

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 | フィールドが必要です」のような結果になります。

これの問題は、1 つのスケジューリング グループに何百ものジョブがある可能性があることを考えると、どの特定のジョブが失敗したかがわからないため、検証が役に立たないことです。検証と 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 | The field SHIFTNUM must be between -62 and 62.」が返されます。XSchedGroup[TABLE_NAME].XJob[JOBNAME].SHIFTNUMのようなコンテナーのチェーンをたどる結果を取得する方法があれば、私はまだそれを望んでいます。

4

2 に答える 2

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;
}
于 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 に答える