web-dev-qa-db-ja.com

Ninjectカーネルへのグローバルなアクセス

この質問は、特にNinjectとは関係ありません。これは一般的なコーディングの質問ですが、私がやろうとしていることよりも、Ninjectで問題を完全に処理するためのより良い方法があるかもしれない場合に備えて、ここに投稿します。

Global.asaxのインスタンスから、Ninject StandardKernelにグローバルにアクセスできるかどうか知りたいのですが。

コードは次のとおりです。

public class MvcApplication : NinjectHttpApplication
{
    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();

        // MVC global registration, routing and filtering code goes here...
    }

    protected override IKernel CreateKernel()
    {
        return Container;
    }

    private static IKernel Container
    {
        get
        {
            IKernel kernel = new StandardKernel();
            kernel.Load(new ServiceModule(), new RepositoryModule());
            return kernel;
        }
    }
}

たとえば、コントローラーとインターフェイスしないファサードクラスなど、依存関係チェーンを開始したいクラスがある場合、次のように使用する必要があると理解しています。

_className = kernel.Get<IClassName>();

ただし、これを行うために私が知っている唯一の方法は、Ninject Standardカーネルの新しいインスタンスを作成することですが、正しく理解している場合は、Ninjectカーネルの新しいインスタンスを作成することはお勧めできません。 2番目のカーネル。

それで、アプリケーションの開始時にGlobal.asaxでインスタンス化された既存のカーネルに、アプリケーションのどこからでもアクセスできますか、それとも完全にこれを行うためのより良い方法がありますか?

よろしく、

フレッドシャトー

17
Fred Chateau

最も簡単な方法(IMO):

_className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));
26
Vasilij

Ninjectの新しいバージョンには、System.Web.MVCで使用する場合、次のメソッドがあります。

var obj = DependencyResolver.Current.GetService<IClassName>();

その場でDIバインディングを操作する必要がない限り、StandardKernelのインスタンス化は少し重いです。

IKernel kernel = new StandardKernel();
var obj = DependencyResolver.Current.GetService<IClassName>();
8
detale

Service Locatorを機能させることができましたが、非常にうまく機能しているようです。リクエストがMVCコントローラーアクションメソッドを介してアプリケーションに入ると、NinjectはNinject.Mvc.Extensionsによって提供される通常の方法で機能します。コントローラコンストラクタを介してインスタンスクラスを挿入します。リクエストが他の方法でアプリケーションに入ると、Service Locatorを呼び出して、そのクラスコンストラクターにインスタンスクラスを提供します。

コードは次のとおりです。

まず、Microsoft.Practices.ServiceLocationへの参照

そして、次のNinjectアダプタクラス。

public class NinjectServiceLocator : ServiceLocatorImplBase
{
    public IKernel Kernel { get; private set; }

    public NinjectServiceLocator(IKernel kernel)
    {
        Kernel = kernel;
    }

    protected override object DoGetInstance(Type serviceType, string key)
    {
        return Kernel.Get(serviceType, key);
    }

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
    {
        return Kernel.GetAll(serviceType);
    }
}

そしてGlobal.asaxで

public class MvcApplication : NinjectHttpApplication
{
    private static IKernel _kernel;


    protected override IKernel CreateKernel()
    {
        return Container;
    }

    private static IKernel Container
    {
        get
        {
            if (_kernel == null)
            {
                _kernel = new StandardKernel();
                _kernel.Load(new ServiceModule(), new RepositoryModule());

                ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel));
            }

            return _kernel;
        }
    }
}

このコードでは、Ninject.Mvc.Extensionsを使用する必要があることに注意してください。これにより、依存関係リゾルバーがデフォルトのコントローラーにフォールバックされます。それ以外の場合は、カスタム依存関係リゾルバーが必要になる場合があります。

これで私の懸念はすべて解決したようです。インスタンスクラスを作成し、オブジェクトグラフ全体を解決し、必要な場所から機能します。そして、私が知る限り、アプリケーションごとに1つのNinject標準カーネルしかありません。

Service Locatorパターンの使用が嫌われることは知っていますが、複数のNinjectカーネルを使用することはさらに悪いことに嫌われると思います。

フレッドシャトー

1
Fred Chateau

Ninjectのファクトリパターンの実装がもっと必要なようです。カーネルをGlobal.asaxからFactoryクラスに移行して、アプリケーションの残りの部分と対話することができます。

あるいは、実行時に指定されたパラメーターがインターフェースバインディングを決定することである状況がある場合は、サービスをラップすることができます。これはDIとServiceLocaterのハイブリッドセットアップですが、ServiceLocaterはサービスレベルのインスタンス化でのみ発生し、他のすべてのレイヤーは通常DI/IOCパターンでコーディングされます。

MyService : IService1
{
    public void DoSomething(MyCustomParameter parameter)
    {
        //Builds the Kernel using the supplied parameter
        //We've in our resolver bound IService1 To MyActualService
        var trueService = kernel.Get<IService1>();
        return trueService.DoSomething(parameter);
    }
}

MyActualService : IService1
{
    public void DoSomething()
    {
        //Do the Actual work
    }
}
0
Kaiser12