Kann ich in ASP.NET MVC einen benutzerdefinierten Ort „für Ansichten suchen“ angeben?
-
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?
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