2010-12-13 8 views
0

私は新しいAsp net mvc 3 RC2で遊んでいました。次のように私は、WindsorViewPageActivatorの作成

public class WindsorViewPageActivator : IViewPageActivator 
    { 
     object IViewPageActivator.Create(ControllerContext controllerContext, Type type) 
     { 
      return DependencyResolver.Current.GetService(type);    
     } 
    } 

とWindsorDependencyResolverクラス

public class WindsorDependencyResolver : IDependencyResolver 
{ 
    private readonly IWindsorContainer container; 

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

    #region IDependencyResolver Members 

    public object GetService(Type serviceType) 
    { 
     return Resolve(serviceType); 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     return container.ResolveAll(serviceType).Cast<object>(); 
    } 

    public IEnumerable<TService> GetAllInstances<TService>() 
    { 
     return container.ResolveAll<TService>(); 
    } 

    public TService GetInstance<TService>() 
    { 
     return (TService)Resolve(typeof(TService)); 
    } 

    #endregion 
    private object Resolve(Type serviceType) 
    { 
     try 
     { 
      return container.Resolve(serviceType); 
     } 
     catch (Exception ex) 
     { 
      return null; 
     } 
    } 
} 

}

今、私はGlobal.asaxの中で、この

container.Register(Component.For<IControllerActivator>().ImplementedBy<WindsorControllerActivator>()); 
container.Register(Component.For<IViewPageActivator>().ImplementedBy<WindsorViewPageActivator>()); 
container.Register(Component.For<IControllerFactory>().ImplementedBy<DefaultControllerFactory>());    
DependencyResolver.SetResolver (new WindsorDependencyResolver(container)); 

ような何かをやっているWindsorViewPageActivatorクラスを作成しました' 次のエラーが発生しました '〜/ Views/Account/LogOn.cshtml'にあるビューが作成されませんでした。 ウィンザーコンテナに各ビューページを登録する必要がある場合は、どのように各ビューを登録できますか?私はRazorビューエンジンを使用しています。 ありがとう

答えて

2

はい、あなたはそれを登録する必要があります。 Have a look at the documentation to familiarise yourself with the API

+0

大丈夫、コントローラのために私はthis.container.Register(AllTypes.Of ().FromAssembly(Assembly.GetExecutingAssembly())のような何かをしました。(c => c.LifeStyle.Transient.Named(c.Implementation .Name.ToLower(CultureInfo.CurrentCulture))))); – Tinku

+0

なぜウィンザー2.5を使用していないのですか? –

+0

はい、Windsor 2.5をダウンロードしました。コントローラ用に、container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly())を使用しました。BasedOn ().Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name .ToLower(CultureInfo.CurrentCulture))))); – Tinku

1

私はこれを自分で試してみましたが、残念ながら正常に動作しないようです。私は私のソリューションで次のことを行います:

public class WindsorViewPageActivator : IViewPageActivator 
{ 
    private readonly IKernel _kernel; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class. 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    public WindsorViewPageActivator([NotNull] IKernel kernel) 
    { 
     if (kernel == null) throw new ArgumentNullException("kernel"); 
     _kernel = kernel; 
    } 

    public object Create(ControllerContext controllerContext, Type type) 
    { 
     if (!_kernel.HasComponent(type)) 
     { 
      if (IsSupportedView(type)) 
      { 
       _kernel.Register(Component.For(type).LifestylePerWebRequest()); 
      } 
      else 
      { 
       return Activator.CreateInstance(type); 
      } 
     } 

     var viewPageInstance = _kernel.Resolve(type); 

     return viewPageInstance; 
    } 

    /// <summary> 
    /// Determines whether the specified type is of a supported view type. 
    /// </summary> 
    /// <param name="viewType">Type of the service.</param> 
    /// <returns> 
    ///  <c>true</c> if the specified type is of a supported view type; otherwise, <c>false</c>. 
    /// </returns> 
    private static bool IsSupportedView(Type viewType) 
    { 
     return viewType.IsAssignableTo<WebViewPage>() 
      || viewType.IsAssignableTo<ViewPage>() 
      || viewType.IsAssignableTo<ViewMasterPage>() 
      || viewType.IsAssignableTo<ViewUserControl>() 
      ; 
    } 
} 

これは、マークアップで何も変更しない限り機能します。そうすると、ビューにコンテナには存在しない新しいタイプが生成されるため、登録エラーが発生します(ただし、名前は同じです)。 私がやったと思ったのは、解決されたらすぐにビューコンポーネントを積極的に解放することでしたが、何らかの理由でコンテナ内でそれを取り除くことはできません。 _kernel.ReleaseComponent(viewPageInstance)への明示的な呼び出しではありません(しかし、それはもちろん、型ではなくインスタンスを解放するだけです)。

Windsorがプロパティを既存のインスタンスに注入するようにする必要があります。つまり、Activator.CreateInstance(type)を使用し、ウィンザーにインスタンスにプロパティを注入するように指示します。しかし、Windsorは既存のインスタンスにプロパティを注入する機能をサポートしていないため、何かを一緒にハックする必要があります。 私はこの1つをhttp://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/(下部にある)と見ましたが、それはうまく機能しません。

私の解決策は、単にビューアアクティベータ(基本ビューページタイプ)で自分のプロパティを手動で設定することでしたが、もっと良い解決策がありますか?私はそれがすべての後に動作を取得するために管理

EDIT

私のソリューションは、単純にそうように、カスタムコンポーネントの活性化因子を作成し、MVCフレームワークの中で行われているものを模倣することです:

public class ViewPageComponentActivator : DefaultComponentActivator 
{ 
    public ViewPageComponentActivator(ComponentModel model, IKernel kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction) 
     : base(model, kernel, onCreation, onDestruction) 
    { 
    } 

    protected override object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments) 
    { 
     // Do like the MVC framework. 
     var instance = Activator.CreateInstance(context.RequestedType); 
     return instance; 
    } 
} 

コンポーネントアクチベーターは、単純に、常にビューの新しいインスタンスを返します。コンポーネントは一時的なものとして登録されているため、常にCreateInstanceが呼び出されます。ここにはいくつかの調整の可能性があります。

ビューページアクティベータははるかに簡単です。ビューの変更時にはサービスのタイプが異なるので、固有の名前に基づいてタイプを登録する必要があります(私はまだこれを修正していませんが、コンポーネントの名前を付ける方が良いかもしれません)。

/// <summary> 
/// An activator using Castle Kernel for activating views. 
/// </summary> 
public class WindsorViewPageActivator : IViewPageActivator 
{ 
    private readonly IKernel _kernel; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class. 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    public WindsorViewPageActivator([NotNull] IKernel kernel) 
    { 
     if (kernel == null) throw new ArgumentNullException("kernel"); 
     _kernel = kernel; 
    } 

    public object Create(ControllerContext controllerContext, Type type) 
    { 
     if (!_kernel.HasComponent(type.FullName)) 
     { 
      _kernel.Register(Component.For(type).Named(type.FullName).Activator<ViewPageComponentActivator>().LifestyleTransient()); 
     } 
     return _kernel.Resolve(type.FullName, type); 
    } 
} 

これは、これが似たような状況にある人にとっては役立つことを願っています。