Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change default view location scheme in ASP.NET MVC?

I want to change view locations at runtime based on current UI culture. How can I achieve this with default Web Form view engine?

Basically I want to know how implement with WebFormViewEngine something what is custom IDescriptorFilter in Spark.

Is there other view engine which gives me runtime control over view locations?


Edit: My URLs should looks following {lang}/{controller}/{action}/{id}. I don't need language dependent controllers and views are localized with resources. However few of the views will be different in some languages. So I need to tell view engine to looks to the language specific folder first.

like image 206
Jakub Šturc Avatar asked May 26 '09 09:05

Jakub Šturc


People also ask

Which is a default view search path for the Razor view engine?

By default Razor Pages are stored in Pages folder under project root.

In which directory all razor pages are stored and organized in your asp net core application?

Razor Pages use the Pages folder to hold all of the pages for the application. You're free to use folders within the Pages root folder to organize pages in whatever way makes sense for your application.

Which directive help a Cshtml file handle request directly?

@page makes the file into an MVC action, which means that it handles requests directly, without going through a controller. @page must be the first Razor directive on a page.

Does ASP net Core support MVC?

ASP.NET Core has built-in support for dependency injection (DI). In ASP.NET Core MVC, controllers can request needed services through their constructors, allowing them to follow the Explicit Dependencies Principle.


2 Answers

A simple solution would be to, in your Appication_Start get hold of the appropriate ViewEngine from the ViewEngines.Engines collection and update its ViewLocationFormats array and PartialViewLocationFormats. No hackery: it's read/write by default.

protected void Application_Start() {     ...     // Allow looking up views in ~/Features/ directory     var razorEngine = ViewEngines.Engines.OfType<RazorViewEngine>().First();     razorEngine.ViewLocationFormats = razorEngine.ViewLocationFormats.Concat(new string[]      {          "~/Features/{1}/{0}.cshtml"     }).ToArray();     ...     // also: razorEngine.PartialViewLocationFormats if required } 

The default one for Razor looks like this:

ViewLocationFormats = new string[] {     "~/Views/{1}/{0}.cshtml",     "~/Views/{1}/{0}.vbhtml",     "~/Views/Shared/{0}.cshtml",     "~/Views/Shared/{0}.vbhtml" }; 

Note that you may want to update PartialViewLocationFormats also.

like image 70
Duncan Smart Avatar answered Oct 06 '22 03:10

Duncan Smart


VirtualPathProviderViewEngine.GetPathFromGeneralName must be changed to allow an additional parameter from the route. Its not public, that's why you have to copy GetPath, GetPathFromGeneralName, IsSpecificPath ...over to your own ViewEngine implementation.

You are right: this looks like a complete rewrite. I wished GetPathFromGeneralName was public.

using System.Web.Mvc; using System; using System.Web.Hosting; using System.Globalization; using System.Linq;  namespace MvcLocalization {     public class LocalizationWebFormViewEngine : WebFormViewEngine     {         private const string _cacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:";         private const string _cacheKeyPrefix_Master = "Master";         private const string _cacheKeyPrefix_Partial = "Partial";         private const string _cacheKeyPrefix_View = "View";         private static readonly string[] _emptyLocations = new string[0];          public LocalizationWebFormViewEngine()         {             base.ViewLocationFormats = new string[] {                      "~/Views/{1}/{2}/{0}.aspx",                      "~/Views/{1}/{2}/{0}.ascx",                      "~/Views/Shared/{2}/{0}.aspx",                      "~/Views/Shared/{2}/{0}.ascx" ,                      "~/Views/{1}/{0}.aspx",                      "~/Views/{1}/{0}.ascx",                      "~/Views/Shared/{0}.aspx",                      "~/Views/Shared/{0}.ascx"               };          }          private VirtualPathProvider _vpp;          public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)         {             if (controllerContext == null)                 throw new ArgumentNullException("controllerContext");              if (String.IsNullOrEmpty(viewName))                 throw new ArgumentException( "viewName");              string[] viewLocationsSearched;             string[] masterLocationsSearched;              string controllerName = controllerContext.RouteData.GetRequiredString("controller");             string viewPath = GetPath(controllerContext, ViewLocationFormats, "ViewLocationFormats", viewName, controllerName, _cacheKeyPrefix_View, useCache, out viewLocationsSearched);             string masterPath = GetPath(controllerContext, MasterLocationFormats, "MasterLocationFormats", masterName, controllerName, _cacheKeyPrefix_Master, useCache, out masterLocationsSearched);              if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))             {                  return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));             }              return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);         }          private string GetPath(ControllerContext controllerContext, string[] locations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations)         {             searchedLocations = _emptyLocations;              if (String.IsNullOrEmpty(name))                 return String.Empty;              if (locations == null || locations.Length == 0)                 throw new InvalidOperationException();              bool nameRepresentsPath = IsSpecificPath(name);             string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName);              if (useCache)             {                 string result = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, cacheKey);                 if (result != null)                 {                     return result;                 }             }              return (nameRepresentsPath) ?                 GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations) :                 GetPathFromGeneralName(controllerContext, locations, name, controllerName, cacheKey, ref searchedLocations);         }          private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKey, ref string[] searchedLocations)         {             string result = String.Empty;             searchedLocations = new string[locations.Length];             string language = controllerContext.RouteData.Values["lang"].ToString();              for (int i = 0; i < locations.Length; i++)             {                 string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName,language);                  if (FileExists(controllerContext, virtualPath))                 {                     searchedLocations = _emptyLocations;                     result = virtualPath;                     ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);                     break;                 }                  searchedLocations[i] = virtualPath;             }              return result;         }          private string CreateCacheKey(string prefix, string name, string controllerName)         {             return String.Format(CultureInfo.InvariantCulture, _cacheKeyFormat,                 GetType().AssemblyQualifiedName, prefix, name, controllerName);         }          private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations)         {             string result = name;              if (!FileExists(controllerContext, name))             {                 result = String.Empty;                 searchedLocations = new[] { name };             }              ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);             return result;         }          private static bool IsSpecificPath(string name)         {             char c = name[0];             return (c == '~' || c == '/');         }      } } 
like image 31
Mathias F Avatar answered Oct 06 '22 03:10

Mathias F