ASP.NET Core 自定義視圖路徑及主題切換


 原文地址:https://www.cnblogs.com/ElderJames/p/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html

 

 

0|1背景


切換主題,是博客、CMS等系統的必備功能,一般來說,有三種切換主題的需求。

  1. 在管理后台上傳主題包,並選擇主題
  2. 前端自動按照頻道、欄目等切換模版
  3. 用戶在前端切換主題,並記錄用戶的選擇

這三種需求,其實核心原理都是一樣,就是制定一套主題的目錄,切換主題等於切換目錄名。主題內的頁面模版都是按照一定的規則存放的。

下面是兩個主題包的目錄示例:

  .
  ├── theme0
  |   ├── Assets
  |   |   ├── js
  |   |   ├── css
  |   |   └── img
  |   ├── Home
  |   |   ├── Index.cshtml
  |   |   └── About.cshtml
  |   ├── Article
  |   |   ├── Index.cshtml
  |   |   └── Detail.cshtml
  |   └── Shared
  |       ├── Page.cshtml
  |       └──  _Layout.cshtml
  └── theme1
      ├── Assets
      |   ├── js
      |   ├── css
      |   └── img
      ├── Home
      |   ├── Index.cshtml
      |   └── About.cshtml
      ├── Article
      |   ├── Index.cshtml
      |   └── Detail.cshtml
      └── Shared
          ├── Page.cshtml
          └──  _Layout.cshtml

大家一定注意到了,上面每個主題包里都按照傳統ASP.NET MVC的約定來划分目錄:控制器名為文件夾,操作名為視圖文件。其實這里只是方便起見,按照接下來介紹的方法,是可以完全地自定義這個目錄划分的。

0|1原理

 

當ASP.NET MVC從控制器處理完數據返回視圖的時候,ASP.NET MVC會按照默認的多個路徑去查找文件,如果文件存在,則使用該文件渲染,如果不存在,則尋找下一個路徑,比如默認的路徑會有/{Area}/{Controller}/{Action}.cshtml/{Controller}/{Action}.cshtml/Shared/{Action}.cshtml等等我們熟悉的約定,那么在查找視圖文件時,會安裝從左往右的路徑去查詢,如果都查詢不出來,是會報錯的。

而如果要做到切換主題文件夾名來切換主題,我們就需要在默認規則上加主題的目錄占位符,使的查詢時用主題文件夾名來替換占位符,例如/{theme}/{Controller}/{Action}.cshtml/{theme}/Shared/{Action}.cshtml等等,這樣,當查詢視圖文件時,就能匹配到對應的主題文件夾,並且找到相應的視圖了。

總結起來,切換主題功能有兩個重點需要我們去實現:

  1. 在原有規則中加入占位符
  2. 每次請求都獲取當前的主題名,並改變視圖查詢路徑

0|1實現


最簡單的實現,在操作(action)的最后return View(viewPath)時傳入視圖路徑,直接就能指向對應視圖,但是,這樣做一點都不靈活,而且每個操作都要傳路徑也是不夠簡潔,不容易維護,所以我們需要更好的解決方案。

ASP.NET MVC 實現

在ASP.NET MVC時代,我們可通過繼承RazorViewEngine類,在基類的ViewLocationFormatsPartialViewLocationFormats兩個屬性中加入有主題目錄名占位符的路徑,並重寫CreateViewCreatePartialViewFileExists三個方法,使每次請求都能獲取最新的主題名,如下面的例子中從路由數據對象中獲取主題名:

public class TemplateViewEngine : RazorViewEngine { public TemplateViewEngine() : base() { ViewLocationFormats = new[] { "~/Views/{1}%1/{0}.cshtml", "~/Views/{1}/{0}.cshtml",//默認路徑 "~/Views/Shared%1/{0}.cshtml", "~/Views/Shared/{0}.cshtml", }; PartialViewLocationFormats = new[] { "~/Views/{1}%1/{0}.cshtml", "~/Views/{1}/{0}.cshtml",//默認路徑 "~/Views/Shared%1/{0}.cshtml", "~/Views/Shared/{0}.cshtml", }; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : ""; return base.CreatePartialView(controllerContext, partialPath.Replace("%1", template)); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : ""; return base.CreateView(controllerContext, viewPath.Replace("%1", template), masterPath); } protected override bool FileExists(ControllerContext controllerContext, string virtualPath) { var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : ""; return base.FileExists(controllerContext, virtualPath.Replace("%1", template)); } }

事實上,如果是需要實現不同用戶不同主題的功能,主題信息可以存儲在Session中,還能從controllerContext實例獲取Session中存儲的主題名。

那么,在ASP.NET Core中如何實現呢?

ASP.NET Core 實現

ASP.NET Core 相比ASP.NET MVC框架,雖然使用上為了開發者平滑過渡,很多約定都相同,但是架構本身是做了翻天覆地的重構和優化,得益於一脈相承的MSDI框架,ASP.NET Core框架實現了組件化,很多功能都通過IoC的方式修改或擴展。例如本文介紹的主題情況功能,就是實現IViewLocationExpander接口來達到擴展配置的目的,而且還比ASP.NET MVC的更加簡潔:

public class TemplateViewLocationExpander : IViewLocationExpander { public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) { var template = context.Values["template"] ?? "Default"; string[] locations = { "/Views/" + template + "/{1}/{0}.cshtml", "/Views/" + template + "/{0}.cshtml", "/Views/" + template + "/Shared/{0}.cshtml" }; return locations.Union(viewLocations); } public void PopulateValues(ViewLocationExpanderContext context) { context.Values["template"] = context.ActionContext.RouteData.Values["Template"]?.ToString() ?? "Default"; } }

這個接口里面,PopulateValues方法主要用來獲取實時的主題信息,context.ActionContext中除了RouteData可獲得實時數據,還有HttpContext實例可獲得用戶信息,甚至能利用RequestServices實例注入服務。而只有在PopulateValues中修改了contextExpandViewLocations方法才會從context中獲得主題信息,從而達到修改視圖查找路徑的目的。

當我們實現了IViewLocationExpander接口后,還需要在Startup類的services.AddMvc();下修改MVC的配置:

services.AddMvc();
//配置模版視圖路徑 services.Configure<RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new TemplateViewLocationExpander()); });

PS:這種修改MVC內部配置的方式很有趣,以后有空會研究一番。

0|1總結

 

本文主要介紹了在ASP.NET Core中利用修改視圖查詢路徑實現主題切換的功能,雖然只介紹了核心部分,但是其它部分如管理主題、前端切換等功能,都是很容易實現的,以后我會在我的框架樣例中實現,敬請大家關注啦

 

 

 

 

 

在開發MVC的過程中可能遇到這種情況:我希望我的視圖可以放在自定義的文件夾下,而不是放在默認的Views文件夾下,這時我就需要更改MVC的默認路徑

  如圖,我的移動端和PC端是兩套單獨設計的頁面,所以我把視圖拆分到了兩個文件夾下:PC和Mobile,但是MVC的默認路徑是找不到這兩個文件夾的,所以我進行了以下更改

 

 

 

ASP.NET Core中有一個接口IViewLocationExpander 通過繼承這個接口我們可以更改,MVC訪問的默認文件路徑

 

 

 

接口中的兩個方法PopulateValues  方法可以讓我在ViewLocationExpanderContext上下文中添加后續可能會用到的鍵值對

ExpandViewLocations 方法會在MVC無法找到默認的視圖路徑時調用,動態的返回需要的路徑

通過這種方法,我們就可以實現更改MVC的視圖默認訪問路徑了
————————————————
版權聲明:本文為CSDN博主「_Tassdar」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/CuiLanren/article/details/81566504

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM