2009-04-10 11 views
2

Je voulais avoir plus d'un contrôleur et afficher le même objet/modèle dans asp.net mvc, mais il s'est avéré être un peu compliqué que prévu.Sous-dossiers dans les contrôleurs et les vues

Fondamentalement, ce que je veux faire est quelque chose comme ceci:

 
site.com/product 
    -> will show product details to visitors. 

site.com/admin/product 
    -> will show some extra information together with product details. 
     and some commands like delete, edit etc. 

L'objectif est de séparer les urls pour les visiteurs et les admins.

Ma première approche était que je crée un sous-dossier dans le contrôleur et la vue des dossiers, de sorte que les choses regarderais cette façon:

 
> Controllers 
    > Admin 
     ProductController.cs 
    ProductController.cs 
> Views 
    > Admin 
     > Product 
      Index.aspx 
    > Product 
     Index.aspx 

je peux cartographier les urls aux contrôleurs corrects sans problème (à condition que je spécifie leurs espaces de noms, puisque les noms de classe sont les mêmes). Toutefois, lorsque je renvoie l'affichage à partir du Controller sous le dossier admin, il n'affiche pas l'affichage Index sous le dossier Views/Admin/Product mais celui sous Views/Product. Je sais que je peux dire return View("Full path here") pour retourner la vue que je veux. Mais ce n'est évidemment pas une bonne solution et je ne veux pas faire ça.

Ma question est, quelle est la meilleure façon de prendre soin de cette situation, avec l'état des URL doit être de cette façon?

  • Créer une classe de contrôleur personnalisé qui remplace la méthode d'affichage (ou tout autre ceux qui doivent être overriden à cet effet) et assure la vue correcte est retourné?

    • Celui-ci est un hack laid, mais cela fonctionnerait.
  • Créer un moteur de vue personnalisé prenant également en compte les dossiers?

    • Je ne sais pas exactement comment je peux le faire, mais pour autant que je comprends, cela devrait aussi résoudre le problème
  • Utilisez Areas Prototype de Phil Haack?

    • Celui-ci utilise en fait une disposition différente pour les dossiers, mais en théorie cela devrait aussi fonctionner. Mais je ne suis toujours pas sûr si c'est la meilleure façon de le faire, car avoir différents dossiers de contrôle sous les différentes parties du site n'est pas exactement ce que je veux.

Je penche vers la vue personnalisée idée du moteur, qui prend les dossiers en considération lors renvoie les vues, mais comme je l'ai dit, je ne sais pas comment faire.

Des suggestions?

Répondre

1

ASP.Net MVC utilise une structure plate de dossier Vues par défaut. Les zones peuvent aider dans une certaine mesure, même si elles ne donnent que votre un niveau de plus!

Cela peut rendre les vues d'une hiérarchie profondément imbriquée de contrôleurs difficiles à gérer. Ce que vous voulez vraiment, c'est que votre hiérarchie de dossiers Views corresponde à la hiérarchie d'espaces de noms de vos contrôleurs. Les bonnes nouvelles sont que vous pouvez écrire un ViewEngine personnalisé pour le faire avec un effort étonnant - voir mon ControllerPathViewEngine project on GitHub pour plus de détails.

J'ai inclus un extrait de la classe ControllerPathRazorViewEngine pour décrire son fonctionnement. En interceptant les méthodes FindView/FindPartialView et en remplaçant le nom du contrôleur par un chemin de dossier (basé sur l'espace de noms et le nom du contrôleur), nous pouvons l'obtenir pour charger des vues à partir de dossiers imbriqués dans le dossier Views principal.

public class ControllerPathRazorViewEngine : RazorViewEngine 
    { 
     //... constructors etc. 

     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
     { 
      return FindUsingControllerPath(controllerContext,() => base.FindView(controllerContext, viewName, masterName, useCache)); 
     } 

     public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) 
     { 
      return FindUsingControllerPath(controllerContext,() => base.FindPartialView(controllerContext, partialViewName, useCache)); 
     } 

     private ViewEngineResult FindUsingControllerPath(ControllerContext controllerContext, Func<ViewEngineResult> func) 
     { 
      string controllerName = controllerContext.RouteData.GetRequiredString("controller"); 
      string controllerPath = controllerPathResolver.GetPath(controllerContext.Controller.GetType()); 
      controllerContext.RouteData.Values["controller"] = controllerPath; 
      var result = func(); 
      controllerContext.RouteData.Values["controller"] = controllerName; 
      return result; 
     } 
    } 
Questions connexes