对象验证器 - 这是一个好的设计吗?

时间:2010-12-25 10:58:19

标签: c# validation reflection attributes

我正在开发一个项目,我编写的API方法必须返回域对象的不同“视图”,如下所示:

namespace View.Product
{
    public class SearchResult : View
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
    }

    public class Profile : View
    {
        public string Name { get; set; }
        public decimal Price { get; set; }

        [UseValidationRuleset("FreeText")]
        public string Description { get; set; }

        [SuppressValidation]
        public string Comment { get; set; }
    }
}

这些也是API中setter方法的参数,必须在将它们存储在DB中之前进行验证。我编写了一个对象验证器,允许用户在XML文件中定义验证规则集,并检查对象是否符合这些规则:

[Validatable]
public class View
{
    [SuppressValidation]
    public ValidationError[] ValidationErrors
    {
        get { return Validator.Validate(this); }
    }
}

public static class Validator
{
    private static Dictionary<string, Ruleset> Rulesets;

    static Validator()
    {
        // read rulesets from xml
    }

    public static ValidationError[] Validate(object obj)
    {
        // check if obj is decorated with ValidatableAttribute
        // if not, return an empty array (successful validation)

        // iterate over the properties of obj
        // - if the property is decorated with SuppressValidationAttribute, 
        //   continue
        // - if it is decorated with UseValidationRulesetAttribute, 
        //   use the ruleset specified to call 
        //   Validate(object value, string rulesetName, string FieldName)
        // - otherwise, get the name of the property using reflection and
        //   use that as the ruleset name
    }

    private static List<ValidationError> Validate(object obj, string fieldName, string rulesetName)
    {
        // check if the ruleset exists, if not, throw exception
        // call the ruleset's Validate method and return the results
    }
}

public class Ruleset
{
    public Type Type { get; set; }
    public Rule[] Rules { get; set; }

    public List<ValidationError> Validate(object property, string propertyName)
    {
        // check if property is of type Type
        // if not, throw exception

        // iterate over the Rules and call their Validate methods
        // return a list of their return values
    }
}

public abstract class Rule
{
    public Type Type { get; protected set; }
    public abstract ValidationError Validate(object value, string propertyName);
}

public class StringRegexRule : Rule
{
    public string Regex { get; set; }

    public StringRegexRule()
    {
        Type = typeof(string);
    }

    public override ValidationError Validate(object value, string propertyName)
    {
        // see if Regex matches value and return
        // null or a ValidationError
    }
}

Phew ...感谢您阅读所有这些内容。我已经实现了它并且它运行良好,我计划扩展它以验证IEnumerable字段和Validatable的其他字段的内容。

  • 我特别关注的是,如果未指定规则集,验证程序会尝试使用该属性的名称作为规则集名称。 (如果您不想要这种行为,可以使用[SuppressValidation]。)这会使代码更加混乱(不需要在每个属性上使用[UseValidationRuleset("something")])但它在某种程度上感觉不对。我无法确定它是否可怕或令人敬畏。你觉得怎么样?
  • 对此设计其他部分的任何建议也是受欢迎的。我不是很有经验,我很感激你的帮助。
  • 另外,“Validatable”是个好名字吗?对我来说,这听起来很奇怪,但我不是母语为英语的人。

1 个答案:

答案 0 :(得分:1)

我的建议使用界面代替属性:

public interface IValidatable
{
    ValidationError[] Validate(Rulesets ruleSets);
}

public class View : IValidatable
{
    public ValidationError[] Validate(Rulesets ruleSets)
    {
       // do validate
    }
}

public static class Validator
{
    private static Rulesets _rulesets;

    static Validator()
    {
        // read rulesets
    }

    public static ValidationError[] Validate(object obj)
    {
        IValidatable validObj = obj as IValidatable;
        if (obj == null)
            // not validatable
            return new ValidationError[0];

        return validObj.Validate(_rulesets);
    }
}