转载

https://www.cnblogs.com/yuangang/p/5464758.html

简述

Razor是ASP.NET MVC 3中新加入的技术,以作为ASPX引擎的一个新的替代项。在早期的MVC版本中默认使用的是ASPX模板引擎,Razor在语法上的确不错,用起来非常方便,简洁的语法与.NET Framework 结合,广泛应用于ASP.NET MVC 项目。

我们在很多项目开发中会常常用到页面静态化,页面静态化有许多方式,最常见的就是类似很多PHP CMS种使用的 标签替换的方式(如:帝国CMS、EcShop等),还有很多都是伪静态,伪静态我们就不做过多解释,通过路由或Url重写来实现就可以了。Razor为我们提供了更加方便的模板解析方式,任何东西都是两方面的,技术也是如此,Razor解析模板虽然更加方便、简洁,但是对于模板制作人员来说也是有一定的技术要求,或者对于开发一套模板制作功能来说,考虑的要更多一些。我们不再去探究这些问题,我们更注重哪种技术更容易、更方便、更好的满足我们项目的需求。

如何使用RazorEngine

今天来简单介绍一下如何使用RazorEngine解析模板生成静态页面,RazorEngine它是基于微软的Razor之上,包装而成的一个可以独立使用的模板引擎。也就是说,保留了Razor的模板功能,但是使得Razor脱离于Asp.net MVC,能够在其它应用环境下使用,项目地址:https://github.com/Antaris/RazorEngine

首先我们去codeplex上下两个需要的dll http://razorengine.codeplex.com

看到网上很多介绍RazorEngine的基础用法的,讲解的都比较详细,对于RazorEngine运行原理很清晰,我们在这里就不重复介绍了。写这篇文章是对于很多新手同学来说比较喜欢“拿来主义”,基本的用法原理都能看懂,但是如何应用到项目中还是有些不是很清晰,我们只讲讲如何在项目中运用。

本文分为两部分:第一个部分,基本的单数据模型模板解析;第二部分,面向接口的多数据模型模板解析

第一个部分 基本的单数据模型模板解析

一、我们创建一个MVC项目,并且添加上面的两个DLL引用,然后我们新建一个简单的文章类

public class Articles{/// <summary>/// 文章ID /// </summary> public int Id { get; set; } /// <summary> /// 文章标题 /// </summary> public string Title { get; set; } /// <summary> /// 文章内容 /// </summary> public string Content { get; set; } /// <summary> /// 作者 /// </summary> public string Author { get; set; } /// <summary> /// 发布时间 /// </summary> public DateTime CreateDate { get; set; } }

二、我们新建一个Razor的Html模板

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>@Model.Title</title> </head> <body> <h1>@Model.Title</h1> <p>作者:@Model.Author - 发布时间:@Model.CreateDate</p> <p>@Raw(Model.Content)</p> </body> </html>

说明:Model就是我们的文章实体类  在MVC的试图页cshtml中 我们一般都是在控制器里传递这个实体类 然后在视图页中 @model Models.Articles 来接收这个实体类 然后通过“@Model.”来输出内容,在Razor模板中是一样的,只是不用@model Models.Articles 来接收了,其它的语法跟在.cshtml试图页中是一样的,这么说多余了,因为写法不一样他就不是Razor了

三、我们写一个方法来获取模板页的Html代码

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

四、我们写一个方法 用于生成Html静态页

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

五、我们来写个方法调用静态模板,并且传递数据模型实体类 创建Html静态页

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

好了,大功告成,是不是很简单。

这里只是一个很简单的应用,没有读取数据,也没有列表,只有一个文章数据模型,下一部分我们将介绍 多模型模板解析,因为是多模型 所以 生成静态页面的时候 就不是传递一个具体模型实体类 我们会用到 反射,通过反射模型属性 获取数据,有不熟悉反射的可以提前研究一下,也可以直接看下一部分的反射代码也很简单的。

第二部分 面向接口的多数据模型模板解析

这一部分,我们介绍使用接口来解析模板,包括列表等多种模型解析,用到了Spring注入和反射还有接口等,有不熟悉的可以百度搜一下或者评论留言。

我们接着上面的示例,我们新建两个类库 一个是存放数据模型的 我们叫Domain;另外一个是接口和实现类的 我们叫Service,然后我们添加他们之间的引用

一、我们在Domain下创建几个测试类

Articles - 文章测试类

Company - 公司测试类

Column - 栏目测试类

TemplateView - 模型解析类(这个是不是比较弱智?我也没深入研究多个模型怎么反射出来 所以 我加了这么个算是公用的类 没有对应的数据表 只是解析模板的时候 作为中间件用用)

   public class Articles{/// <summary>/// 文章ID /// </summary> public int Id { get; set; } /// <summary> /// 文章标题 /// </summary> public string Title { get; set; } /// <summary> /// 文章内容 /// </summary> public string Content { get; set; } /// <summary> /// 作者 /// </summary> public string Author { get; set; } /// <summary> /// 发布时间 /// </summary> public DateTime CreateDate { get; set; } }   public class Company { /// <summary> /// 公司Id /// </summary> public int Id { get; set; } /// <summary> /// 公司名称 /// </summary> public string CompanyName { get; set; } /// <summary> /// 公司电话 /// </summary> public string CompanyTel { get; set; } /// <summary> /// 联系人 /// </summary> public string ContectUser { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime CreateDate { get; set; } }   public class Column { /// <summary> /// 栏目ID /// </summary> public int Id { get; set; } /// <summary> /// 栏目名称 /// </summary> public string Title { get; set; } /// <summary> /// 文章列表 /// </summary> public virtual ICollection<Articles> Articles { get; set; } }   public class TemplateView { /// <summary> /// ID /// </summary> public int Id { get; set; } /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 内容 /// </summary> public string Content { get; set; } /// <summary> /// 作者 /// </summary> public string Author { get; set; } /// <summary> /// 时间 /// </summary> public DateTime CreateDate { get; set; } /// <summary> /// 公司名称 /// </summary> public string CompanyName { get; set; } /// <summary> /// 公司电话 /// </summary> public string CompanyTel { get; set; } /// <summary> /// 联系人 /// </summary> public string ContectUser { get; set; } /// <summary> /// 文章列表 /// </summary> public virtual ICollection<Articles> Articles { get; set; } }

二、我们在Service下创建一个基础操作接口以及其实现类(里面的很多方法 比如:获取页面的Html代码、获取页面的编码以及创建静态文件等 是没有必要写在接口的 这个可以写到公用的类库里,因为这里就用到这么几个方法 所以我没有加公用类库 就直接写在这里面了)

/// <summary>/// 基础操作接口/// </summary> /// <typeparam name="T"></typeparam> public interface IRepository<T> where T : class { /// <summary> /// 解析模板生成静态页 /// </summary> /// <param name="temppath">模板地址</param> /// <param name="path">静态页地址</param> /// <param name="t">数据模型</param> /// <returns></returns> bool CreateStaticPage(string temppath, string path, T t); /// <summary> /// 获取页面的Html代码 /// </summary> /// <param name="url">模板页面路径</param> /// <param name="encoding">页面编码</param> /// <returns></returns> string GetHtml(string url, System.Text.Encoding encoding); /// <summary> /// 获取页面的编码 /// </summary> /// <param name="html">Html源码</param> /// <returns></returns> System.Text.Encoding GetEncoding(string html); /// <summary> /// 创建静态文件 /// </summary> /// <param name="result">Html代码</param> /// <param name="createpath">生成路径</param> /// <returns></returns> bool CreateFileHtmlByTemp(string result, string createpath); } /// <summary> /// 基础接口实现类 /// </summary> /// <typeparam name="T"></typeparam> public abstract class RepositoryBase<T> : IRepository<T> where T : class { /// <summary> /// 解析模板生成静态页 /// </summary> /// <param name="temppath">模板地址</param> /// <param name="path">静态页地址</param> /// <param name="t">数据模型</param> /// <returns></returns> public bool CreateStaticPage(string temppath, string path, T t) { try { //实例化模型 var Entity = new Domain.TemplateView(); //获取模板Html string TemplateContent = GetHtml(temppath, System.Text.Encoding.UTF8); //初始化结果 string result = ""; //反射赋值 Type typeT = t.GetType(); Type typeEn = Entity.GetType(); System.Reflection.PropertyInfo[] propertyinfosT = typeT.GetProperties(); foreach (System.Reflection.PropertyInfo propertyinfoT in propertyinfosT) { System.Reflection.PropertyInfo propertyinfoEn = typeEn.GetProperty(propertyinfoT.Name); if (propertyinfoEn != null && propertyinfoT.GetValue(t, null) != null) { propertyinfoEn.SetValue(Entity, propertyinfoT.GetValue(t, null), null); } } //很多时候 我们并没有创建复杂的主外键关系 例如栏目下的文章 我们仅仅是在文章表中添加了一个所属栏目ID的字段 //并没有创建关联 这种情况下 我们直接获取栏目的时候 是获取不到文章列表的 //包括很多自定义的模型和字段 比如 文章的内容 可能不跟文章一个表 而是一个单独的大数据字段表 这种情况下 我们的 //TemplateView.Content就需要单独获取一下另一个数据模型里的 这个文章的内容 这种时候 我们可以在这里重新给他赋值 //如 传入的模型是 文章 //if(t is Domain.Articles) //{ // Entity.Content= 查询大数据字段表中这篇文章的内容; //}  result = Razor.Parse(TemplateContent, Entity); return CreateFileHtmlByTemp(result, path); } catch (Exception e) { throw e; } } /// <summary> /// 获取页面的Html代码 /// </summary> /// <param name="url">模板页面路径</param> /// <param name="encoding">页面编码</param> /// <returns></returns> public string GetHtml(string url, System.Text.Encoding encoding) { byte[] buf = new WebClient().DownloadData(url); if (encoding != null) return encoding.GetString(buf); string html = System.Text.Encoding.UTF8.GetString(buf); encoding = GetEncoding(html); if (encoding == null || encoding == System.Text.Encoding.UTF8) return html; return encoding.GetString(buf); } /// <summary> /// 获取页面的编码 /// </summary> /// <param name="html">Html源码</param> /// <returns></returns> public System.Text.Encoding GetEncoding(string html) { string pattern = @"(?i)\bcharset=(?<charset>[-a-zA-Z_0-9]+)"; string charset = Regex.Match(html, pattern).Groups["charset"].Value; try { return System.Text.Encoding.GetEncoding(charset); } catch (ArgumentException) { return null; } } /// <summary> /// 创建静态文件 /// </summary> /// <param name="result">Html代码</param> /// <param name="createpath">生成路径</param> /// <returns></returns> public bool CreateFileHtmlByTemp(string result, string createpath) { if (!string.IsNullOrEmpty(result)) { if (string.IsNullOrEmpty(createpath)) { createpath = "/default.html"; } string filepath = createpath.Substring(createpath.LastIndexOf(@"\")); createpath = createpath.Substring(0, createpath.LastIndexOf(@"\")); if (!Directory.Exists(createpath)) { Directory.CreateDirectory(createpath); } createpath = createpath + filepath; try { FileStream fs2 = new FileStream(createpath, FileMode.Create); StreamWriter sw = new StreamWriter(fs2, new System.Text.UTF8Encoding(false));//去除UTF-8 BOM sw.Write(result); sw.Close(); fs2.Close(); fs2.Dispose(); return true; } catch { return false; } } return false; } }

三、我们分别创建 文章管理、公司管理、栏目管理的接口和实现类 并且他们都集成基础操作

   /// <summary>/// 文章管理/// </summary>   public interface IArticleManage:IRepository<Domain.Articles> { } public class ArticleManage:RepositoryBase<Domain.Articles>,IArticleManage { }   /// <summary> /// 公司管理 /// </summary> public interface ICompanyManage:IRepository<Domain.Company> { }   public class CompanyManage:RepositoryBase<Domain.Company>,ICompanyManage { }   //栏目管理 public interface IColumnManage:IRepository<Domain.Column> { }   public class ColumnManage:RepositoryBase<Domain.Column>,IColumnManage { }

四、注入Xml

<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net"> <description>Spring注入Service,容器指向本层层封装的接口</description> <object id="Service.ArticleManage" type="Service.ArticleManage,Service" singleton="false"> </object> <object id="Service.ColumnManage" type="Service.ColumnManage,Service" singleton="false"> </object> <object id="Service.CompanyManage" type="Service.CompanyManage,Service" singleton="false"> </object> </objects>

五、我们分别初始化一个文章类、一个公司类(没有管理数据表,它下面没有文章列表 栏目模型我就不初始化了,怎么输出列表 大家可以参考下 栏目模板)

    public class HomeController : Controller{/// <summary>/// 声明一下注入接口 /// </summary> public IArticleManage ArticleManage = Spring.Context.Support.ContextRegistry.GetContext().GetObject("Service.ArticleManage") as IArticleManage; public ICompanyManage CompanyManage = Spring.Context.Support.ContextRegistry.GetContext().GetObject("Service.CompanyManage") as ICompanyManage; public IColumnManage ColumnManage = Spring.Context.Support.ContextRegistry.GetContext().GetObject("Service.ColumnManage") as IColumnManage; public ActionResult Index() { //初始化一个文章数据模型 var entityArticle = new Domain.Articles() { Id = 1, Title = "这里是文章标题", Content = "<span style=\"color:red;\">这里是文章内容</span>", Author = "张三", CreateDate = DateTime.Now }; //初始化一个公司数据模型 var entityCompany = new Domain.Company() { Id = 1, CompanyName = "这里是公司名称", CompanyTel = "公司电话", ContectUser = "张三", CreateDate = DateTime.Now }; //调用方法生成静态页面 ArticleManage.CreateStaticPage(Server.MapPath("/Templates/Temp_article.html"), Server.MapPath("/Pages/news/" + DateTime.Now.ToString("yyyyMMddHHmmss") + "1.html"), entityArticle); CompanyManage.CreateStaticPage(Server.MapPath("/Templates/Temp_company.html"), Server.MapPath("/Pages/news/" + DateTime.Now.ToString("yyyyMMddHHmmss") + "2.html"), entityCompany); return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } }

六、这是测试的简单的文章模板、公司模板和栏目模板

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>@Model.Title</title> </head> <body> <h1>@Model.Title</h1> <p>作者:@Model.Author - 发布时间:@Model.CreateDate</p> <p>@Raw(Model.Content)</p> </body> </html>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <p>公司名称:@Model.CompanyName</p> <p>公司电话:@Model.CompanyTel</p> <p>联系人:@Model.ContectUser</p> <p>创建时间:@Model.CreateDate</p> </body> </html>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <p>栏目标题: @Model.Title</p> <p> 文章列表 <ul> @foreach(var item in @Model.Articles) { <li> <a href=""> <span>@item.Title</span> <span>@item.Author</span> <span>@item.CreateDate</span> </a> </li> } </ul> </p> </body> </html>

我们运行一下,大功告成~~~

         

怎么排序?怎么获取前几条?怎么格式化日期时间?怎么分页?

这可是Razor啊,这都不需要再多讲了吧,简单一说,如果你传入数据前没有事先排序或者获取前几条,这些操作要做模板里操作 那跟在.cshtml里基本是一样的

@foreach(var item in @Model.ListColumn)
{<div >
@if (@item.LinkUrl==null) { <ul> @foreach(var article in @item.COM_ARTICLE.Take(15).OrderByDescending(p=>p.UpDateDate)) { <li> <a href="@article.LinkUrl" class="gd-a"> <div>@article.Title</div></a> </li> } </ul> } else { } </div> }

应用还是很广泛的,而且解析代码相对于标签替换来说十分简洁、高效。有时间可以多研究研究,改天有空写一个模板替换标签的供大家参考一下。有人会说那我还得教前台制作Razor语法,这种说法我们没法去置评,标签替换你仍然要教他如何使用标签啊,所以是不是复杂并不是探究的主题,想要前台制作人员更方便的制作一套模板语法并不是主要因素,比如我们可以做一套方便的模板制作,用户点击一下就生成代码,或者直接做成可视化的,这可能让我们的程序员要耗费更多的精力,但是一劳永逸,标签替换方式你仍然要给前台制作人员一套标签规范和语法,况且后台解析异常的庞大和复杂。

转载于:https://www.cnblogs.com/mrray/p/9139536.html

ASP.NET MVC 解析模板生成静态页一(RazorEngine)相关推荐

  1. ASP非模板生成静态页

    首先我们要创建一个数据库表news包括字段 id   title     contect     date  接着我们设置一个ASP数据显示页shownew.asp 代码如下: <%@codep ...

  2. 详谈asp生成静态页方法

    生成静态页的好处不用说,当今大型网站,为缓解服务器端的压力许的的页面都改用了静态的页面,并利用AJAX技术动态地更新其中的部分内容,如广告等. 一个简单的不用模板可以直接生成HTML静态页的方法. 如 ...

  3. Asp.net 2.0 中将网站首页生成静态页的一个比较好的方法

    做网站时,有时为了提高性能会将网站首页生成静态页(当然, Asp.net中页面缓存也是一个不错的选择了 将页面生成静态的方法有多中,据不完全统计有N种(N>1) 呵呵 以下的方法来自 " ...

  4. mvc分页生成静态页,mvc生成静态页

    http://blog.csdn.net/xxj_jing/article/details/7899125 分页生成静态页 http://www.cnblogs.com/luanyilin/archi ...

  5. 用Response.Filter生成静态页

    我原来写的利用UrlRewrite,asp.net动态生成htm页面(补充说明2) ,生成静态页面时,使用下边的代码 Code using System; using System.IO; using ...

  6. 利用smarty生成静态页的关键代码

    smarty中有一个获取模板页内容方法fetch(), 它的声明原形是这样的: <?php function fetch( $resource_name, $cache_id=null, $co ...

  7. Smarty 生成静态页

    1.smarty配置文件:(直接继承smarty类) <?php require('/libs/Smarty.class.php'); class SmartyMistake extends S ...

  8. html手机pc不同页面,PC端和手机端如何同时生成静态页

    静态页是和图片类似的静态资源,访问静态资源不会经过程序处理,不会根据浏览器返回不同页面.要同时支持PC端和手机端浏览器,且要生成静态页时,最好使用bootstrap之类的技术,实现自适应页面设计. 如 ...

  9. php读取模板生成静态功能,php 生成静态页面的办法与实现代码详细版

    php中主要用到的就是要用到fread()和fwirte().而静态页面生成了之后,就会牵扯到修改的问题.这里可以用到正则匹配的方法来替换模版中改变的部位.不过此种方法太麻烦,值得推荐的方法是直接把原 ...

  10. 织梦列表页生成的html在哪里,织梦系统给手机版生成静态页HTML的方法

    原标题:织梦系统给手机版生成静态页HTML的方法 织梦dedecms默认的手机端不能生成静态,对于使用静态的网站来说多少有些不方便,其实dedecms可以通过一种另类的方法来给手机端生成静态页面的. ...

最新文章

  1. Informatica在linux下安装搭建
  2. c调用python打包_如何将C++的API封装成python可调用形式?
  3. HTML Help Workshop制作chm帮助文件和在应用程序中的调用
  4. Python之socketserver模块和验证客户端链接的合法性
  5. Java jdk中的部分工具javac javaw javaws javadoc javah javap jar jdb jps的作用
  6. @bean注解和@component注解的区别_通过源码查看 @Component,@Service 等注解是如何被解析的...
  7. stm32f407wet6安装linux,elua移植到STM32F407VET6流程
  8. 《An Introduction to Ray Tracing》—— 2.5 Ray/Quadric Intersection And Mapping
  9. 用户,用户组,文件和目录权限详解
  10. Dynamic CRM2013安装系列三、SQL及CRM2013安装
  11. R-CNN学习笔记1:Selective Search for Object Recognition
  12. python正则表达式模块re
  13. AHP权重计算方法案例
  14. 从美国人工智能年会看2017世界人工智能最新研究成果
  15. 无刷直流电机换相原理
  16. C++面向对象程序设计(侯捷)笔记
  17. 循环彩灯c语言程序,PLC彩灯实例,一个简单的顺序控制
  18. 关于勒索病毒 Ransom:Win32.WannaCrypt 解决方案的最后一次说明
  19. 微信小程序毕业设计开题报告医院预约挂号小程序+后台管理系统|前后分离VUE.js
  20. 哔哩哔哩前端笔试(卷1)

热门文章

  1. Servlet3.0 jsp跳转到Servlet 出现404错误的路径设置方法
  2. Android项目开发填坑记-so文件引发的攻坚战
  3. 详解C#自动注册Dll(OCX)控件的两种方法(转)
  4. 【Sniffer】如何查看Sniffer截获的数据内容
  5. Datagridview中的数据很多,加载完数据后滚动条自动到最下边,如何解决?
  6. 几句话介绍MagicAjax
  7. firefly 环境配置所需工具
  8. flash cs4中3D特性之PerspectiveProjection属性设置
  9. MAVEN(一)中的Scope
  10. SqlServer根据表中ID加序号