106 votes

Puis-je spécifier un emplacement personnalisé pour "rechercher des vues" dans ASP.NET MVC?

J'ai la suite de la mise en page pour mon projet mvc:

  • /Contrôleurs
    • /Démo
    • /Demo/DemoArea1Controller
    • /Demo/DemoArea2Controller
    • etc...
  • /Points de vue
    • /Démo
    • /Demo/DemoArea1/Index.aspx
    • /Demo/DemoArea2/Index.aspx

Cependant, quand j'ai ce pour DemoArea1Controller:

public class DemoArea1Controller : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Je reçois le "La vue" index "ou son maître n'a pas pu être trouvé" erreur, avec les emplacements de recherche habituels.

Comment puis-je spécifier que les contrôleurs de la "Démonstration" de l'espace de noms de la recherche dans la "Démo" afficher le sous-dossier?

122voto

Sam Wessel Points 4906

Vous pouvez facilement étendre WebFormViewEngine pour spécifier tous les emplacements que vous souhaitez rechercher:

 public class CustomViewEngine : WebFormViewEngine
{
    public CustomViewEngine()
    {
        var viewLocations =  new[] {  
            "~/Views/{1}/{0}.aspx",  
            "~/Views/{1}/{0}.ascx",  
            "~/Views/Shared/{0}.aspx",  
            "~/Views/Shared/{0}.ascx",  
            "~/AnotherPath/Views/{0}.ascx"
            // etc
        };

        this.PartialViewLocationFormats = viewLocations;
        this.ViewLocationFormats = viewLocations;
    }
}
 

N'oubliez pas d'enregistrer le moteur de visualisation en modifiant la méthode Application_Start dans votre fichier Global.asax.cs.

 protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new CustomViewEngine());
}
 

42voto

Chris S Points 32376

Il existe en fait une méthode beaucoup plus simple que de coder en dur les chemins dans votre constructeur. Vous trouverez ci-dessous un exemple d'extension du moteur Razor afin d'ajouter de nouveaux chemins. Une chose sur laquelle je ne suis pas tout à fait sûr est de savoir si les chemins que vous ajoutez ici seront mis en cache:

 public class ExtendedRazorViewEngine : RazorViewEngine
{
    public void AddViewLocationFormat(string paths)
    {
        List<string> existingPaths = new List<string>(ViewLocationFormats);
        existingPaths.Add(paths);

        ViewLocationFormats = existingPaths.ToArray();
    }

    public void AddPartialViewLocationFormat(string paths)
    {
        List<string> existingPaths = new List<string>(PartialViewLocationFormats);
        existingPaths.Add(paths);

        PartialViewLocationFormats = existingPaths.ToArray();
    }
}
 

Et votre Global.asax.cs

 protected void Application_Start()
{
    ViewEngines.Engines.Clear();

    ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
    engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.cshtml");
    engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.vbhtml");

    // Add a shared location too, as the lines above are controller specific
    engine.AddPartialViewLocationFormat("~/MyThemes/{0}.cshtml");
    engine.AddPartialViewLocationFormat("~/MyThemes/{0}.vbhtml");

    ViewEngines.Engines.Add(engine);

    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
}
 

Une chose à noter: votre emplacement personnalisé aura besoin du fichier ViewStart.cshtml à la racine.

23voto

devundef Points 4561

Si vous souhaitez simplement ajouter de nouveaux chemins, vous pouvez simplement ajouter aux moteurs de vue par défaut:

 ViewEngines.Engines.Clear();
var razorEngine = new RazorViewEngine();
razorEngine.MasterLocationFormats = razorEngine.MasterLocationFormats
      .Concat(new[] { "~/V3/Views/{0}.cshtml" }).ToArray();

razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
      .Concat(new[] { 
          "~/V3/Views/{1}/{0}.cshtml", 
          "~/V3/Views/Shared/{0}.cshtml" 
      }).ToArray();

ViewEngines.Engines.Add(razorEngine);
 

Faites la même chose avec WebFormEngine () ...

13voto

Simon Giles Points 116

Au lieu de sous-classer RazorViewEngine ou de le remplacer directement, vous pouvez simplement modifier la propriété existante de RazorViewEngine, PartialViewLocationFormats. Ce code va dans Application_Start:

 System.Web.Mvc.RazorViewEngine rve = (RazorViewEngine)ViewEngines.Engines
  .Where(e=>e.GetType()==typeof(RazorViewEngine))
  .FirstOrDefault();

string[] additionalPartialViewLocations = new[] { 
  "~/Views/[YourCustomPathHere]"
};

if(rve!=null)
{
  rve.PartialViewLocationFormats = rve.PartialViewLocationFormats
    .Union( additionalPartialViewLocations )
    .ToArray();
}
 

3voto

Joel Potter Points 12759

Aux dernières nouvelles, cela nécessite que vous construisiez votre propre ViewEngine. Je ne sais pas s'ils ont rendu les choses plus faciles en RC1.

L’approche de base que j’avais utilisée avant le premier contrôleur de contrôle consistait, dans mon propre ViewEngine, à diviser l’espace de noms du contrôleur et à rechercher les dossiers qui correspondaient aux parties.

MODIFIER:

Je suis retourné et j'ai trouvé le code. Voici l'idée générale.

 public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
{
    string ns = controllerContext.Controller.GetType().Namespace;
    string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");

    //try to find the view
    string rel = "~/Views/" +
        (
            ns == baseControllerNamespace ? "" :
            ns.Substring(baseControllerNamespace.Length + 1).Replace(".", "/") + "/"
        )
        + controller;
    string[] pathsToSearch = new string[]{
        rel+"/"+viewName+".aspx",
        rel+"/"+viewName+".ascx"
    };

    string viewPath = null;
    foreach (var path in pathsToSearch)
    {
        if (this.VirtualPathProvider.FileExists(path))
        {
            viewPath = path;
            break;
        }
    }

    if (viewPath != null)
    {
        string masterPath = null;

        //try find the master
        if (!string.IsNullOrEmpty(masterName))
        {

            string[] masterPathsToSearch = new string[]{
                rel+"/"+masterName+".master",
                "~/Views/"+ controller +"/"+ masterName+".master",
                "~/Views/Shared/"+ masterName+".master"
            };


            foreach (var path in masterPathsToSearch)
            {
                if (this.VirtualPathProvider.FileExists(path))
                {
                    masterPath = path;
                    break;
                }
            }
        }

        if (string.IsNullOrEmpty(masterName) || masterPath != null)
        {
            return new ViewEngineResult(
                this.CreateView(controllerContext, viewPath, masterPath), this);
        }
    }

    //try default implementation
    var result = base.FindView(controllerContext, viewName, masterName);
    if (result.View == null)
    {
        //add the location searched
        return new ViewEngineResult(pathsToSearch);
    }
    return result;
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X