it-swarm.com.de

Kann ich einen benutzerdefinierten Speicherort für die Suche nach Ansichten in ASP.NET MVC angeben?

Ich habe das folgende Layout für mein MVC-Projekt:

  • /Controller
    • /Demo
    • / Demo/DemoArea1Controller
    • / Demo/DemoArea2Controller
    • etc...
  • /Ansichten
    • /Demo
    • /Demo/DemoArea1/Index.aspx
    • /Demo/DemoArea2/Index.aspx

Wenn ich dies für DemoArea1Controller:

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

Ich erhalte den Fehler "Die Ansicht 'Index' oder sein Master konnte nicht gefunden werden" mit den üblichen Suchpfaden.

Wie kann ich festlegen, dass Controller in der Namespacesuche "Demo" im Unterordner "Demo" angezeigt werden?

102
Daniel Schaffer

Sie können die WebFormViewEngine einfach erweitern, um alle Standorte anzugeben, in denen Sie suchen möchten:

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

Denken Sie daran, die View Engine zu registrieren, indem Sie die Application_Start-Methode in Ihrer Datei Global.asax.cs ändern

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

Jetzt können Sie in MVC 6 die IViewLocationExpander -Oberfläche implementieren, ohne mit View-Engines herumzuspielen:

public class MyViewLocationExpander : IViewLocationExpander
{
    public void PopulateValues(ViewLocationExpanderContext context) {}

    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        return new[]
        {
            "/AnotherPath/Views/{1}/{0}.cshtml",
            "/AnotherPath/Views/Shared/{0}.cshtml"
        }; // add `.Union(viewLocations)` to add default locations
    }
}

dabei ist {0} der Name der Zielansicht, {1} - der Name des Controllers und {2} - der Name des Bereichs.

Sie können Ihre eigene Standortliste zurückgeben, mit der Standardliste viewLocations (.Union(viewLocations)) zusammenführen oder sie einfach ändern (viewLocations.Select(path => "/AnotherPath" + path)).

Fügen Sie zur Registrierung Ihres benutzerdefinierten View Location Expanders in MVC die nächsten Zeilen zur Methode ConfigureServices in der Datei Startup.cs Hinzu:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RazorViewEngineOptions>(options =>
    {
        options.ViewLocationExpanders.Add(new MyViewLocationExpander());
    });
}
43
whyleee

Es gibt tatsächlich eine viel einfachere Methode, als die Pfade in Ihren Konstruktor fest zu codieren. Unten sehen Sie ein Beispiel für die Erweiterung der Razor-Engine, um neue Pfade hinzuzufügen. Eine Sache, bei der ich nicht ganz sicher bin, ist, ob die hier hinzugefügten Pfade zwischengespeichert werden:

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

Und Ihre 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);
}

Beachten Sie Folgendes: Für Ihren benutzerdefinierten Speicherort muss die Datei ViewStart.cshtml im Stammverzeichnis vorhanden sein.

40
Chris S

Wenn Sie nur neue Pfade hinzufügen möchten, können Sie die Standardansichtsmodule erweitern und einige Codezeilen einsparen:

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

razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
      .Concat(new[] { 
          "~/custom/path/{1}/{0}.cshtml",   // {1} = controller name
          "~/custom/path/Shared/{0}.cshtml" 
      }).ToArray();

ViewEngines.Engines.Add(razorEngine);

Gleiches gilt für WebFormEngine

22
Marcelo De Zen

Anstatt die RazorViewEngine einer Unterklasse zuzuordnen oder sie komplett zu ersetzen, können Sie einfach die vorhandene PartialViewLocationFormats-Eigenschaft von RazorViewEngine ändern. Dieser Code geht in 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();
}
13
Simon Giles

Hinweis: Für ASP.NET MVC 2 sind zusätzliche Pfadangaben erforderlich, die Sie für Ansichten in "Bereiche" festlegen müssen.

 AreaViewLocationFormats
 AreaPartialViewLocationFormats
 AreaMasterLocationFormats

Das Erstellen einer View Engine für einen Bereich ist beschrieben in Phils Blog .

Hinweis: Dies ist eine Vorschau auf Version 1, Änderungen vorbehalten.

3
Simon_Weaver

Versuchen Sie so etwas:

private static void RegisterViewEngines(ICollection<IViewEngine> engines)
{
    engines.Add(new WebFormViewEngine
    {
        MasterLocationFormats = new[] {"~/App/Views/Admin/{0}.master"},
        PartialViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.ascx"},
        ViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.aspx"}
    });
}

protected void Application_Start()
{
    RegisterViewEngines(ViewEngines.Engines);
}
3

Zuletzt habe ich überprüft, dass Sie Ihre eigene ViewEngine erstellen müssen. Ich weiß nicht, ob sie es in RC1 einfacher gemacht haben.

Der grundlegende Ansatz, den ich vor dem ersten RC verwendet habe, bestand in meiner eigenen ViewEngine darin, den Namespace des Controllers zu teilen und nach Ordnern zu suchen, die mit den Teilen übereinstimmen.

EDIT:

Ging zurück und fand den Code. Hier ist die allgemeine Idee.

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