宝哥软件园

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

编辑:宝哥软件园 来源:互联网 时间:2021-09-04

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

在本文中,我将通过重写视图引擎来演示。在此之前,我假设你已经有了一些MVC的基础。我们先来看看效果:

系统登录后,是默认主题。当我们点击切换主题时,左侧菜单栏的布局会改变,右侧内容的样式会改变,地址栏保持不变。Metronic用于用户界面。虽然是在官网收费,但在国内总能免费找到。官方地址:http://keenthemes.com/preview/metronic/

在这里,我使用了划分区域和模块的方法(根据独立的业务功能)。一个模块是一个独立的dll。给你,赛康。Emx.Admin和Secom。Emx.History是两个独立的模块,分别创建了区域Admin和History。

你会发现Secom下的区域目录。Emx.Admin模型与Secom中的目录完全相同。实际上,我一开始并不想在模块项目中添加任何视图,但是我添加它们是为了方便独立部署。

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

Xcopy/e/r/y $ (projectdir)区域 admin view $(solutiondir)Secom。这个命令非常简单。其实在编译Secom项目的时候。Emx.Admin,项目中的视图被复制到secom.emx.webapp。

我把区域配置文件放在Secom.Emx.WebApp中,其实可以独立放在一个类库项目中,因为注册区域路由后,项目最终会找到bin目录下继承AreaRegistration类的所有区域,然后让WebApp引用这个类库项目,并添加Secom的引用。Emx.Admin和Secom。secom.emx.webapp项目的历史。

管理区域注册码如下:

使用系统。Web . Mvc命名空间Secom。emx . Webapp { public class AdminAreRegistration : area Registration { public override string area name { get { return ' Admin };} } public override void registerearea(areregistrationcontext){ context。MapRoute('Admin_default ',' Admin/{ controller }/{ action }/{ id } ',new { action='Index ',id=UrlParameter。可选},名称空间:新字符串[1] { 'Secom。emx . admin . areas . admin . controller ' });}}}请注意命名空间和命名空间:newstring [1] {'Secom。emx . admin . areas . admin . controllers ' }稍后添加,这是独立模块secom.emx.admin下的控制器所在的命名空间。

历史注册代码如下:

使用系统。Web . Mvc命名空间Secom。Emx.WebApp{公共类历史记录注册:区域注册{公共覆盖字符串区域名称{ get { return ' History} } public override void registerearea(areregistrationcontext){ context。MapRoute('History_default ',' History/{ controller }/{ action }/{ id } ',new { action='Index ',id=UrlParameter。可选},名称空间:新字符串[1] { 'Secom。emx . history . areas . history . controller ' });}}}我们先来看看RazorViewEngine的原始构造函数,如下所示:

public razorfiewengine(IViewPageActivator): base(viewPageActivator){ AreaViewLocationFormats=new[]{ ' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .vbhtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .vbhtml ' };aremasterlocationformats=new[]{ ' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .vbhtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .vbhtml ' };arepartialviewlocationformats=new[]{ ' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .vbhtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .vbhtml ' };view location formats=new[]{ ' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .vbhtml ',' ~/view/Shared/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .vbhtml ' };MasterLocationFormats=new[]{ ' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .vbhtml ',' ~/view/Shared/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .vbhtml ' };partial view plocationformats=new[]{ ' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .vbhtml ',' ~/view/Shared/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .vbhtml ' };FileExtensions=new[] { 'cshtml ',' vbhtml ',};}然后新建CustomRazorViewEngine继承自RazorViewEngine,对视角的路由规则进行了重写,既然可以重写路由规则,那意味着,你可以任意定义规则,然后遵守自己定义的规则就可以了。需要注意的是,要注意路由数组中的顺序,查找视图时,是按照前后顺序依次查找的,当找到了视图就立即返回,不会再去匹配后面的路由规则。为了提升路由查找效率,我这里删除了所有vbhtml的路由规则,因为我整个项目中都采用C#语言。

使用系统网络。手动音量调节命名空间Secom .emx。webapp。helper { public class customrazoreviewengine : razoreviewengine { public customrazoreviewengine(字符串主题){ if(!字符串IsNullOrEmpty(主题)){ areviewplocationformats=new[]{//themes ' ~/themes/' theme '/view/Areas/{ 2 }/{ 1 }/{ 0 } .cshtml ',' ~/themes/' theme/' Shared/{ 0 } .“~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ' };aremasterlocationformats=new[]{//themes ' ~/themes/' theme '/view/Areas/{ 2 }/{ 1 }/{ 0 } .cshtml ',' ~/themes/' theme '/view/Areas/{ 2 }/Shared/{ 0 } .cshtml ',' ~/themes/' theme '/view/Shared/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ' };arepartialviewlocationformats=new[]{//themes ' ~/themes/' theme '/view/Shared/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/{ 1 }/{ 0 } .cshtml ',' ~/Areas/{ 2 }/view/Shared/{ 0 } .cshtml ' };view locationformats=new[]{//themes ' ~/themes/' theme '/view/{ 1 }/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .cshtml ' };MasterLocationFormats=new[]{//themes ' ~/themes/' theme '/view/Shared/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .cshtml ' };partial view plocationformats=new[]{//themes ' ~/themes/' theme '/view/Shared/{ 0 } .cshtml ',' ~/view/{ 1 }/{ 0 } .cshtml ',' ~/view/Shared/{ 0 } .cshtml ' };文件扩展名=new[]{ ' cshtml ' };} } } } }

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

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

切换主题视角代码:

div=' BTN-组'按钮类型='按钮'按钮=' BTN BTN-圆圈BTN-轮廓红色下拉-切换'数据-切换='下拉' I class=' fa-plus '/I span class=' hidden-sm hidden-xs '切换主题/span I class=' fa fa-角度向下'/I/按钮ul class='下拉菜单'角色='菜单'阿利href=' javascript:setTheme血红素血红素('默认)“i class=”图标-文档/i默认主题/a /li阿利蓝色主题/a /li /ul /div脚本类型='text/javascript '函数设置主题(主题名称){ window。位置。href='/Home/set血红素?主题名称='主题名称href='窗口。位置。href}/脚本当用户登录成功的时候,从饼干中读取所选主题信息,当饼干中没有读取到主题记录时,则从Web.config配置文件中读取配置的主题名称,如果都没有读取到,则说明是默认主题,沿用原有的视图引擎规则。

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

使用系统;使用系统网络。手动音量调节使用Secom .Emx。WebApp。助手使用系统网络.使用Secom .通用控制器;命名空间Secom .Emx。控制器公共类HomeController :基本控制器{ string themeCookieName=' Theme ';公共操作结果Index(){查看数据[' Menu ']=GetMenus();返回视图();}公共操作结果设置主题(字符串主题名称,字符串href) { if(!字符串IsNullOrEmpty(主题名称)){回应.饼干。设置(新的HttpCookie(主题名称,主题名称){过期时间=日期时间.现在。AddYears(1)});} else {主题名称=请求饼干.主题菜单名称]。价值?''.trim();} Utils .ResetRazorViewEngine(主题名称);返回字符串IsNullOrEmpty(href)?重定向(' ~/主页/索引'):重定向(href);}公共操作结果登录(){字符串主题名称=请求饼干.主题菜单名称]。价值?''.trim();if(!字符串IsNullOrEmpty(主题名称)){ Utils .ResetRazorViewEngine(主题名称);}返回视图();} }}Utils类:

使用系统。配置;使用系统网络。手动音量调节命名空间Secom .Emx。网络应用助手公共类Utils {私有静态字符串_主题名;公共静态字符串主题名称{ get { if(!字符串IsNullOrEmpty(_主题名称)){ return _主题名称;} //模板风格_主题名称=字符串IsNullOrEmpty(配置管理器AppSettings['Theme'])?' :配置管理器AppSettings['主题'];返回_主题名;} } public static void ResetRazorViewEngine(字符串主题名){主题名=字符串.IsNullOrEmpty(主题名)?Utils .主题名称:主题名称;if(!字符串IsNullOrEmpty(主题名称)){视图引擎.引擎。清除();视图引擎。引擎。添加(新的自定义视图引擎(主题名称));} } }}实现方式实在是太简单,简单得我不知道如何表述才好,我还是记下来,方便有需要的人可以查阅,希望可以帮到你们。由于项目引入了庞大的各种相关文件以致文件比较大,网速原因无法上传源码还望见谅!

更多资讯
游戏推荐
更多+