• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    ASP.NET MVC使用RazorEngine解析模板生成静态页

    简述

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

     /// 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; }
     }
    
    

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

    /// 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;
     }
    

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

    /// summary>
     /// 解析模板生成静态页
     /// /summary>
     /// param name="temppath">模板地址/param>
     /// param name="path">静态页地址/param>
     /// param name="t">数据模型/param>
     /// returns>/returns>
     public bool CreateStaticPage(string temppath, string path, RazorEngineTemplates.Models.Articles t)
     {
      try
      {
      //获取模板Html
      string TemplateContent = GetHtml(temppath, System.Text.Encoding.UTF8);
    
      //初始化结果
      string result = string.Empty;
    
      //解析模板生成静态页Html代码
      result = Razor.Parse(TemplateContent, t);
    
      //创建静态文件
      return CreateFileHtmlByTemp(result, path);
      }
      catch (Exception e)
      {
      throw e;
      }
     }
    
    

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

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

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

    这一部分,我们介绍使用接口来解析模板,包括列表等多种模型解析,用到了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 ICollectionArticles> 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 ICollectionArticles> Articles { get; set; }
     }
    
    

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

    /// summary>
     /// 基础操作接口
     /// /summary>
     /// typeparam name="T">/typeparam>
     public interface IRepositoryT> 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 RepositoryBaseT> : IRepositoryT> 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:IRepositoryDomain.Articles>
     {
     }
     public class ArticleManage:RepositoryBaseDomain.Articles>,IArticleManage
     {
     }
    
      /// summary>
     /// 公司管理
     /// /summary>
     public interface ICompanyManage:IRepositoryDomain.Company>
     {
     }
      public class CompanyManage:RepositoryBaseDomain.Company>,ICompanyManage
     {
     }
    
      //栏目管理
     public interface IColumnManage:IRepositoryDomain.Column>
     {
     }
      public class ColumnManage:RepositoryBaseDomain.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>
    }
    
    

    应用还是很广泛的,而且解析代码相对于标签替换来说十分简洁、高效。有时间可以多研究研究,改天有空写一个模板替换标签的供大家参考一下。

    还是那句老话,这篇文章仅仅是个人的一些理解和实现,可能中间会出现一些不合理的地方或是错误,请大家指正,我们共同学习研究。
    以上就是本文的全部内容,希望大家喜欢。
    原文地址:http://yuangang.cnblogs.com

    您可能感兴趣的文章:
    • 详解ASP.NET Razor 语法
    • ASP.NET MVC重写RazorViewEngine实现多主题切换
    • 详解ASP.NET MVC 利用Razor引擎生成静态页
    • ASP.NET MVC4 Razor模板简易分页效果
    • ASP.NET Razor模板引擎中输出Html的两种方式
    • asp.net模板引擎Razor调用外部方法用法实例
    • asp.net模板引擎Razor中cacheName的问题分析
    • 使用Asp.net Mvc3 Razor视图方式扩展JQuery UI Widgets方法介绍
    • 详细分析ASP.NET Razor之C# 变量
    上一篇:在ASP.NET 2.0中操作数据之十三:在DetailsView控件中使用TemplateField
    下一篇:在ASP.NET 2.0中操作数据之十四:使用FormView 的模板
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    ASP.NET MVC使用RazorEngine解析模板生成静态页 ASP.NET,MVC,使用,RazorEngine,