2010-12-13 34 views
0

je jouais avec le nouveau mvc net Asp 3 RC2. J'ai créé une classe WindsorViewPageActivator comme suitCréation WindsorViewPageActivator

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

puis une classe 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; 
     } 
    } 
} 

}

Maintenant, je suis en train de faire en Global.asax quelque chose comme ça

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)); 

' Maintenant, je reçois l'erreur suivante La vue trouvée dans '~/Views/Account/LogOn.cshtml' n'a pas été créée. Ai-je besoin d'enregistrer chaque page de vue dans le conteneur windsor? Si oui, comment puis-je enregistrer chaque vue? J'utilise le moteur de vue Razor. Merci

Répondre

2

Oui, afin de résoudre les choses que vous devez l'enregistrer. Have a look at the documentation to familiarise yourself with the API.

+0

ok, pour les contrôleurs que je l'ai fait quelque chose comme this.container.Register (AllTypes.Of () .FromAssembly (Assembly.GetExecutingAssembly()). Configurer (c => c.LifeStyle.Transient.Named (c.Implementation .Name.ToLower (CultureInfo.CurrentCulture)))); Pouvez-vous suggérer la syntaxe des vues – Tinku

+0

Pourquoi n'utilisez-vous pas Windsor 2.5? –

+0

Oui, j'ai téléchargé Windsor 2.5 et pour les contrôleurs j'utilise container.Register (AllTypes.FromAssembly (Assembly.GetExecutingAssembly()). BasedOn () .Configure (c => c.LifeStyle.Transient.Named (c.Implementation.Name .ToLower (CultureInfo.CurrentCulture)))); – Tinku

1

J'ai essayé moi-même, et malheureusement je ne peux pas sembler le faire fonctionner correctement. Je fais ce qui suit dans ma solution:

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>() 
      ; 
    } 
} 

Cela fonctionne aussi longtemps que vous ne changez rien dans votre balisage. Si vous le faites, vous obtiendrez une erreur d'enregistrement, car la vue va maintenant générer un nouveau type, qui n'existe pas dans le conteneur (mais il a le même nom!). Ce que je pensais de faire, était de libérer agressivement la composante vue dès qu'il est résolu, mais je ne peux pas vous en débarrasser dans le récipient pour une raison quelconque. Même pas un appel explicite à le ferait (mais cela libère bien sûr l'instance, pas le type).

Ce que nous devons vraiment faire, est de faire des propriétés Windsor injectent dans les instances existantes. Autrement dit, utilisez Activator.CreateInstance(type) puis dites à Windsor d'injecter les propriétés dans l'instance. Mais Windsor ne prend pas en charge l'injection de propriétés dans des instances existantes, nous devons donc pirater quelque chose ensemble, cela fera l'affaire pour nous. Je l'ai vu un http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ (en bas), mais cela ne procéderait pas très bien.

Ma solution consistait simplement à définir manuellement mes propriétés dans l'activateur de page d'affichage (vous avez un type de page d'affichage de base), mais peut-être y a-t-il une meilleure solution?

EDIT

j'ai réussi à le faire fonctionner après tout!

Ma solution est de créer simplement un activateur de composant personnalisé et imiter ce qui se fait dans le cadre MVC, comme ceci:

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; 
    } 
} 

L'activateur composante retour simplement toujours une nouvelle instance de la vue. Étant donné que le composant est enregistré comme étant transitoire, CreateInstance est toujours appelé. Il pourrait y avoir quelques possibilités de peaufinage ici.

L'activateur de page d'affichage est maintenant beaucoup plus simple. Notez que le type de service est différent chaque fois que vous changez la vue, nous devons donc enregistrer le type en fonction de son nom unique (je ne l'ai pas encore modifié, mais il pourrait y avoir une meilleure façon de nommer le composant).

/// <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); 
    } 
} 

J'espère que cela pourrait être utile à quelqu'un dans des situations similaires.