私は先週かそこらの間だけ試している実験を提案するでしょう。
このインスピレーションに基づいて、アプローチとは少し異なる方法で検証するDTOを作成していDataAnnotations
ます。サンプルDTO:
public class Contact : DomainBase, IModelObject
{
public int ID { get; set; }
public string Name { get; set; }
public LazyList<ContactDetail> Details { get; set; }
public DateTime Updated { get; set; }
protected override void ConfigureRules()
{
base.AddRule(new ValidationRule()
{
Properties = new string[] { "name" },
Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
validator = () => this.Name.IsRequired300LenNoSpecial()
});
base.AddRule(new ValidationRule()
{
Properties = new string[] { "updated" },
Description = "required",
validator = () => this.Updated.IsRequired()
});
}
}
これはもっとDataAnnotations
うまくいくように見えるかもしれません、それはそれですが、それは巨大ではありません。私はそれがクラスでより見栄えがよいと思います(私は今DataAnnotations
属性を持ついくつかの本当に醜いDTOクラスを持っています-あなたはもうプロパティを見ることさえできません)。そして、このアプリケーションでの匿名のデリゲートの力は、ほとんど本に値するものです(私は発見しています)。
基本クラス:
public partial class DomainBase : IDataErrorInfo
{
private IList<ValidationRule> _rules = new List<ValidationRule>();
public DomainBase()
{
// populate the _rules collection
this.ConfigureRules();
}
protected virtual void ConfigureRules()
{
// no rules if not overridden
}
protected void AddRule(ValidationRule rule)
{
this._rules.Add(rule);
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; } // Validation should call the indexer so return "" here
} // ..we dont need to support this property.
public string this[string columnName]
{
get
{
// get all the rules that apply to the property being validated
var rulesThatApply = this._rules
.Where(r => r.Properties.Contains(columnName));
// get a list of error messages from the rules
StringBuilder errorMessages = new StringBuilder();
foreach (ValidationRule rule in rulesThatApply)
if (!rule.validator.Invoke()) // if validator returns false then the rule is broken
if (errorMessages.ToString() == String.Empty)
errorMessages.Append(rule.Description);
else
errorMessages.AppendFormat("\r\n{0}", rule.Description);
return errorMessages.ToString();
}
}
#endregion
}
ValidationRule
と私の検証機能:
public class ValidationRule
{
public string[] Properties { get; set; }
public string Description { get; set; }
public Func<bool> validator { get; set; }
}
/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
#region IsRequired
public static bool IsRequired(this String str)
{
return !str.IsNullOrTrimEmpty();
}
public static bool IsRequired(this int num)
{
return num != 0;
}
public static bool IsRequired(this long num)
{
return num != 0;
}
public static bool IsRequired(this double num)
{
return num != 0;
}
public static bool IsRequired(this Decimal num)
{
return num != 0;
}
public static bool IsRequired(this DateTime date)
{
return date != DateTime.MinValue;
}
#endregion
#region String Lengths
public static bool IsLengthLessThanOrEqual(this String str, int length)
{
return str.Length <= length;
}
public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
{
return !str.IsNullOrTrimEmpty() && (str.Length <= length);
}
public static bool IsRequired300LenNoSpecial(this String str)
{
return !str.IsNullOrTrimEmpty() &&
str.RegexMatch(@"^[- \r\n\\\.!:*,@$%&""?\(\)\w']{1,300}$",
RegexOptions.Multiline) == str;
}
#endregion
}
私のコードが乱雑に見える場合、それは私がこの数日間この検証アプローチに取り組んでいるだけだからです。いくつかの要件を満たすには、このアイデアが必要です。
IDataErrorInfo
MVCレイヤーが自動的に検証されるように、インターフェイスをサポートする必要があります
- 複雑な検証シナリオ(私が推測する質問の要点全体)をサポートできる必要があります。同じオブジェクト(つまり、StartDateとFinishDate)の複数のプロパティに対して検証できるようにしたいです。オブジェクトグラフにあるような、異なる/複数の/関連付けられたオブジェクトのプロパティ。そして、私がまだ考えていない他のことさえ。
- 複数のプロパティに適用されるエラーのアイデアをサポートする必要があります
- TDDとDDDの旅の一環として、ドメインオブジェクトにサービスレイヤーメソッドよりも多くの「ドメイン」を記述させたいので、これらの複雑な条件をモデルオブジェクト(DTOではない)に配置すると、これが達成されるようです。
このアプローチは私が欲しいものを私に与えると思います、そして多分あなたもそうです。
あなたがこれについて私と一緒に飛び乗ったら、私たちは「自分たちで」かなりなるだろうと想像しますが、それは価値があるかもしれません。MVC 2の新しい検証機能について読んでいましたが、カスタム変更を行わないと、上記のウィッシュリストを満たしていません。
お役に立てれば。