web-dev-qa-db-ja.com

MVC3用のCastleWindsor Dependency Resolver

MVC3でのIoC/DIの実装は、RCでの最終的な形である可能性が高いため、Caste Windsorを使用したDependencyResolver、IControllerActivator、およびIViewPageActivatorの更新された実装を探しています。 MVC 3 RC用に更新された例はありますか?

EDIT#1 Windsor依存関係リゾルバーの実装は確かに簡単ですが、まだ何かが欠けています。 Jeff PutzのNinjectの例(下記)とは異なり、Windsorの場合ほど単純ではないようです。依存関係リゾルバをそのように設定した後、

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

WindsorはComponentNotFoundExceptionをスローします。 IControllerFactoryとIControllerActivatorの実装を提供する必要があります。 DefaultControllerFactoryはDependencyResolverに対応しているため、これは次のように解決できます。

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),

WindsorControllerActivatorも簡単です。ただし、これにより、IViewPageActivatorの別のComponentNotFoundExceptionが発生します。

これは私が何かを逃していると私に信じさせます。これがコントローラーファクトリを実装し、ControllerBuilder.Current.SetControllerFactory MVC2.0スタイルを呼び出すよりも複雑になる方法はありません。

EDIT#2サービスが見つからない場合に、依存関係リゾルバーがnullを返す必要があるという微妙ではあるが重要な詳細を見逃しました。実装は次のとおりです。

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

  public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

編集#

コメントの質問に答える。独自のIControllerActivatorが必要な場合は、Windsorの簡単な実装を次に示します。

public class WindsorControllerActivator : IControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorControllerActivator(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController Create(RequestContext requestContext, Type controllerType)
    {
        return (IController)container.GetService(controllerType);
    }
}

}

繰り返しますが、これは[〜#〜] not [〜#〜]基本的なDIをWindsorおよびMVC3依存関係リゾルバーで動作させるために必要です。

編集#4いくつかのさらなる調査とフィードバックに基づくと、従来のコントローラーファクトリーの実装がウィンザーとMVC3にとって最良のアプローチであるように思われます。懸念されるのは、IDependencyResolverインターフェイスにリリースメソッドがないため、Windsorがコンポーネントを破棄しないとメモリリークが発生する可能性があることです。すべての依存関係がPerWebRequestライフサイクルで解決されれば、これはおそらく問題にはなりませんが、チャンスを逃さない方がよいでしょう。これは、MVC3用のWindsorコントローラーファクトリの基本的な実装です。

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

    public override void ReleaseController(IController controller)
    {
        container.Kernel.ReleaseComponent(controller);
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerComponentName = controllerName + "Controller";
        return container.Kernel.Resolve<IController>(controllerComponentName);
    }
}

EDIT#5 MVCエリアを使用している場合、上記の実装は機能しません。フルネームに基づいて各コントローラーを登録し、CreateControllerの代わりにGetControllerInstanceをオーバーライドする必要があります。

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }
32
James H

ベータリリース以降、インターフェースは変更されていないため、さまざまなフレームワークのすべての実装が引き続き機能するはずです。そして真実は、それはインターフェースのそれほど複雑ではないということです...あなたはそれほど面倒なしであなた自身を転がすことができるはずです。たとえば、私はNinjectに対してこれを行いました。

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

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

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

次に、次のようにglobal.asaxに接続します。

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

その時点で、コントローラーのDI、コントローラーファクトリ、アクションフィルター、ビューの基本クラスなど、あらゆる種類のグッズを無料で入手できることを忘れないでください。

編集:明確にするために、私はあなたの「活性化因子」が何であるかわかりませんが、おそらくあなたはそれらを必要としないでしょう。 IDependencyResolverインターフェースは、コントローラーとビューの更新を自動的に処理します。

10
Jeff Putz

MVC3 IDependencyResolverインターフェイスには、リリースメソッドがないという大きな問題があります。これは、Windsorで使用する場合、メモリリークが発生する可能性があることを意味します。ここでそれについての私のブログ投稿を参照してください:

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

24
Mike Hadlow

MVCContrib は現在、IoC-MVC統合の信頼できるソースです。現在、MVC3ブランチには、コントローラーファクトリとIDependencyResolverの実装(およびその他のいくつか)のみが含まれています。リポジトリをフォークして、不足している拡張ポイントを実装することをお勧めします(それほど難しくないはずです)。次に、チームにプルリクエストを送信します。

2