您现在的位置是:网站首页> 编程资料编程资料

ASP.NET MVC使用RazorEngine解析模板生成静态页_实用技巧_

2023-05-24 427人已围观

简介 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 { ///  /// 文章ID ///  public int Id { get; set; } ///  /// 文章标题 ///  public string Title { get; set; } ///  /// 文章内容 ///  public string Content { get; set; } ///  /// 作者 ///  public string Author { get; set; } ///  /// 发布时间 ///  public DateTime CreateDate { get; set; } }

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

@Model.Title

@Model.Title

作者:@Model.Author - 发布时间:@Model.CreateDate

@Raw(Model.Content)

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

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

 ///  /// 获取页面的Html代码 ///  /// 模板页面路径 /// 页面编码 ///  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); } ///  /// 获取页面的编码 ///  /// Html源码 ///  public System.Text.Encoding GetEncoding(string html) { string pattern = @"(?i)\bcharset=(?[-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静态页

 ///  /// 创建静态文件 ///  /// Html代码 /// 生成路径 ///  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静态页

 ///  /// 解析模板生成静态页 ///  /// 模板地址 /// 静态页地址 /// 数据模型 ///  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 { ///  /// 文章ID ///  public int Id { get; set; } ///  /// 文章标题 ///  public string Title { get; set; } ///  /// 文章内容 ///  public string Content { get; set; } ///  /// 作者 ///  public string Author { get; set; } ///  /// 发布时间 ///  public DateTime CreateDate { get; set; } }   public class Company { ///  /// 公司Id ///  public int Id { get; set; } ///  /// 公司名称 ///  public string CompanyName { get; set; } ///  /// 公司电话 ///  public string CompanyTel { get; set; } ///  /// 联系人 ///  public string ContectUser { get; set; } ///  /// 创建时间 ///  public DateTime CreateDate { get; set; } }   public class Column { ///  /// 栏目ID ///  public int Id { get; set; } ///  /// 栏目名称 ///  public string Title { get; set; } ///  /// 文章列表 ///  public virtual ICollection Articles { get; set; } }   public class TemplateView { ///  /// ID ///  public int Id { get; set; } ///  /// 标题 ///  public string Title { get; set; } ///  /// 内容 ///  public string Content { get; set; } ///  /// 作者 ///  public string Author { get; set; } ///  /// 时间 ///  public DateTime CreateDate { get; set; } ///  /// 公司名称 ///  public string CompanyName { get; set; } ///  /// 公司电话 ///  public string CompanyTel { get; set; } ///  /// 联系人 ///  public string ContectUser { get; set; } ///  /// 文章列表 ///  public virtual ICollection Articles { get; set; } } 

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

 ///  /// 基础操作接口 ///  ///  public interface IRepository where T : class { ///  /// 解析模板生成静态页 ///  /// 模板地址 /// 静态页地址 /// 数据模型 ///  bool CreateStaticPage(string temppath, string path, T t); ///  /// 获取页面的Html代码 ///  /// 模板页面路径 /// 页面编码 ///  string GetHtml(string url, System.Text.Encoding encoding); ///  /// 获取页面的编码 ///  /// Html源码 ///  System.Text.Encoding GetEncoding(string html); ///  /// 创建静态文件 ///  /// Html代码 /// 生成路径 ///  bool CreateFileHtmlByTemp(string result, string createpath); } ///  /// 基础接口实现类 ///  ///  public abstract class RepositoryBase : IRepository where T : class { ///  /// 解析模板生成静态页 ///  /// 模板地址 /// 静态页地址 /// 数据模型 ///  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就需要单独获取一下另一个数据模型里的 这个文章的内容 这种时候 我们可以在这里重新给他
                
                

-六神源码网