0

0

ASP.NET MVC重写的实例教程

零下一度

零下一度

发布时间:2017-07-02 10:35:07

|

2237人浏览过

|

来源于php中文网

原创

这篇文章主要为大家详细介绍了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代码如下:

开源淘宝客淘货网
开源淘宝客淘货网

淘宝客开源程序-淘货网最新TopAPI淘宝客网站 淘打折淘客程序、免维护、伪静态、带缓存本程序采用asp.net 2.0进行开发,全自动应用最新淘客api,自动采集信息,无需手工更新,全站基本免维护,坐等收钱。(只需要第一次配置一下基本信息即可,无需替换,无后门)。 以下提供的演示地址和参考地址链接均需复制后粘贴在浏览器地址栏打开。 1、支持URL伪静态,全站全部实现伪静态重写,超强的SEO效

下载


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代码:


用户登录成功的时候,从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));
   }
  }
 }
}

实现方式实在是太简单,简单得我不知道如何表述才好,我还是记下来,方便有需要的人可以查阅,希望可以帮到你们。由于项目引入了庞大的各种相关文件以致文件比较大,网速原因无法上传源码还望见谅!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

2

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

2

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

0

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

0

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

25

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

622

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
ASP.NET参考手册
ASP.NET参考手册

共0课时 | 0人学习

传播智客ASP.NET中级系列视频教程
传播智客ASP.NET中级系列视频教程

共33课时 | 6.4万人学习

传播智客ASP.NET高级系列视频教程
传播智客ASP.NET高级系列视频教程

共34课时 | 6.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号