Могу ли я указать пользовательское местоположение для "поиска представлений" в ASP.NET MVC?
у меня есть следующий макет для моего проекта mvc:
- /контроллеры
- / Demo
- / Demo / DemoArea1Controller
- / Demo / DemoArea2Controller
- etc...
- /вид
- / Demo
- / Demo / DemoArea1 / Index.aspx
- / Demo / DemoArea2 / Index.aspx
Впрочем, когда у меня есть это DemoArea1Controller
:
public class DemoArea1Controller : Controller
{
public ActionResult Index()
{
return View();
}
}
I получите ошибку" The view 'index' или его мастер не может быть найден " с обычными местами поиска.
Как я могу указать, что контроллеры в поиске пространства имен "Demo"в подпапке" Demo " view?
8 ответов:
Вы можете легко расширить WebFormViewEngine, чтобы указать все места, в которых вы хотите посмотреть:
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; } }
убедитесь, что вы не забыли зарегистрировать механизм просмотра, изменив метод Application_Start в своем глобальном.асакс.cs
protected void Application_Start() { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new CustomViewEngine()); }
на самом деле есть гораздо более простой метод, чем жесткое кодирование путей в вашем конструкторе. Ниже приведен пример расширения Razor engine для добавления новых путей. Одна вещь, в которой я не совсем уверен, - это будут ли пути, которые вы добавляете здесь, кэшироваться:
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(); } }
и ваш глобальный.асакс.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); }
одна вещь, чтобы отметить: ваше пользовательское местоположение будет нуждаться в ViewStart.cshtml файл в его корень.
теперь в MVC 6 Вы можете реализовать
IViewLocationExpander
интерфейс без возиться с движками просмотра: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 } }
здесь
{0}
это имя целевого вида,{1}
- имя контроллера и{2}
- название области.вы можете вернуть свой собственный список местоположений, объединить его с default
viewLocations
(.Union(viewLocations)
) или просто изменить их (viewLocations.Select(path => "/AnotherPath" + path)
).чтобы зарегистрировать пользовательский расширитель местоположения представления в MVC, добавьте следующие строки в
ConfigureServices
методStartup.cs
файл:public void ConfigureServices(IServiceCollection services) { services.Configure<RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new MyViewLocationExpander()); }); }
Если вы хотите просто добавить новые пути, вы можете добавить к механизмам просмотра по умолчанию и сэкономить несколько строк кода:
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);
то же самое относится к
WebFormEngine
вместо подкласса RazorViewEngine или его прямой замены вы можете просто изменить существующее свойство PartialViewLocationFormats RazorViewEngine. Этот код идет в 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(); }
последний раз я проверял, это требует от вас построить свой собственный ViewEngine. Я не знаю, если они сделали это проще в RC1, хотя.
основной подход, который я использовал до первого RC, был, в моем собственном ViewEngine, чтобы разделить пространство имен контроллера и искать папки, которые соответствуют частям.
EDIT:
вернулся и нашел код. Вот общая идея.
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; }
попробуйте что-то вроде этого:
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); }
Примечание: для ASP.NET MVC 2 у них есть дополнительные пути расположения, которые вам нужно будет установить для представлений в "областях".
AreaViewLocationFormats AreaPartialViewLocationFormats AreaMasterLocationFormats
создание механизма просмотра для области-это описано в блоге.
Примечание: это для версии 1, поэтому может быть изменена.