モデルクラスは、依存性注入の一部であってはなりません。また、彼ら自身の検証に責任を持つべきではありません(ただし、検証属性(単なるメタデータ)でそれらを装飾することは問題ありません)。
代わりに、検証を行うための適切な抽象化を定義してください。たとえば、次の抽象化を定義します。
public interface IValidator<T>
{
ValidationResult Validate(T instance);
}
このようにして、特定のタイプのインターフェースの実装を0、1、または複数持つことがIValidator<T>
でき、これをすべてAutofacに非常に効果的に登録できます。
タイプに検証がない場合、コンテナにデフォルトの-empty-実装を戻すことができます。
// Implementation of the Null Object pattern
public class EmptyValidator<T> : IValidator<T>
{
public ValidationResult Validate(T instance)
{
return ValidationResult.ValidResult;
}
}
タイプに複数のバリデーターが定義されている場合、それらをコンポジットでラップできます。
// Implementation of the Composite pattern
public class CompositeValidator<T> : IValidator<T>
{
private readonly IEnumerable<Validator<T>> col;
public CompositeValidator(IEnumerable<Validator<T>> col)
{
this.col = col;
}
public ValidationResult Validate(T instance)
{
ValidationResult total = ValidationResult.ValidResult;
foreach (var validator in this.col)
{
var result = validator.Validate(instance);
total = ValidationResult.Append(total, result);
}
return total;
}
}
IValidator<T>
Web APIコントローラーに直接挿入する代わりに、IRepository<T>
インターフェースをラップするデコレーターを作成します。このようにして、リポジトリを変更することなく、検証動作を追加できます。このような実装は次のようになります。
public class ValidationRepositoryDecorator<T>
: IRepository<T>
{
private readonly IRepository<T> decorated;
private readonly IValidator<T> validator;
public ValidationRepositoryDecorator(
IRepository<T> decorated,
IValidator<T> validator)
{
this.decorated = decorated;
this.validator = validator;
}
public void Save(T instance)
{
var result = this.validator.Validate(instance);
if (!results.IsValid)
new ValidationException(result);
this.decorated.Save(instance);
}
}
Autofacを使用すると、デコレータを登録できます。