ASP.NET MVC重写RazorViewEngine实现多主题切换

2025-05-29 0 29

ASP.NET MVC中来实现主题的切换一般有两种方式,一种是通过切换皮肤的css和js引用,一种就是通过重写视图引擎。通过重写视图引擎的方式更加灵活,因为我不仅可以在不同主题下面布局和样式不一样,还可以让不同的主题下面显示的数据条目不一致,就是说可以在某些主题下面添加一下个性化的东西。

本篇我将通过重写视图引擎的方式来进行演示,在这之前,我假设你已经具备了MVC的一些基础,我们先来看下效果:

系统登录后是默认主题,当我们点击切换主题之后,左侧菜单栏的布局变了,右侧内容的样式也变了,而地址栏是不变的。界面UI用的metronic,虽然官网是收费的,但是在天朝,总是可以找到免费的。官方地址:http://keenthemes.com/preview/metronic/

ASP.NET MVC重写RazorViewEngine实现多主题切换

ASP.NET MVC重写RazorViewEngine实现多主题切换

在这里,我使用了分区域、分模块(按独立的业务功能划分)的方式,一个模块就是一个独立的dll,在这里Secom.Emx.Admin和Secom.Emx.History就是两个独立的模块,并分别创建了区域Admin和History。

ASP.NET MVC重写RazorViewEngine实现多主题切换

ASP.NET MVC重写RazorViewEngine实现多主题切换

你会发现Secom.Emx.Admin模型下面的Areas目录和Secom.Emx.WebApp中的目录是一模一样的,其实我最初不想在模块项目中添加任何的View,但是为了方便独立部署还是加了。

右键单击项目Secom.Emx.Admin,选择“属性”——“生成事件”添加如下代码:

?

1

2
xcopy /e/r/y $(ProjectDir)Areas\\Admin\\Views

$(SolutionDir)Secom.Emx.WebApp\\Areas\\Admin\\Views

这命令很简单,其实就是当编译项目Secom.Emx.Admin的时候,将项目中的Views复制到Secom.Emx.WebApp项目的指定目录下。

ASP.NET MVC重写RazorViewEngine实现多主题切换

区域配置文件我放置到了Secom.Emx.WebApp中,其实你完全可以独立放置到一个类库项目中,因为注册区域路由的后,项目最终会寻找bin目录下面所有继承了AreaRegistration类的,然后让WebApp引用这个类库项目,Secom.Emx.WebApp项目添加Secom.Emx.Admin、Secom.Emx.History的引用。

ASP.NET MVC重写RazorViewEngine实现多主题切换

AdminAreaRegistration代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25
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代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25
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的原始构造函数如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53
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#语言。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

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

}

}

}

}

ASP.NET MVC重写RazorViewEngine实现多主题切换

重写后,我们的路由规则将是这样的:当没有选择主题的情况下,沿用原来的路由规则,如果选择了主题,则使用重写后的路由规则。

新的路由规则:在选择了主题的情况下,优先查找thems/主题名称/views/Areas/区域名称/控制器名称/视图名称.cshtml,如果找不到再按照默认的路由规则去寻找,也就是Areas/区域名称/Views/控制器名称/视图名称.cshtml

ASP.NET MVC重写RazorViewEngine实现多主题切换

切换主题View代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25
<div 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>

</div>

<script type="text/javascript">

function setTheme(themeName)

{

window.location.href = "/Home/SetTheme?themeName=" + themeName + "&href=" + window.location.href;

}

</script>

当用户登录成功的时候,从Cookie中读取所选主题信息,当Cookie中没有读取到主题记录时,则从Web.config配置文件中读取配置的主题名称,如果都没有读取到,则说明是默认主题,沿用原有的视图引擎规则。

在后台管理界面,每次选择了主题,我都将主题名称存储到Cookie中,默认保存一年,这样当下次再登录的时候,就能够记住所选的主题信息了。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40
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类:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33
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));

}

}

}

}

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

原文链接:http://www.cnblogs.com/jiekzou/p/7084827.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 ASP.NET MVC重写RazorViewEngine实现多主题切换 https://www.kuaiidc.com/99257.html

相关文章

发表评论
暂无评论