虽然有很多前端模板库,但是前端模板都是后期再渲染呈现,而后端模板是在服务端渲染之前执行替换操作,可以避免页面闪屏,自定义的后端的方式,也更适合后端开发人员。
对于Asp.net Mvc, 后端html修改,可以在视图引擎里修改html,MVC默认视图引擎为RazorViewEngine, RazorViewEngine继承自基类BuildManagerViewEngine, 它有两个重载的函数CreatePartialView和CreateView:
#region 程序集 System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// D:\development\WebMvc\SecurityDemo\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll
#endregion
namespace System.Web.Mvc
{
//
// 摘要:
// 表示一个用于呈现使用 ASP.NET Razor 语法的网页的视图引擎。
public class RazorViewEngine : BuildManagerViewEngine
{
//
// 摘要:
// 初始化 System.Web.Mvc.RazorViewEngine 类的新实例。
public RazorViewEngine();
//
// 摘要:
// 使用视图页激活器初始化 System.Web.Mvc.RazorViewEngine 类的新实例。
//
// 参数:
// viewPageActivator:
// 视图页激活器。
public RazorViewEngine(IViewPageActivator viewPageActivator);
//
// 摘要:
// 使用指定的控制器上下文和分部路径创建分部视图。
//
// 参数:
// controllerContext:
// 控制器上下文。
//
// partialPath:
// 分部视图的路径。
//
// 返回结果:
// 分部视图。
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath);
//
// 摘要:
// 使用指定的控制器上下文以及视图和母版视图的路径来创建视图。
//
// 参数:
// controllerContext:
// 控制器上下文。
//
// viewPath:
// 视图的路径。
//
// masterPath:
// 母版视图的路径。
//
// 返回结果:
// 视图。
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath);
}
}
这两个函数返回对象类型都继承自IView接口,那我们分装一个类,只要继承自IView接口就可以,定义一个类RazorViewPlus(视图类)并继承自RazorView类(RazorView实际上也继承自IView接口,它是RazorViewEngine默认使用的类型,所以用它更好)。
RazorViewPlus.cs
using Microsoft.Ajax.Utilities;
using Microsoft.VisualBasic;
using RazorEnginePlus.Extend;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.UI;
namespace RazorEnginePlus
{
public class RazorViewPlus : RazorView
{
public RazorViewPlus(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable viewStartFileExtensions) : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions)
{
}
public RazorViewPlus(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable viewStartFileExtensions, IViewPageActivator viewPageActivator) : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, viewPageActivator)
{
}
protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
{
StringWriter stringWriter = new StringWriter();
HtmlTextWriter tw = new HtmlTextWriter(stringWriter);
base.RenderView(viewContext, tw, instance);
string html = stringWriter.ToString();
//模板替换
Regex regx = new Regex("[\\s\\S]*? ", RegexOptions.IgnoreCase);
MatchCollection matchList = regx.Matches(html); //这里已捕获到了
for (int i = 0; i < matchList.Count; i++) {
var ls_tmpl = matchList[i].Value;
if (!string.IsNullOrEmpty(ls_tmpl)) {
var ls_id = "";
Regex regxtmplid = new Regex("\\s+?id\\s*?=\\s*?\"\\s*?[\\S]+?\\s*?\"", RegexOptions.IgnoreCase);
MatchCollection matchTmplId = regxtmplid.Matches(ls_tmpl);
if (matchTmplId.Count > 0) {
ls_id = matchTmplId[0].Value;
if (!string.IsNullOrEmpty(ls_id)) {
ls_id = new Regex("[\\s\\S]*?\\s+?id\\s*?=\\s*?\"", RegexOptions.IgnoreCase).Replace(ls_id, "");
ls_id = ls_id.Replace(" ", "").Replace("\"", "");
}
//找到模板指定的区域
if (!string.IsNullOrEmpty(ls_id)) {
Regex regxPartial = new Regex("", RegexOptions.IgnoreCase);
MatchCollection matchScriptTmpl = regxPartial.Matches(html);
if (matchScriptTmpl.Count <= 0) {
regxPartial = new Regex("", RegexOptions.IgnoreCase);
matchScriptTmpl = regxPartial.Matches(html);
}
if (matchScriptTmpl.Count > 0) {
var ls_partial = matchScriptTmpl[0].Value;
Regex regxPartialRp1 = new Regex("", RegexOptions.IgnoreCase);
ls_partial = regxPartialRp1.Replace(ls_partial, "");
ls_partial = regxPartialRp2.Replace(ls_partial, "");
Regex regxTag = new Regex("[\\s\\S]*? ", RegexOptions.IgnoreCase);
html = regxTag.Replace(html, ls_partial);
}
}
}
}
}
//移除模板代码
Regex regTmplRemove1 = new Regex("", RegexOptions.IgnoreCase);
html = regTmplRemove1.Replace(html, "");
Regex regTmplRemove2 = new Regex("", RegexOptions.IgnoreCase);
html = regTmplRemove2.Replace(html, "");
//输出到页面
writer.Write(html);
}
}
}
视图类RazorViewPlus最终还是要用在视图引擎里,我们自定义一个EngineCore类并继承自RazorViewEngine类,重写CreateView方法,CreatePartialView是创建分部视图,一般没必要改,修改后的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace RazorEnginePlus
{
public class EngineCore : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return base.CreateView(controllerContext, partialPath, string.Empty);
}
///
/// 根据指定路径返回一个实现了 IView 接口的对象
///
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
//var physicalPath = controllerContext.HttpContext.Server.MapPath(viewPath);
//return new BaseView(physicalPath);
return new RazorViewPlus(controllerContext, viewPath, masterPath, true, base.FileExtensions, base.ViewPageActivator);
//return base.CreateView(controllerContext, viewPath, masterPath);
}
}
}
最后一步,使用我们重写的视图引擎,找到你的MVC项目更目录下的Global.asax文件,在Application_Start函数里面的最前面添加下面代码:
//移除默认视图引擎
var orgRazorEngine = ViewEngines.Engines.SingleOrDefault(ve => ve is RazorViewEngine);
if (orgRazorEngine != null)
{
ViewEngines.Engines.Remove(orgRazorEngine);
}
//也可以先清空引擎集合
//ViewEngines.Engines.Clear();
//添加自定义的视图引擎到引擎集合中
ViewEngines.Engines.Add(new EngineCore());
html页面代码:
最终输出到页面的html:
aaaa