DotLiquid模板引擎简介
DotLiquid是⼀个在.Net Framework上运⾏的模板引擎,采⽤Ruby的Liquid语法,这个语法⼴泛的⽤在Ruby on rails和Django等⽹页框架中。DotLiquid相⽐于Mvc默认模板引擎Razor的好处有:
因为不需要编译到程序集再载⼊
⾸次渲染速度很快
不会导致内存泄漏
可以在任何地⽅使⽤
不需要先准备WebViewPage,ViewContext等复杂的上下⽂对象
⽰例代码
我创建⼀个使⽤了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;django前端模板
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 inv
这是因为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的看看。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。