解讀ASP.NET 5 & MVC6系列(16):自定義View視圖文件查找邏輯
之前MVC5和之前的版本中,我們要想對View文件的路徑進行控制的話,則必須要對IViewEngine接口的FindPartialView或FindView方法進行重寫,所有的視圖引擎都繼承于該IViewEngine接口,比如默認的RazorViewEngine。但新版本MVC6中,對視圖文件的路徑方式卻不太一樣了,目前有兩種方式,一種是通過RazorViewEngine,另外一種是通過新特性IViewLocationExpander接口。
通過RazorViewEngine來控制View路徑
在新版的RazorViewEngine中,該類提供了兩個虛屬性(AreaViewLocationFormats和ViewLocationFormats),可以用于重寫控制,而不必再對FindPartialView或FindView方法進行重寫,示例如下:
- public class ThemeViewEngine : RazorViewEngine
- {
- public ThemeViewEngine(IRazorPageFactory pageFactory,
- IRazorViewFactory viewFactory,
- IViewLocationExpanderProvider viewLocationExpanderProvider,
- IViewLocationCache viewLocationCache)
- : base(pageFactory,
- viewFactory,
- viewLocationExpanderProvider,
- viewLocationCache)
- {
- }
- public override IEnumerable<string> AreaViewLocationFormats
- {
- get
- {
- var value = new Random().Next(0, 1);
- var theme = value == 0 ? "Theme1" : "Theme2"; // 可通過其它條件,設置皮膚的種類
- return base.AreaViewLocationFormats.Select(f => f.Replace("/Views/", "/Views/" + theme + "/"));
- }
- }
- public override IEnumerable<string> ViewLocationFormats
- {
- get
- {
var value = new Random().Next(0, 1);
var theme = value == 0 ? "Theme1" : "Theme2"; // 可通過其它條件,設置皮膚的種類
return base.ViewLocationFormats.Select(f => f.Replace("/Views/", "/Views/" + theme + "/"));
- }
- }
- }
- 然后,通過修改MVcOptions的實例屬性ViewEngines即可完成對視圖引擎的替換,代碼如下:
- services.AddMvc().Configure<MvcOptions>(options =>
- {
- options.ViewEngines.Clear();
- options.ViewEngines.Add(typeof(ThemeViewEngine));
- });
這樣,系統在查找視圖文件的時候,就會按照新注冊的ThemeViewEngine的邏輯來執行。
通過IViewLocationExpander來控制View路徑
在MVC6中,微軟還提供了另外一種新的方式來控制View文件的路徑,那就是IViewLocationExpander接口,通過實現該接口即可實現自定義邏輯,并且也可以使用相關的上下文對象。示例如下:
- public class ThemeViewLocationExpander : IViewLocationExpander
- {
- public void PopulateValues(ViewLocationExpanderContext context)
- {
- var value = new Random().Next(0, 1);
- var theme = value == 0 ? "Theme1" : "Theme2";
- context.Values["theme"] = theme;
- }
- public virtual IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context,
- IEnumerable<string> viewLocations)
- {
- return viewLocations.Select(f => f.Replace("/Views/", "/Views/" + context.Values["theme"] + "/"));
- }
- }
在上述自定義的IViewLocationExpander中,實現了2個方法分別是PopulateValues和ExpandViewLocations,PopulateValues方法可以讓我們想ViewLocationExpanderContext上下文中添加響應的鍵值對以便后續使用,通過,我們可以利用通過該上下文對象,來查找ActionContext和HttpContext對象,以便利用這些對象做響應的判斷操作;而ExpandViewLocations方法,只會在沒有View緩存或在View緩存里找不到對應key的View文件時才會調用該方法,在該方法內,我們可以動態返回視圖的位置。
***,我們在Startup.cs里通過修改RazorViewEngineOptions實例對象的ViewLocationExpanders屬性,來實現注冊目的,代碼如下:
- services.Configure<RazorViewEngineOptions>(options =>
- {
- options.ViewLocationExpanders.Add(typeof(ThemViewLocationExpander));
- });