DotLiquid模板引擎简介
DotLiquid是一个在.Net Framework上运行的模板引擎,采用Ruby的Liquid语法,这个语法广泛的用在Ruby on rails和Django等网页框架中。
DotLiquid相比于Mvc默认模板引擎Razor的好处有:
- 因为不需要编译到程序集再载入
- 首次渲染速度很快
- 不会导致内存泄漏
- 可以在任何地方使用
- 不需要先准备WebViewPage,ViewContext等复杂的上下文对象
DotLiquid的官网是http://dotliquidmarkup.org/,开源协议是非常宽松的MS-PL。
示例代码
我创建一个使用了DotLiquid的示例Mvc项目,完整代码可以查看这里。
以下的示例将以Mvc中的Action为单位,都存放在HomeController下。
最基础的使用
Template.Parse可以把字符串解析为模板对象,再使用Render把模板对象渲染为字符串。
打开页面可以看见Hello, World!。
public ActionResult HelloWorld()
{
var template = Template.Parse("Hello, {{ name }}!");
var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));
return Content(result);
}
使用过滤器
在|后面的就是过滤器,过滤器可以连锁起来使用。
escape过滤器用于做html编码,避免name中的"<"当成是html标签描画。
upcase过滤器把字符串中的字母全部转换为大写。
打开页面可以看见Hello, <WORLD>!。
public ActionResult HelloFilter()
{
var template = Template.Parse("Hello, {{ name | escape | upcase }}!");
var result = template.Render(Hash.FromAnonymousObject(new { name = "<World>" }));
return Content(result);
}
定义过滤器
DotLiquid支持自定义过滤器,首先需要一个过滤器类型,其中的函数名称就是过滤器名称。
过滤器支持多个参数和默认参数。
public class DotliquidCustomFilter
{
public static string Substr(string value, int startIndex, int length = -1)
{
if (length >= 0)
return value.Substring(startIndex, length);
return value.Substring(startIndex);
}
}
在网站启动的时候把这个过滤器注册到DotLiquid
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// 在原有的代码下添加
Template.RegisterFilter(typeof(DotliquidCustomFilter));
}
}
这个例子会显示Hello, orl!
public ActionResult CustomFilter()
{
var template = Template.Parse("Hello, {{ name | substr: 1, 3 }}!");
var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));
return Content(result);
}
使用标签
DotLiquid中有两种标签,一种是普通标签(Block),一种是自闭合标签(Tag)。
这里的assign是自闭合标签,if是普通标签,普通标签需要用end+标签名闭合。
显示内容是Hello, World!
public ActionResult HelloTag()
{
var template = Template.Parse(@"
{% assign name = 'World' %}
{% if visible %}
Hello, {{ name }}!
{% endif %}
");
var result = template.Render(Hash.FromAnonymousObject(new { visible = true }));
return Content(result);
}
自定义标签
这里我将定义一个自闭合标签conditional,这个标签有三个参数,如果第一个参数成立则描画第二个否则描画第三个参数。
public class ConditionalTag : Tag
{
public string ConditionExpression { get; set; }
public string TrueExpression { get; set; }
public string FalseExpression { get; set; }
public override void Initialize(string tagName, string markup, List<string> tokens)
{
base.Initialize(tagName, markup, tokens);
var expressions = markup.Trim().Split(' ');
ConditionExpression = expressions[0];
TrueExpression = expressions[1];
FalseExpression = expressions.Length >= 3 ? expressions[2] : "";
}
public override void Render(Context context, TextWriter result)
{
var condition = context[ConditionExpression];
if (!(condition == null || condition.Equals(false) || condition.Equals("")))
result.Write(context[TrueExpression]);
else
result.Write(context[FalseExpression]);
}
}
在网站启动时把这个标签注册到DotLiquid
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// 在原有的代码下添加
Template.RegisterTag<ConditionalTag>("conditional");
}
}
这个例子会显示Bar
public ActionResult CustomTag()
{
var template = Template.Parse("{% conditional cond foo bar %}");
var result = template.Render(Hash.FromAnonymousObject(new { cond = false, foo = "Foo", bar = "Bar" }));
return Content(result);
}
模板文件
DotLiquid也支持从文件读取模板,需要先定义一个TemplateFileSystem。
public class DotliquidTemplateFileSystem : IFileSystem
{
public string ReadTemplateFile(Context context, string templateName)
{
var path = context[templateName] as string;
if (string.IsNullOrEmpty(path))
return path;
var fullPath = HttpContext.Current.Server.MapPath(path);
return File.ReadAllText(fullPath);
}
}
设置DotLiquid使用自定义的文件系统
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// 在原有的代码下添加
Template.FileSystem = new DotliquidTemplateFileSystem();
}
}
再定义一个控制器基类
public abstract class DotliquidController : Controller
{
public ContentResult DotliquidView(string path = null, object parameters = null)
{
// 路径为空时根据当前的Action决定
if (string.IsNullOrEmpty(path))
{
var controller = RouteData.Values["controller"];
var action = RouteData.Values["action"];
path = $"~/DotliquidViews/{controller}/{action}.html";
}
// 根据路径读取模板内容
var templateStr = Template.FileSystem.ReadTemplateFile(new Context(), "'" + path + "'");
// 解析模板,这里可以缓存Parse出来的对象,但是为了简单这里就略去了
var template = Template.Parse(templateStr);
// 描画模板
Hash templateParameters;
if (parameters is IDictionary<string, object>)
templateParameters = Hash.FromDictionary((IDictionary<string, object>)parameters);
else
templateParameters = Hash.FromAnonymousObject(parameters ?? new { });
var result = template.Render(templateParameters);
// 返回描画出来的内容
return Content(result, "text/html");
}
}
现在可以在控制器中使用基于DotLiquid的模板了
public ActionResult HelloTemplateFile()
{
return DotliquidView();
}
上面会返回文件~/DotliquidViews/Home/HelloTemplateFile.html的内容
Hello, Template!
嵌入子模板
为了实现代码的重用,DotLiquid的模板还可以嵌入其他子模板,嵌入需要使用include标签。
以下例子会显示Hello, Include!
public ActionResult HelloInclude()
{
return DotliquidView();
}
文件~/DotliquidViews/Home/HelloInclude.html的内容
Hello, {% include "~/DotliquidViews/Home/HelloIncludeContents.html" %}!
文件~/DotliquidViews/Home/HelloIncludeContents.html的内容
Include
继承父模板
除了嵌入子模版,还能实现布局(Layout)方式的继承父模板,继承需要使用extends和block标签。
以下例子会返回Html<div class="layout"><h1>Here is title</h1><p>Here is body</p></div>
public ActionResult HelloExtends()
{
return DotliquidView();
}
文件~/DotliquidViews/Home/HelloExtendsLayout.html的内容
<div class="layout">
<h1>
{% block title %}
Default title
{% endblock %}
</h1>
<p>
{% block body %}
Default body
{% endblock %}
</p>
</div>
文件~/DotliquidViews/Home/HelloExtends.html的内容
{% extends "~/DotliquidViews/Home/HelloExtendLayout.html" %}
{% block title %}
Here is title
{% endblock %}
{% block body %}
Here is body
{% endblock %}
描画自定义对象
请先看以下的例子
public class ExampleViewModel
{
public string Name { get; set; }
public int Age { get; set; }
}
public ActionResult CustomObject()
{
var template = Template.Parse("Name: {{ model.Name }}, Age: {{ model.Age }}");
var model = new ExampleViewModel() { Name = "john", Age = 35 };
var result = template.Render(Hash.FromAnonymousObject(new { model }));
return Content(result);
}
你可能预料这个例子会显示Name: john, Age: 35,但实际运行时会给出以下错误
Name: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable, Age: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable
这是因为DotLiquid为了安全性,默认不允许描画未经注册的对象,这样即使模板由前端使用者提供也不会导致信息泄露。
为了解决上面的错误,需要把ExampleViewModel注册为可描画的对象。
除了使用RegisterSafeType注册,你也可以让ExampleViewModel继承ILiquidizable,在部分场景下会更适合。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// 在原有的代码下添加
Template.RegisterSafeType(typeof(ExampleViewModel), Hash.FromAnonymousObject);
}
}
写在最后
DotLiquid是一个灵活性很高并且依赖很少的模板引擎,虽然没有Razor流行,但大量的单元测试保证它可以经得起实际的使用。
目前使用了DotLiquid的项目有
目前DotLiquid准备升级2.0版本,作者正在召集PR,如果你有意向可以到DotLiquid的github看看。
DotLiquid模板引擎简介的更多相关文章
- JST(JavaScript Trimpath)前端模板引擎简介
JST(JavaScript Trimpath)前端模板引擎简介及应用 今天在做某系统日志列表的时候用到了这个玩意儿.刚开始只是根据别人的例子照葫芦画瓢完成了日志列表及对应详情,晚上有空了才仔细去网上 ...
- Smarty 模板引擎简介
前言 Smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一.它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑 ...
- Thymeleaf 模板引擎简介
目录 Thymeleaf 模板引擎 官方文档下载 Hello World 新建应用 后台控制器 前端页面 浏览器访问测试 Thymeleaf 模板引擎1.Thymeleaf 是 Web 和独立环境的现 ...
- thymeleaf模板引擎简介
一:thymeleaf 学习笔记---http://www.blogjava.net/bjwulin/articles/395185.html thymeleaf是一个支持html原型的自然引擎,它在 ...
- Spring Boot 系列(五)web开发-Thymeleaf、FreeMarker模板引擎
前面几篇介绍了返回json数据提供良好的RESTful api,下面我们介绍如何把处理完的数据渲染到页面上. Spring Boot 使用模板引擎 Spring Boot 推荐使用Thymeleaf. ...
- SpringBoot系列之集成jsp模板引擎
目录 1.模板引擎简介 2.环境准备 4.源码原理简介 SpringBoot系列之集成jsp模板引擎 @ 1.模板引擎简介 引用百度百科的模板引擎解释: 模板引擎(这里特指用于Web开发的模板引擎)是 ...
- C#模板引擎 DotLiquid
DotLiquid 是一个简单.快速和安全的模板引擎,移植自 Ruby 的 Liquid 标签. 示例模板: <p>{{ user.name }} has to do:</p> ...
- 一,Smarty模板技术/引擎——简介
Smarty是一个使用PHP写出来的模板PHP模板引擎,它提供了逻辑与外在内容的分离,简单的讲,目的就是要使PHP程序员与美工分离,使用的程序员改变程序的逻辑内容不会影响到美工的页面设计,美工重新修改 ...
- Python模板引擎Jinja2使用简介
原文链接 背景 最近在项目开发中,需要针对 Jenkins 项目进行配置,Jenkins 的 job 配置采用的是 xml,在维护配置模板的过程中就遇到了问题,因为逐步发现配置灵活性超出了字符串的范畴 ...
随机推荐
- 【小程序分享篇 二 】web在线踢人小程序,维持用户只能在一个台电脑持登录状态
最近离职了, 突然记起来还一个小功能没做, 想想也挺简单,留下代码和思路给同事做个参考. 换工作心里挺忐忑, 对未来也充满了憧憬与担忧.(虽然已是老人, 换了N次工作了,但每次心里都和忐忑). 写写代 ...
- 用CIL写程序:你好,沃尔德
前言: 项目紧赶慢赶总算在年前有了一些成绩,所以沉寂了几周之后,小匹夫也终于有时间写点东西了.以前匹夫写过一篇文章,对CIL做了一个简单地介绍,不过不知道各位看官看的是否过瘾,至少小匹夫觉得很不过瘾. ...
- HTML渲染过程详解
无意中看到寒冬关于前端的九个问题,细细想来我也只是对第一.二.九问有所了解,正好也趁着这个机会梳理一下自己的知识体系.由于本人对http协议以及dns对url的解析问题并不了解,所以这里之探讨url请 ...
- [APUE]系统数据文件与信息
一.口令文件 UNIX口令文件包含下表中的各个字段,这些字段包含在 由于历史原因,口令文件是/bin/passwd,而且是一个文本文件,每一行都包括了上表中的七个字段,字段之间用":&quo ...
- HTTP常用状态码分析
不管是面试还是工作中,经常会碰到需要通过HTTP状态码去判断问题的情况,比如对于后台RD,给到前端FE的一个接口,出现502或者504 error错误,FE就会说接口存在问题,如果没有知识储备,那就只 ...
- python 数据类型 ---文件一
1.文件的操作流程: 打开(open), 操作(read,write), 关闭(close) 下面分别用三种方式打开文件,r,w,a 模式 . "a"模式将不会覆盖原来的文件内容, ...
- 在 SharePoint Server 2016 本地环境中设置 OneDrive for Business
建议补丁 建议在sharepoint2016打上KB3127940补丁,补丁下载地址 https://support.microsoft.com/zh-cn/kb/3127940 当然不打,也可以用O ...
- Mysql - 触发器/视图
触发器在之前的项目中, 应用的着实不多, 没有办法的时候, 才会去用这个. 因为这个东西在后期并不怎么好维护, 也容易造成紊乱. 我最近的项目中, 由于数据库设计(别人设计的)原因, 导致一些最简单功 ...
- CentOS 6.5安装Node.js, npm
CentOS上可以通过下载*.tar.gz安装包的方式自己解压缩.编译的方式安装,同时还可以采用EPEL的方式安装: Node.js and npm are available from the Fe ...
- Ubuntu Server(Ubuntu 14.04 LTS 64位)安装libgdiplus2.10.9出错问题记录
首先下载libgdiplus2.10.9安装包 wget http://download.mono-project.com/sources/libgdiplus/libgdiplus-2.10.9.t ...