ASP. net mvc rewrite RazorViewEngine to implement multi-topic switching, mvcrazorviewengine

Source: Internet
Author: User

ASP. net mvc rewrite RazorViewEngine to implement multi-topic switching, mvcrazorviewengine

There are two methods to switch themes in ASP. net mvc. One is to switch the css and js references of the skin, and the other is to rewrite the view engine. The method of rewriting the view engine is more flexible, because I can not only have different la S and styles under different themes, but also make the data entries displayed under different themes different, that is to say, you can add personalized things under certain themes.

In this article, I will rewrite the view engine for demonstration. Before that, I assume that you already have some MVC basics. Let's take a look at the effect:

After logging on to the system, it is the default topic. After we click to switch the topic, the layout of the left-side menu bar changes, the style of the right-side content also changes, and the address bar remains unchanged. Metronic used in the UI is charged on the official website, but it is always available for free in tianchao. Official Address: http://keenthemes.com/preview/metronic/

Here, I use the method of partitioning by region and by module (by independent business function). A module is an independent dll. Here, Secom. emx. admin and Secom. emx. history is two independent modules, and the region Admin and History are created respectively.

You will find that Secom. emx. the Areas directory and Secom. emx. the directories in the WebApp are exactly the same. In fact, I didn't want to add any View to the module project at first, but it was added to facilitate independent deployment.

Right-click Project Secom. Emx. Admin and choose "properties"> "generate event" to add the following code:

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

This command is very simple, in fact, when compiling the project Secom. Emx. Admin, copy the Views in the project to the specified directory of the Secom. Emx. WebApp project.

I placed the region configuration file to Secom. emx. in WebApp, you can actually put it in a class library project independently, because after registering a region route, the project will eventually find all the projects that inherit the AreaRegistration class under the bin directory, then let the WebApp reference this class library project, Secom. emx. add Secom to the WebApp project. emx. admin, Secom. emx. history reference.

The AdminAreaRegistration code is as follows:

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" }   );  } }}

Note the namespace and the namespaces: new string [1] {"Secom. emx. admin. areas. admin. controllers "}, the namespace is the independent module Secom. emx. the namespace of the Controller under Admin.

The HistoryAreaRegistration code is as follows:

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" }   );  } }}

Let's take a look at the original constructor of RazorViewEngine as follows:

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",   };  }

Create a new CustomRazorViewEngine that inherits from RazorViewEngine and overwrites the View routing rules. Since you can rewrite the routing rules, you can define any rules, then follow the rules you have defined. Pay attention to the order in the route array. When you look for a view, the view is searched in order. When you find the view, the view is returned immediately and will not match the subsequent routing rules. To improve routing search efficiency, I deleted all vbhtml routing rules here, because C # is used in my entire project.

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"};   }  } }}

After rewriting, our routing rules will be like this: if the topic is not selected, the original routing rules will be followed. If the topic is selected, the rewritten routing rules will be used.

New Routing rule: if a topic is selected, the thems/topic name/views/Areas/region name/controller name/view name is preferred. cshtml. If it cannot be found, search for it based on the default routing rules, that is, Areas/region name/Views/controller name/view name. cshtml

Code for switching the topic View:

<Div class = "btn-group"> <button type = "button" class = "btn-circle btn-outline red dropdown-toggle" data-toggle = "dropdown"> <I class = "fa-plus"> </I> <span class = "hidden-sm hidden-xs"> switch topic </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> default topic </a> </li> <a href =" javascript: setThe Me ('blue ') "> <I class =" icon-tag "> </I> blue topic </a> </li> </ul> </div> <script type =" text /javascript "> function setTheme (themeName) {window. location. href = "/Home/SetTheme? ThemeName = "+ themeName +" & href = "+ window. location. href ;}</script>

When the user logs on successfully, the selected topic information is read from the Cookie. When the Cookie does not read the topic record, the selected topic information is read from the Web. the name of the topic read from the config configuration file. If none of the topics are read, the default topic is used and the original view engine rules are used.

On the backend management interface, when a topic is selected, I store the topic name in the Cookie, Which is saved for one year by default, so that when I log on again next time, you can remember the selected topic information.

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 class:

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;} // template style _ themeName = string. IsNullOrEmpty (ConfigurationManager. receivettings ["Theme"])? "": ConfigurationManager. receivettings ["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 ));}}}}

The implementation method is too simple. It is as simple as I don't know how to express it. I will write it down so that people who need it can check it and hope it can help you. Due to the introduction of a large variety of related files in the project, the file size is relatively large, and the source code cannot be uploaded due to network speed. Sorry!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.