11

Service Locatorパターンを使用せずにNinject.Kernelにアクセスする方法の明確なガイドラインを見つけることなく、このトピックに関する数十の投稿を読みました。

私は現在、使用する必要のあるクラスCustomerBusiness(これは私のサービスです)に次のものがあり、正常に動作しますが、それが推奨される方法ではないことをよく知っています。

private CustomerBusiness _customerBusiness;

private ICustomerRepository CustomerRepository
{
    get { return NinjectWebCommon.Kernel.Get<IAccountRepository>(); }
}

private CustomerBusiness CustomerBusiness
{
    get
    {
        if (_customerBusiness == null)
        {
            _customerBusiness = new CustomerBusiness(AccountRepository);
        }

        return _customerBusiness;
    }
}

public Customer GetCustomer(int id)
{
    return CustomerBusiness.GetCustomer(id);
}

これは、上記のコードでアクセスされるKernelプロパティです。

public static IKernel Kernel
{
    get
    {
        return CreateKernel();
    }
}

このためのファクトリの使用に関する多くの提案を読みましたが、このファクトリの使用方法を説明しているものはありません。誰かが「CustomerFactory」またはそれを使用する方法を含む他の推奨されるアプローチを私に見せてくれたら本当にありがたいです。

アップデート

ASP.NET Webフォームを使用しておりCustomerBusiness、CodeBehindからアクセスする必要があります。

解決

私が機能していることがわかった最終的な解決策は、この投稿で最も多くの票を獲得した答えでした 。asp.netWebフォームにNinjectまたはDIを実装するにはどうすればよいですか。

これは次のようになります(Ninject.Webの一部であるPageBaseからの継承に注意してください-それが鍵です!):

public partial class Edit : PageBase
{
    [Inject]
    public ICustomerBusiness CustomerBusiness { get; set; }
    ...

以下の受け入れられた答えは、間接的にこの解決策を見つけるように私を導きます。

4

2 に答える 2

12

を使用しているのでNinjectWebCommon、ある種のWebアプリケーションがあると思います。実際には、コンポジションルートの1か所でのみNinjectカーネルにアクセスする必要があります。これは、オブジェクトグラフを作成する場所であり、IoCコンテナへのアクセスが必要になる唯一の場所です。必要な依存関係を実際に取得するには、通常、コンストラクターインジェクションを使用します。

たとえば、MVC Webアプリケーションの場合、Ninjectカーネルを使用するコントローラーファクトリがあり、それを参照する唯一の場所です。

特定の状況を拡張するために、クラスはコンストラクターで受け入れ、依存関係としてICustomerBusinessのインスタンスが必要であることを宣言します。ICustomerBusiness

class CustomerBusinessConsumer : ICustomerBusinessConsumer
{
    private readonly ICustomerBusiness customerBusiness;

    public CustomerBusinessConsumer(ICustomerBusiness customerBusiness)
    {
        this.customerBusiness = customerBusiness;
    }
    ...
}

これで、依存関係として使用するクラスはどれでも、同じパターンに従います(のインスタンスをコンストラクターパラメーターとしてICustomerBusinessConsumer受け入れます)。ICustomerBusinessConsumer基本的に、 (特定の例外は別として)を使用して手動で依存関係を構築することはありません。new

次に、クラスが依存関係を取得していることを確認する必要があります。これを行うのは、この構成ルートです。コンポジションルートとは正確には、作成しているアプリケーションの種類(コンソールアプリケーション、WPFアプリケーション、Webサービス、MVC Webアプリケーションなど)によって異なります。


編集:ASP.NET WebFormsレルムの状況に慣れるために、使用したことがないため、詳細を調べる必要がありました。残念ながら、WebFormsでは、各Pageクラスにパラメーターなしのコンストラクターが必要であるため、オブジェクトグラフの上部から下部までコンストラクターインジェクションを使用することはできません。

ただし、 WebFormsでのオブジェクトの作成に関するMark Seemanの章を参照した後、優れたDIプラクティスに沿って行動しながら、このフレームワークの非効率性に対処する方法を言い換えることができます。

  1. 設定したNinjectのカーネルを使用して、依存関係の解決を担当するクラスを用意します。これは、カーネルの非常に薄いラッパーである可能性があります。それを呼びましょうDependencyContainer

  2. コンテナを作成してアプリケーションコンテキストに保存し、必要なときにすぐに使用できるようにします

    protected void Application_Start(object sender, EventArgs e)
    {
       this.Application["container"] = new DependencyContainer();
    }
    
  3. あなたのページクラス(それを呼びましょうHomePage)がに依存しているとしましょうICustomerBusinessConsumer。次に、次DependencyContainerのインスタンスを取得できるようにする必要がありますICustomerBusinessConsumer

    public ICustomerBusinessConsumer ResolveCustomerBusinessConsumer()
    {
        return Kernel.Get<ICustomerBusinessConsumer>();
    }
    
  4. クラス自体よりもMainPage、デフォルトのコンストラクターで依存関係を解決します。

    public MainPage()
    {
        var container = (DependencyContainer) HttpContext.Current.Application["container"];
        this.customerBusinessConsumer = container.ResolveCustomerBusinessConsumer();
    }
    

いくつかのメモ:

  • 依存関係コンテナをで利用できるようにHttpContextすることは、それをサービスロケーターと見なしたくなるものであってはなりません。実際、ここでのベストプラクティス(少なくともDIに忠実であるという観点から)は、ページクラスの機能を中継するある種の「実装者」クラスを用意することです。

    たとえば、によって処理さMainPageれる各アクションは、その実装者クラスにのみ中継されます。この実装者クラスはの依存関係にMainPageなり、他のすべての依存関係と同様に、コンテナを使用して解決されます。

    重要な部分は、これらの実装者クラスは、ASP.NETアセンブリを参照していないアセンブリに含まれている必要があるため、HttpContext

  • これを達成するために多くのコードを書かなければならないことは確かに理想的ではありませんが、それはフレームワークの制限の結果にすぎません。たとえば、ASP.NET MVCアプリケーションでは、これははるかに優れた方法で処理されます。ここには、オブジェクトグラフを作成できる単一のポイントがあり、WebFormsで行う必要があるように、各トップレベルクラスでそれらを解決する必要はありません。

  • 良い点は、ページクラスコンストラクターで配管コードを記述しなければならない一方で、そこからオブジェクトグラフの下にコンストラクターインジェクションを使用できることです。

于 2012-08-12T10:24:14.670 に答える
1

コンストラクターインジェクションは、ninjectを使用したDIの推奨される方法ですが、プロパティインジェクションもサポートしています。ここhttps://github.com/ninject/ninject/wiki/Injection-Patternsで注入パターンに関するninjectページを読んでください。

これらは両方とも、リクエストベースのサービスロケーションとは異なり、実際にはインジェクションではなく、インジェクションパターンです。

インジェクションの裏側は、構造を制御する必要があるということです。MVCを使用する場合、これを行うためのすべての配線は、nugetのMVCninjectパッケージに組み込まれています。

于 2012-08-12T10:24:28.950 に答える