ASP.NET MVC ContactsManager チュートリアルの依存性注入ループ問題を解決する良い/適切な方法はありますか? 質問する

ASP.NET MVC ContactsManager チュートリアルの依存性注入ループ問題を解決する良い/適切な方法はありますか? 質問する

私が何を言っているのかわからない場合は、チュートリアル依存性注入を自分で追加してみるか、私の問題の説明を参考にして運試しをしてみてください。

注記:この問題は、ASP.NET の元のチュートリアルの範囲外です。チュートリアルでは、使用されているパターンが依存性注入に適していることのみを示唆しています。

基本的に問題は、Controller、ModelStateWrapper、および ContactManagerService の間に依存関係ループがあることです。

  1. ContactController コンストラクターは IContactManagerService を受け取ります。
  2. ContactManagerServiceコンストラクタはIContactManagerRepositoryを受け取ります(重要じゃない)そしてIValidationDictionary(ModelStateWrapper が実装)
  3. ModelStateWrapperコンストラクタはModelStateDictionaryを受け取ります(コントローラー上の「ModelState」というプロパティです)

依存関係のサイクルは次のようになります: コントローラー > サービス > ModelStateWrapper > コントローラー

これに依存性注入を追加しようとすると、失敗します。そこで私の質問は、どうすればいいかということです。他の人もこの質問を投稿していますが、回答は少なく、異なっており、どれもちょっと「ハックっぽい」もののようです。

現在の解決策は、IService コンストラクターから IModelStateWrapper を削除し、代わりに次のように Initialize メソッドを追加することです。

public class ContactController : Controller
{
    private readonly IContactService _contactService;

    public ContactController(IContactService contactService)
    {
        _contactService = contactService;
        contactService.Initialize(new ModelStateWrapper(ModelState));
    }

    //Class implementation...
}

public class ContactService : IContactService
{
    private IValidationDictionary _validationDictionary;
    private readonly IContactRepository _contactRepository;

    public ContactService(IContactRepository contactRepository)
    {
        _contactRepository = contactRepository;
    }

    private void Initialize(IValidationDictionary validationDictionary)
    {
        if(validationDictionary == null)
            throw new ArgumentNullException("validationDictionary");

        _validationDictionary = validationDictionary;
    }

    //Class implementation...
}

public class ModelStateWrapper : IValidationDictionary
{
    private readonly ModelStateDictionary _modelState;

    public ModelStateWrapper(ModelStateDictionary modelState)
    {
        _modelState = modelState;
    }

    //Class implementation...
}

この構造を使用すると、Unity コンテナーを次のように構成できます。

public static void ConfigureUnityContainer()
{
    IUnityContainer container = new UnityContainer();

    // Registrations
    container.RegisterTypeInHttpRequestLifetime<IContactRepository, EntityContactRepository>();
    container.RegisterTypeInHttpRequestLifetime<IContactService, ContactService>();

    ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
}

残念ながら、これはサービスの「Initialize」メソッドを呼び出す必要があることを意味します手動でコントローラー コンストラクターによって。もっと良い方法はありますか? おそらく、Unity 構成に IValidationDictionary を何らかの方法で含めるのでしょうか? 別の DI コンテナーに切り替える必要がありますか? 何か見落としているのでしょうか?

ベストアンサー1

一般的に、循環依存関係は設計上の欠陥を示しています。コードの元の作成者ではないので、これは間違いないと言えると思います :)

Initialize メソッドは良い解決策ではないと思います。アドイン シナリオを扱っている場合を除いて (そうではありません)、メソッド インジェクションは適切な解決策ではありません。DI コンテナーが実行できないために手動で呼び出す必要があることに不満を感じているので、そのことはすでにほぼ理解しているはずです。

私が完全に間違っていなければ、ContactController は、Action メソッドが呼び出される前に IValidationDictionary インスタンスを必要としないのでしょうか?

これが本当であれば、最も簡単な解決策はおそらく IValidationDictionaryFactory インターフェイスを定義し、ContactController コンストラクターがこのインターフェイスのインスタンスを取得するようにすることです。

このインターフェースは次のように定義できます。

public interface IValidationDictionaryFactory
{
    IValidationDictionary Create(Controller controller);
}

IValidationDictionary インスタンスを必要とするコントローラー上の任意の Action メソッドは、Create メソッドを呼び出してインスタンスを取得できます。

デフォルトの実装は次のようになります。

public class DefaultValidationDictionaryFactory : IValidationDictionaryFactory
{
    public IValidationDictionary Create(Controller controller)
    {
        return controller.ModelState;
    }
}

おすすめ記事