私のビジネスレイヤーには、IValidatableObjectを実装するオブジェクトがあります。これらのエンティティのビジネスルールを外部アセンブリに入れてから、次のタイプのバリデーターを呼び出します。
public IEnumerable<ValidationResult> Validate(ValidationContext vc){}
DIを使用して、IValidatableObjectインターフェイスを実装するタイプのコンストラクターにバリデーターを挿入しました。
public Customer(ICustomerValidator validator)
{
this.Validator = validator;
}
タイプファクトリのUnityに呼び出して、そこから注入すると思いました。
しかし、多くの場合、エンティティは変更されずに読み取られます。つまり、顧客エンティティです。ユースケースをサポートするためだけに存在し、実際には変更されない可能性があるため、必ずしもバリデーターは必要ありません。
だから私は次のいずれかができると思います:
- CustomerEditクラスを作成してから、CustomerReadクラスではなく、それらのクラスにのみコンストラクタインジェクターを使用しますが、これにより、このアプリケーションには本当に必要のないクラスの爆発的な増加につながります。
- 単一の顧客クラスを用意し、必要に応じてバリデーターを挿入します。
上記の2の場合、IValidatableObjectインターフェイスの実装のValidateメソッドが適切な場所のようです。問題は、多くの場合、このメソッドが自分以外のコードによって呼び出されることです。たとえば、Entity Frameworkから、および一部のタイプでは、モデルクラスとして使用されるMVCから。
これで、DIできるように、フレームワークコードのメソッドをオーバーライドする必要があります。これは正しく「見えない」のですが、正直なところ、理由はわかりません。
次に見たのは、ValidationContextのGetService()メソッドです。
public IEnumerable<ValidationResult> Validate(ValidationContext vc)
{
var customerValidator = (ICustomerValidator)vc.GetService(typeof(ICustomerValidator));
return customerValidator.Validate();
}
しかし、これを始めたら、ServiceLocatorアンチパターンの領域全体に足を踏み入れて、デメテルの法則を破り、テストを完全に苦痛にしたのではないでしょうか。
それで、これからよりクリーンな方法がありますか、それとも私が概説したものから私のトレードオフを選択するだけの問題ですか?