Я работаю над проектом, в котором методы 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, которые должны быть проверены перед сохранением их в БД. Я написал валидатор объекта, который позволяет пользователю определять наборы правил валидации в файле 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
}
}
Фу ... Спасибо, что прочитали все это. Я уже реализовал это, и он прекрасно работает, и я планирую расширить его, чтобы проверить содержимое полей IEnumerable и других полей, которые Validatable
.
- Что меня особенно беспокоит, так это то, что если набор правил не указан, валидатор пытается использовать имя свойства в качестве имени набора правил. (Если вам не нужно такое поведение, вы можете использовать
[SuppressValidation]
.) Это делает код намного менее загроможденным (не нужно использовать [UseValidationRuleset("something")]
для каждого отдельного свойства), но это почему-то не кажется правильным. Я не могу решить, ужасно это или круто. Что ты думаешь?
- Любые предложения по другим частям этого дизайна тоже приветствуются. Я не очень опытный, и я благодарен за любую помощь.
- Кроме того, "Validatable" - это хорошее имя? Для меня это звучит довольно странно, но я не являюсь носителем английского языка.