Kann ich in ASP.NET MVC einen benutzerdefinierten Ort „für Ansichten suchen“ angeben?

StackOverflow https://stackoverflow.com/questions/632964

  •  08-07-2019
  •  | 
  •  

Frage

Ich habe folgendes Layout für mein MVC-Projekt:

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

Allerdings, wenn ich dies für DemoArea1Controller:

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

Ich erhalte den „Die Ansicht‚Index‘oder sein Master kann nicht gefunden werden“ Fehler mit den üblichen Suchpositionen.

Wie kann ich festlegen, dass Controller in der „Demo“ Namespace-Suche in der „Demo“ Ansicht Unterordner?

War es hilfreich?

Lösung

Sie können leicht die WebFormViewEngine erweitern alle Standorte angeben, die Sie suchen in 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;
    }
}

Merken Sie sich die Ansicht Engine zu registrieren, indem die Application_Start Methode in Ihrer Global.asax.cs Modifizieren

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

Andere Tipps

Jetzt 6 in MVC können Sie IViewLocationExpander Schnittstelle implementieren, ohne mit Blick Motoren rumgespielt:

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

wo {0} ist Zielansicht Name, {1} - Controller-Name und {2} -. Bereichsname

Sie können Ihre eigene Liste von Orten zurückzukehren, führen Sie sich mit Standard-viewLocations (.Union(viewLocations)) oder sich einfach ändern (viewLocations.Select(path => "/AnotherPath" + path)).

Um die benutzerdefinierte Ansicht Lage Expander in MVC, fügen Sie folgende Zeilen ConfigureServices Methode in Startup.cs Datei zu registrieren:

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

Es gibt tatsächlich viele einfachere Methode als die Pfade in Ihr Konstruktor zu. Unten ist ein Beispiel der Rasierer Motor erstreckt, neue Wege zu addieren. Eine Sache, ich bin nicht ganz sicher ist, ob die Pfade, die Sie hier hinzufügen, werden im Cache gespeichert 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);
}

Eine Sache zu beachten:. Ihre individuelle Lage die ViewStart.cshtml Datei in seiner Wurzel benötigen

Wenn Sie nur neue Wege hinzufügen möchten, können Sie auf die Standardansicht Motoren hinzuzufügen und einige Zeilen Code verschonen:

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

Das gleiche gilt für WebFormEngine

Statt die RazorViewEngine von Subklassen, oder es völlig zu ersetzen, können Sie einfach bestehende RazorViewEngine Eigentum PartialViewLocationFormats ä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();
}

Zuletzt habe ich gecheckt, dies erfordert, dass Sie Ihre eigenen Viewengine zu bauen. Ich weiß nicht, ob sie, obwohl es leichter in RC1 gemacht.

Der grundlegende Ansatz, den ich vor dem ersten RC verwendet wurde, in meinem eigenen Viewengine, den Namensraum des Controllers zu spalten und für Ordner suchen, die die Teile angepasst.

EDIT:

Wir gingen zurück und den Code gefunden. 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;
}

Versuchen Sie etwas wie folgt aus:

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

. Hinweis: für ASP.NET MVC 2 sie zusätzliche Standortpfade haben, müssen Sie für Ansichten in ‚Areas‘ gesetzt

 AreaViewLocationFormats
 AreaPartialViewLocationFormats
 AreaMasterLocationFormats

einen Blick Motor für einen Bereich zu schaffen, ist auf Phils beschrieben Blog .

. Hinweis: Dies ist für Preview Release 1, so kann sich ändern

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top