ASP.NET MVC重寫的執行個體教程

來源:互聯網
上載者:User
這篇文章主要為大家詳細介紹了ASP.NET MVC重寫RazorViewEngine實現多主題切換,具有一定的參考價值,感興趣的小夥伴們可以參考一下

在ASP.NET MVC中來實現主題的切換一般有兩種方式,一種是通過切換皮膚的css和js引用,一種就是通過重寫視圖引擎。通過重寫視圖引擎的方式更加靈活,因為我不僅可以在不同主題下面布局和樣式不一樣,還可以讓不同的主題下面顯示的資料條目不一致,就是說可以在某些主題下面添加一下個人化的東西。

本篇我將通過重寫視圖引擎的方式來進行示範,在這之前,我假設你已經具備了MVC的一些基礎,我們先來看下效果:

系統登入後是預設主題,當我們點擊切換主題之後,左側功能表列的布局變了,右側內容的樣式也變了,而地址欄是不變的。介面UI用的metronic,雖然官網是收費的,但是在天朝,總是可以找到免費的。官方地址:http://keenthemes.com/preview/metronic/

在這裡,我使用了分地區、分模組(按獨立的業務功能劃分)的方式,一個模組就是一個獨立的dll,在這裡Secom.Emx.Admin和Secom.Emx.History就是兩個獨立的模組,並分別建立了地區Admin和History。

你會發現Secom.Emx.Admin模型下面的Areas目錄和Secom.Emx.WebApp中的目錄是一模一樣的,其實我最初不想在模組項目中添加任何的View,但是為了方便獨立部署還是加了。

按右鍵項目Secom.Emx.Admin,選擇“屬性”——“建置事件”添加如下代碼:


xcopy /e/r/y $(ProjectDir)Areas\Admin\Views $(SolutionDir)Secom.Emx.WebApp\Areas\Admin\Views

這命令很簡單,其實就是當編譯項目Secom.Emx.Admin的時候,將項目中的Views複製到Secom.Emx.WebApp項目的指定目錄下。

地區設定檔我放置到了Secom.Emx.WebApp中,其實你完全可以獨立放置到一個類庫項目中,因為註冊地區路由的後,項目最終會尋找bin目錄下面所有繼承了AreaRegistration類的,然後讓WebApp引用這個類庫項目,Secom.Emx.WebApp項目添加Secom.Emx.Admin、Secom.Emx.History的引用。

AdminAreaRegistration代碼如下:


using System.Web.Mvc;namespace Secom.Emx.WebApp{ public class AdminAreaRegistration : AreaRegistration  {  public override string AreaName   {   get    {    return "Admin";   }  }  public override void RegisterArea(AreaRegistrationContext context)   {   context.MapRoute(    "Admin_default",    "Admin/{controller}/{action}/{id}",    new { action = "Index", id = UrlParameter.Optional },    namespaces:new string[1] { "Secom.Emx.Admin.Areas.Admin.Controllers" }   );  } }}

注意命名空間和後面添加的 namespaces:new string[1] { "Secom.Emx.Admin.Areas.Admin.Controllers" },這個命名空間就是獨立模組Secom.Emx.Admin下面的控制器所在的命名空間。

HistoryAreaRegistration代碼如下:


using System.Web.Mvc;namespace Secom.Emx.WebApp{ public class HistoryAreaRegistration : AreaRegistration  {  public override string AreaName   {   get    {    return "History";   }  }  public override void RegisterArea(AreaRegistrationContext context)   {   context.MapRoute(    "History_default",    "History/{controller}/{action}/{id}",    new { action = "Index", id = UrlParameter.Optional },    namespaces:new string[1] { "Secom.Emx.History.Areas.History.Controllers" }   );  } }}

我們先看下RazorViewEngine的原始建構函式如下:


public RazorViewEngine(IViewPageActivator viewPageActivator)   : base(viewPageActivator)  {   AreaViewLocationFormats = new[]   {    "~/Areas/{2}/Views/{1}/{0}.cshtml",    "~/Areas/{2}/Views/{1}/{0}.vbhtml",    "~/Areas/{2}/Views/Shared/{0}.cshtml",    "~/Areas/{2}/Views/Shared/{0}.vbhtml"   };   AreaMasterLocationFormats = new[]   {    "~/Areas/{2}/Views/{1}/{0}.cshtml",    "~/Areas/{2}/Views/{1}/{0}.vbhtml",    "~/Areas/{2}/Views/Shared/{0}.cshtml",    "~/Areas/{2}/Views/Shared/{0}.vbhtml"   };   AreaPartialViewLocationFormats = new[]   {    "~/Areas/{2}/Views/{1}/{0}.cshtml",    "~/Areas/{2}/Views/{1}/{0}.vbhtml",    "~/Areas/{2}/Views/Shared/{0}.cshtml",    "~/Areas/{2}/Views/Shared/{0}.vbhtml"   };     ViewLocationFormats = new[]   {    "~/Views/{1}/{0}.cshtml",    "~/Views/{1}/{0}.vbhtml",    "~/Views/Shared/{0}.cshtml",    "~/Views/Shared/{0}.vbhtml"   };   MasterLocationFormats = new[]   {    "~/Views/{1}/{0}.cshtml",    "~/Views/{1}/{0}.vbhtml",    "~/Views/Shared/{0}.cshtml",    "~/Views/Shared/{0}.vbhtml"   };   PartialViewLocationFormats = new[]   {    "~/Views/{1}/{0}.cshtml",    "~/Views/{1}/{0}.vbhtml",    "~/Views/Shared/{0}.cshtml",    "~/Views/Shared/{0}.vbhtml"   };     FileExtensions = new[]   {    "cshtml",    "vbhtml",   };  }

然後建立CustomRazorViewEngine繼承自RazorViewEngine,對View的路由規則進行了重寫,既然可以重寫路由規則,那意味著,你可以任意定義規則,然後遵守自己定義的規則就可以了。需要注意的是,要注意路由數組中的順序,查詢檢視表時,是按照前後順序依次尋找的,當找到了視圖就立即返回,不會再去匹配後面的路由規則。為了提升路由尋找效率,我這裡刪除了所有vbhtml的路由規則,因為我整個項目中都採用C#語言。


using System.Web.Mvc;namespace Secom.Emx.WebApp.Helper{ public class CustomRazorViewEngine : RazorViewEngine {  public CustomRazorViewEngine(string theme)  {   if (!string.IsNullOrEmpty(theme))   {    AreaViewLocationFormats = new[]    {      //themes      "~/themes/"+theme+"/views/Areas/{2}/{1}/{0}.cshtml",      "~/themes/"+theme+"/Shared/{0}.cshtml"  "~/Areas/{2}/Views/{1}/{0}.cshtml",  "~/Areas/{2}/Views/Shared/{0}.cshtml" };    AreaMasterLocationFormats = new[]    {        //themes    "~/themes/"+theme+"/views/Areas/{2}/{1}/{0}.cshtml",    "~/themes/"+theme+"/views/Areas/{2}/Shared/{0}.cshtml",    "~/themes/"+theme+"/views/Shared/{0}.cshtml",  "~/Areas/{2}/Views/{1}/{0}.cshtml",  "~/Areas/{2}/Views/Shared/{0}.cshtml" };    AreaPartialViewLocationFormats = new[]    {       //themes   "~/themes/"+theme+"/views/Shared/{0}.cshtml",  "~/Areas/{2}/Views/{1}/{0}.cshtml",  "~/Areas/{2}/Views/Shared/{0}.cshtml" };    ViewLocationFormats = new[]    {       //themes   "~/themes/"+theme+"/views/{1}/{0}.cshtml",  "~/Views/{1}/{0}.cshtml",  "~/Views/Shared/{0}.cshtml" };    MasterLocationFormats = new[]    {       //themes   "~/themes/"+theme+"/views/Shared/{0}.cshtml",  "~/Views/{1}/{0}.cshtml",  "~/Views/Shared/{0}.cshtml" };    PartialViewLocationFormats = new[]    {       //themes  "~/themes/"+theme+"/views/Shared/{0}.cshtml",  "~/Views/{1}/{0}.cshtml",  "~/Views/Shared/{0}.cshtml" };    FileExtensions = new[]{"cshtml"};   }  } }}

重寫後,我們的路由規則將是這樣的:當沒有選擇主題的情況下,沿用原來的路由規則,如果選擇了主題,則使用重寫後的路由規則。

新的路由規則:在選擇了主題的情況下,優先尋找thems/主題名稱/views/Areas/地區名稱/控制器名稱/視圖名稱.cshtml,如果找不到再按照預設的路由規則去尋找,也就是Areas/地區名稱/Views/控制器名稱/視圖名稱.cshtml

切換主題View代碼:


<p class="btn-group">     <button type="button" class="btn btn-circle btn-outline red dropdown-toggle" data-toggle="dropdown">      <i class="fa fa-plus"></i>       <span class="hidden-sm hidden-xs">切換主題 </span>       <i class="fa fa-angle-down"></i>     </button>     <ul class="dropdown-menu" role="menu">      <li>       <a href="javascript:setTheme('default')">        <i class="icon-docs"></i> 預設主題       </a>      </li>      <li>       <a href="javascript:setTheme('Blue')">        <i class="icon-tag"></i> 藍色主題       </a>      </li>     </ul>    </p>  <script type="text/javascript">   function setTheme(themeName)   {    window.location.href = "/Home/SetTheme?themeName=" + themeName + "&href=" + window.location.href;   }</script>

當使用者登入成功的時候,從Cookie中讀取所選主題資訊,當Cookie中沒有讀取到主題記錄時,則從Web.config設定檔中讀取配置的主題名稱,如果都沒有讀取到,則說明是預設主題,沿用原有的視圖引擎規則。

在後台管理介面,每次選擇了主題,我都將主題名稱儲存到Cookie中,預設儲存一年,這樣當下次再登入的時候,就能夠記住所選的主題資訊了。


using System;using System.Web.Mvc;using Secom.Emx.WebApp.Helper;using System.Web;using Secom.Emx.Common.Controllers;namespace Secom.Emx.WebApp.Controllers{ public class HomeController : BaseController {  string themeCookieName = "Theme";  public ActionResult Index()  {   ViewData["Menu"] = GetMenus();   return View();  }  public ActionResult SetTheme(string themeName,string href)  {   if (!string.IsNullOrEmpty(themeName))   {    Response.Cookies.Set(new HttpCookie(themeCookieName, themeName) { Expires = DateTime.Now.AddYears(1) });   }   else   {    themeName = Request.Cookies[themeCookieName].Value ?? "".Trim();   }   Utils.ResetRazorViewEngine(themeName);   return string.IsNullOrEmpty(href)? Redirect("~/Home/Index"):Redirect(href);  }  public ActionResult Login()  {   string themeName = Request.Cookies[themeCookieName].Value ?? "".Trim();   if (!string.IsNullOrEmpty(themeName))   {    Utils.ResetRazorViewEngine(themeName);   }   return View();  } }}

Utils類:


using System.Configuration;using System.Web.Mvc;namespace Secom.Emx.WebApp.Helper{ public class Utils {  private static string _themeName;  public static string ThemeName  {   get   {    if (!string.IsNullOrEmpty(_themeName))    {     return _themeName;    }    //模板風格    _themeName =string.IsNullOrEmpty(ConfigurationManager.AppSettings["Theme"])? "" : ConfigurationManager.AppSettings["Theme"];    return _themeName;   }  }  public static void ResetRazorViewEngine(string themeName)  {   themeName = string.IsNullOrEmpty(themeName) ? Utils.ThemeName : themeName;   if (!string.IsNullOrEmpty(themeName))   {    ViewEngines.Engines.Clear();    ViewEngines.Engines.Add(new CustomRazorViewEngine(themeName));   }  } }}

實現方式實在是太簡單,簡單得我不知道如何表述才好,我還是記下來,方便有需要的人可以查閱,希望可以幫到你們。由於項目引入了龐大的各種相關檔案以致檔案比較大,網速原因無法上傳源碼還望見諒!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.