0

[注:私のNinjectDependencyResolverクラスはこの質問の一番下にあります。]

設定:

ASP.NET MVC 4アプリには、サービスを利用するコントローラーがあります。

各サービスには、コンストラクターパラメーターとしてIUnitOfWorkインターフェイスがあります。例えば:

public ClientService(IUnitOfWork uow){ //... }

適切に記述されたNinjectDependencyResolver : IDependencyResolverクラスをGlobal.asax.csクラスに登録すると、これらのサービスが適切にインスタンス化され、すべてが機能するようになります。ここまでは順調ですね。

ただし、属性など、他のコードでサービスをインスタンス化する必要がある場合があります。例えば:

namespace MyApp.Domain.Attributes
{
    public class AuthorizeUnprocessedOnlyAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool isUnprocessed = false;

            string usuario = string.Empty;
            if (httpContext.User.Identity.IsAuthenticated)
            {
                // THIS IS THE LINE WHERE DI IS NEEDED!!
                ClientService service = new ClientService();
                usuario = httpContext.User.Identity.Name;
                isUnprocessed = service.IsUnprocessed(usuario);
            }

            return isUnprocessed;
        }
    }
}

私の問題は次の行です。

ClientService service = new ClientService();

次のように、ClientServiceにパラメーターなしのコンストラクターを指定する必要がありました。

public ClientService() : this (new UnitOfWork()) {}

これは完全に反DIのようです。

これを行う理由は、属性コードに依存関係を挿入する方法がわからないためです。コントローラーはControllerFactoryによってインスタンス化されるので、私はそれについて知らずに通り抜けました。

つまり、NinjectまたはIDependencyResolverについて十分に知りません...

質問1:

では、どうすれば自分より上に上がることができ'Ignorance Pattern'ますか?

ClientServiceオブジェクトを次の行に沿って取得する必要があります。

NinjectDependencyResolver ndr = new NinjectDependencyResolver();
IUnitOfWorkMR uow = ndr.Kernel.Get<IUnitOfWorkMR>();
IClientService service = new ClientService(uow);

この最初の質問に対する答えが「はい」であっても、私はあまり幸せではありません。

ClientServiceのインスタンスをインスタンス化する必要があるため、IClientServiceインターフェイスをNinjectDependencyResolverクラスで適切に構築されたClientServiceインスタンスにバインドする必要があります。

これはどうしたらいいかわからないので、これが私の2番目の質問です。

質問2:

ClientServiceを適切にインスタンス化するために、IUnitOfWork構築パラメーターの依存性注入をデイジーチェーン接続するにはどうすればよいですか?(以下のコメントアウトされた取り組みを参照してください-私には意味がないのでコメントアウトしました-UnitOfWorkの新しいインスタンスを作成するべきではありませんか?):

NinjectDependencyResolverクラス:

namespace MyApp.Domain.Infrastructure
{
    public class NinjectDependencyResolver : IDependencyResolver
    {
        private IKernel kernel;

        public NinjectDependencyResolver()
        {
            kernel = new StandardKernel();
            AddBindings();
        }

        public object GetService(Type serviceType)
        {
            return kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernel.GetAll(serviceType);
        } 

        public IBindingToSyntax<T> Bind<T>()
        {
            return kernel.Bind<T>();
        }

        public IKernel Kernel
        {
            get { return kernel; }
        }

        private void AddBindings()
        {
            kernel.Bind<IUnitOfWorkMR>().To<UnitOfWorkMR>().InRequestScope();
            // kernel.Bind<IClientService>().To<ClientService>().WithConstructorArgument("uow", new UnitOfWork());
        }
    }
}

ノート:

WithConstructorArgumentのエラーを修正しました(パラメーター名がありませんでした)。

編集:

テストでは、信じられないほどのことが起こりました。問題のコードは機能します。質問2に関しては、NinjectDepenedencyResolverクラスの次の変更により、動作中のアプリが突然解き放たれました(このようなことは確かにまれな喜びです)。

kernel.Bind<IUnitOfWorkMR>().To<UnitOfWorkMR>().InRequestScope();
            kernel.Bind<IClientService>().To<ClientService>().InRequestScope();

つまり、WithConstructorArgument呼び出しを削除しました。おそらく、NinjectにはUnitOfWorkの動作インスタンスがあり、それを使用してサービスをインスタンス化します。したがって、パラメータのないコンストラクタはもうありません...

しかし、これはRWTDI(それを行う正しい方法)ですか?

4

1 に答える 1

2

はい、それがバインディングを構成する正しい方法です。これがDIコンテナーの要点であり、コンストラクターのパラメーターと構成済みのものに基づいて何を注入するかを判断します。

ただし、NinjectDependcyResolverは奇妙だと思います。Ninject.MVC3を使用しないのはなぜですか?(MVC4でも機能します)。これにより、MVCのDependencyResolverが自動的にセットアップされ、App_Start\NinjectWebCommon.csでマッピングを構成します。

属性の場合、正しい方法は、Ninject.MVC3で自動的にインストールされるBindFilter拡張機能を使用することです。次のように構成します。

kernel.BindFilter<MyAuthorization>(FilterScope.Action, 0)
    .WhenActionMethodHas<MyAuthorization>();

次に、Ninjectは、それに注入された構成済みオブジェクトを自動的に処理します。

これにより、属性内からGetServiceを呼び出す必要がなくなり(常にコードの臭いです)、すべてが連携して機能します。

最低限、Ninject.MVC3を使用してMVCアプリをセットアップし、フィルターでGetServiceを本当に呼び出したい場合は、MVC DependencyResolver(Ninject.MVCが自動的に登録する)を使用して、次のようにします。

var x = DependencyResolver.Current.GetService<MyType>(); 

ただし、ここでも、代わりにBindFilter構文を実際に使用する必要があります。

于 2012-10-16T20:13:40.730 に答える