У нас есть пользовательский RazorViewEngine
на основе темы.
public CustomViewEngine(string theme)
{
PartialViewLocationFormats = new[]
{
"~/Views/PartialViews/" + theme + "/{0}.cshtml",
"~/Views/PartialViews/Base/{0}.cshtml"
}; // This is simplified, we actually have some themes falling back to some other themes before falling back to Base
}
protected void Application_Start()
{
string theme = GetTheme(); // read from config file
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine(theme));
}
Когда тема статическая (например, из файла конфигурации и никогда не изменяется), это все хорошо .
Но теперь нам нужно, чтобы тема была динамическая (пользователь сможет изменить ее).
Каков наилучший способ сделать это?
Установка ViewEngine
при загрузке страницы (в Controller
, а не в Application_Start
) работает, если запросы приходят по одному, но я боюсь, что это может привести к неправильной теме, когда людиодновременно попадают на страницу.
public class HomeController : Controller
{
public ActionResult Index()
{
string selectedTheme = GetUserTheme(); // eg. HttpContext.Current.Request["theme"]
// Reset ViewEngine every page load because selectedTheme may have changed
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine(selectedTheme));
// Putting Thread.Sleep here (to simulate concurrent requests) and opening multiple
// tabs with different theme selections will make some tabs load the wrong theme :(
return View();
}
}
Как правильно CustomViewEngine
правильно выбрать тему и быть устойчивым к одновременным запросам?
Или есть способ переопределить логику ViewEngine, чтобы мы могли написать собственную функцию для определения местоположения файла .cshtml (вместо того, чтобы просто передавать массив возможных местоположений файла)?
РЕДАКТИРОВАТЬ:
Очевидно, решение заключается в переопределении FileExists
, хотя это делает загрузку страницы медленнее.
protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
{
// Do your own logic here, look up Request and return true or false
return base.FileExists(controllerContext, virtualPath);
}
http://robhead89.blogspot.com/2014/01/aspnet-viewengine-caching-and-how-to.html