2012-07-24 3 views
2

Je jetais un coup d'oeil à ASP.NET MVC 4 RC et ne trouve pas DefaultHttpControllerFactory ou même IHttpControllerFactory pour permettre à mon conteneur IoC de choix (Castle Windsor) de se connecter au framework pour Web Api contrôleurs. J'ai fini par utiliser IDependencyResolver, ce qui rend la libération des composants un peu plus compliquée, mais a fini avec ce qui suit. Est-ce que ça va marcher/pas de fuite de mémoire jusqu'à ce que IDependencyResolver ait une méthode Release? Global.asax finit comme:ASP.NET MVC 4 RC avec Castle Windsor

public class WebApiApplication : System.Web.HttpApplication 
{ 
    private IWindsorContainer container; 

    protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 

     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
     RouteConfig.RegisterRoutes(RouteTable.Routes); 
     BundleConfig.RegisterBundles(BundleTable.Bundles); 

     Windsor(); 
    } 

    protected void Application_End() 
    { 
     container.Dispose(); 
    } 

    private void Windsor() 
    { 
     container = new WindsorContainer().Install(FromAssembly.This()); 

     // mvc: 
     var mvcControllerFactory = new WindsorControllerFactory(container.Kernel); 
     ControllerBuilder.Current.SetControllerFactory(mvcControllerFactory); 

     // web api: 
     var httpDependencyResolver = new WindsorHttpDependencyResolver(container.Kernel); 
     GlobalConfiguration.Configuration.DependencyResolver = httpDependencyResolver; 
    } 
} 

WindsorControllerFactory est l'extension de DefaultControllerFactory pour les contrôleurs Mvc et il y a un installateur Windsor pour eux. WindsorHttpDependencyResolver finit comme:

public class WindsorHttpDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver 
{ 
    private readonly IKernel kernel; 

    public WindsorHttpDependencyResolver(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public IDependencyScope BeginScope() 
    { 
     return kernel.Resolve<IDependencyScope>(); // instances released suitably (at end of web request) 
    } 

    public object GetService(Type serviceType) 
    { 
     // for ModelMetadataProvider and other MVC related types that may have been added to the container 
     // check the lifecycle of these registrations 
     return kernel.HasComponent(serviceType) ? kernel.Resolve(serviceType) : null; 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     return kernel.HasComponent(serviceType) ? kernel.ResolveAll(serviceType) as IEnumerable<object> : Enumerable.Empty<object>(); 
    } 

    public void Dispose() 
    { 
     // Nothing created so nothing to dispose - kernel will take care of its own 
    } 
} 

En théorie, cela signifie Windsor va maintenant fournir les contrôleurs de api, une fois qu'ils sont installés:

public class ApiControllersInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.AddFacility<TypedFactoryFacility>(); 
     container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<WebApiTypedFactoryComponentSelector>()); 
     container.Register(Component.For<IDependencyScope>().AsFactory(tfc => tfc.SelectedWith<WebApiTypedFactoryComponentSelector>()).LifestylePerWebRequest()); 

     container.Register(Classes.FromAssemblyContaining<ValuesController>().BasedOn<IHttpController>().LifestyleTransient()); 
    } 
} 

J'utilise l'installation d'usine dactylographiée à mettre en œuvre IDependencyScope pour moi , ce qui signifie que lorsque le framework le disposera à la fin d'une requête, il libérera implicitement le contrôleur et ses dépendances. En utilisant un cycle de vie par demande Web, Windsor libérera également l'usine. Cela laisse simplement le sélecteur de composants d'usine tapé sur mesure que GetService (s) ne trouvera rien dans le conteneur:

public class WebApiTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector 
{ 
    protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments) 
    { 
     if (method.Name == "GetService" || method.Name == "GetServices") 
     { 
      return (arguments[0] as Type).FullName; 
     } 
     return base.GetComponentName(method, arguments); 
    } 

    protected override Type GetComponentType(System.Reflection.MethodInfo method, object[] arguments) 
    { 
     if (method.Name == "GetService" || method.Name == "GetServices") 
     { 
      return arguments[0] as Type; 
     } 
     return base.GetComponentType(method, arguments); 
    } 
} 

Espérons que cela est utile.

+0

Est-ce que votre question "Est-ce que ça va marcher/pas de fuite de mémoire jusqu'à ce que IDependencyResolver ait une méthode Release?"? –

+0

@Jesse Je suppose que j'essaie de savoir si c'est une approche viable compte tenu de la structure de MVC 4 RC. Je crois que j'ai bien compris les documents de Windsor, mais si j'ai fait une erreur quelque part, je serais reconnaissant si quelqu'un me l'indiquait. – hagrid27

Répondre

3

J'ai fini par utiliser le code de this blog post (encore amélioré par this other one par Mark Seemann), qui crée une portée par requête et prend soin de libérer les objets créés. C'est une approche légèrement différente de celle que vous avez prise.

+0

Merci pour le lien, semble intéressant. – hagrid27

Questions connexes