最近剛好有要寫寄Email的程式,在代碼中寫HTML覺得很呆,抽出代碼外寫到txt或html檔當範本,由程式執行時在載入檔案時用Regex換關鍵字又覺得不夠好用,而且因為有時會有要判斷一些條件,就會寫一堆if esle在代碼中看了就討厭,因為寫MVC久了,就很希望範本也可以像MVC中的View,傳Model過去,在View層決定如何呈現,而更希望是使用Razor語法來寫範本,花了時間研究,找到RazorEngine,使用它來載入檔案,由它來編譯與執行並輸入結果。
RazorEngine
官網網址:http://razorengine.codeplex.com/
在找到RazorEngine之前曾經想過其他的方案,如T4與V8 Engine載jquery.template,但T4如果要獨立於MSBuild或Visual Studio執行有點麻煩,而V8 Engine我又不想在Class Library專案中放一堆js檔,後來就想到Razor,因為Razor的相關處理都是寫在System.Web.Razor,雖然Namespace叫System.Web,但根本沒有載入任何的System.Web相關的組件(如圖一),所以我肯定它可以獨立在非Web環境於中使用,在研究如何運用的期間,就發現早在去年就有人寫好放在CodePlex上,我太落伍了。

圖一 System.Web.Razor的參考,只有載入基本的三個組件
註:有興趣知道如何使用System.Web.Razor產生結果(基本上都是CodeDom),我所知道就有四套,小弟這一篇[ASP.NET MVC]Razor Views 預編譯(Pre-Compile)[1]-加快第一次執行回應速度介紹的二個Extension與本篇的RazorEngine與ASP.NET MVC 3使用的System.Web.WebPages.Razor,除了System.Web.WebPages.Razor外都是Open Source的可以下載Code來觀摩。
下面的範例,將展示如果只單獨使用System.Web.Razor.dll,如何產生結果(有點累,還是用別人的組件比較好)。
01 |
namespace RezorCodeDomSample |
03 |
internal class Program |
05 |
private static void Main(string[] args) |
08 |
string template = @"@{var name=""Would"";} |
11 |
var input = new System.IO.StringReader(template); |
13 |
//產生Razor的TemplateEngine |
14 |
var host = new RazorEngineHost(new CSharpRazorCodeLanguage()); |
15 |
host.DefaultBaseClass = "RezorCodeDomSample.MyTemplate"; |
16 |
host.DefaultNamespace = "RezorCodeDomSample"; |
17 |
host.DefaultClassName = "MyTemplateResult"; |
18 |
var engine = new RazorTemplateEngine(host); |
21 |
var code = engine.GenerateCode(input); |
22 |
var codeType = code.GeneratedCode.Namespaces[0].Types[0]; |
23 |
var codeProvider = new CSharpCodeProvider(); |
26 |
//CodeGeneratorOptions options = new CodeGeneratorOptions(); |
27 |
//options.BlankLinesBetweenMembers = true; |
28 |
//System.IO.StringWriter sw = new System.IO.StringWriter(); |
29 |
//codeProvider.GenerateCodeFromCompileUnit(code.GeneratedCode, sw, options); |
30 |
//File.WriteAllText("c:\\text.cs", sw.ToString()); |
33 |
var options = new CompilerParameters() |
35 |
GenerateInMemory = true, |
36 |
GenerateExecutable = false, |
38 |
options.ReferencedAssemblies.Add(typeof(Program).Assembly.Location); |
39 |
var asselby = codeProvider.CompileAssemblyFromDom(options, code.GeneratedCode); |
42 |
var type = asselby.CompiledAssembly.GetType("RezorCodeDomSample.MyTemplateResult"); |
43 |
var ins = Activator.CreateInstance(type) as MyTemplate; |
45 |
Console.Write(ins.Reault); |
50 |
public class MyTemplate |
52 |
private StringBuilder sb = new StringBuilder(); |
54 |
public virtual void Execute() |
58 |
public void Write(object value) |
63 |
public void WriteLiteral(object value) |
70 |
get { return sb.ToString(); } |
使用範例(部份直接使用官網的範例)
一般用法
1 |
string template = "Hello @Model.Name! Welcome to Razor!"; |
2 |
string result = Razor.Parse(template, new { Name = "World" }, "Sample"); |
最後一個參數Name是選項參數,但建議給值因為關係到快取,如果有給,下次使用相同名稱的範本會用快取的,而且關係到範本的Include,雖然RazorEngine不能用RanderAction或RanderPartial但有提供Include可以載入,也是使用此Name為關鍵字。
使用.cshtml檔案
只要是副檔名為.cshtml,就算不在ASP.NET MVC3專案中,編輯.cshtml的方式都相同(但缺web.config中的設定,所以有些功能出不來),當然範本檔副檔名不一定要為.cshtml,但有IDE支援總比沒有好。
只是寫法要變,因為ASP.NET MVC 3的BaseType是System.Web.Mvc.WebViewPage,而RazorEngine的BaseType是RazorEngine.Templating.TemplateBase,除了Model屬性外其他的Html、Url、Ajax等等屬性都不沒有,但是C#的語法都支援。

1 |
string result = Razor.Parse(File.ReadAllText("test.cshtml"), new { IsVip = true, Name = "Wade" }); |
進階用法
Template的Include
RazorEngine雖然不支援RanderAction或RanderPartial,不過他有提供Include方法,載入已經Compile(或Parse)過的範本,以下是使用範例:
1 |
string template1 = "Hello @Model.Name"; |
2 |
string template2 = "This is my sample template, @Include(\"Template1\",Model)"; |
3 |
Razor.Compile(template1, "Template1"); |
4 |
string result = Razor.Parse(template2, new { Name = "Wade" }); |
內嵌方法
如果只有單一個範本會用到的方法可以使用內嵌方法,以下是使用範例:
2 |
@helper MyMethod(string name) { |
6 |
@MyMethod(Model.Name)! Welcome to Razor!"; |
8 |
string result = Razor.Parse(template, new { Name = "World" }); |
BaseType
每一個範本,最後都會使用System.Web.Razor.RazorTemplateEngine編譯成Class,而且繼承BaseType,所以BaseType決定了範本能使用的功能,如果還是不清楚以第一個範例為例:
1 |
@"@{var name=""Would"";} |
這些內容經剖析後會變成這樣
01 |
//與第一個範例拿掉註解後所產生的test.cs檔案相同 |
02 |
namespace RezorCodeDomSample |
04 |
public class MyTemplateRsult : RezorCodeDomSample.MyTemplate |
06 |
public MyTemplateRsult() |
10 |
public override void Execute() |
14 |
WriteLiteral("Hello "); |
18 |
WriteLiteral("!!\r\n"); |
這樣有比較清楚BaseType的功用了嗎?
所以如果希望所有的範本都可以使用的功能,可以繼承RazorEngine.Templating.TemplateBase,將擴充功能寫在子類別,然後註冊子類別,以下是使用範例:
01 |
public abstract class MyCustomTemplateBase<T> : TemplateBase<T> |
03 |
public string ToUpperCase(string name) |
05 |
return name.ToUpperCase(); |
10 |
Razor.SetTemplateBase(typeof(MyCustomTemplateBase<>)); |
12 |
string template = "My name in UPPER CASE is: @ToUpperCase(Model.Name)"; |
13 |
string result = Razor.Parse(template, new { Name = "Matt" }); |
載入組件與命名空間
RazorEngine註冊CodeDom所使用的組件是使用AppDomain.CurrentDomain.GetAssemblies()的方式,所以只要在專案中所參考的組件,範本中都可以使用,還有為了增加撰寫的便利性,可以增加命名空間,以下是使用範例:
1 |
Razor.DefaultTemplateService.Namespaces.Add("System.Xml"); |
4 |
var xml = new XmlDocument(); |
8 |
string result = Razor.Parse<string>(template, "<Test>test</Test>"); |
設定檔
跟ASP.NET MVC 3一樣,命名空間或BaseType等等都可以寫在設定檔中,詳情請參考官網
增加區段
1 |
<?xml version="1.0" encoding="UTF-8" ?> |
4 |
<section name="razorEngine" type="RazorEngine.Configuration.RazorEngineConfigurationSection, RazorEngine" requirePermission="false" /> |
增加設定
01 |
<razorEngine activator="RazorEngineSamples.Activators.MySampleActivator, RazorEngineSamples" |
02 |
factory="RazorEngine.Web.WebCompilerServiceFactory, RazorEngine.Web"> |
04 |
<add namespace="System.Linq" /> |
06 |
<templateServices default="myCustomTemplateService"> |
07 |
<add name="myCustomTemplateService1" language="CSharp" /> |
08 |
<add name="myCustomTemplateService2" templateBase="MyTemplateBase"/> |
TemplateService可以讓某些範本使用不同的設定,以下是使用範例:
1 |
var service = Razor.Services["myCustomTemplateService"]; |
2 |
string result = service.Parse("Hello @Model.Name", new { Name = "World" }); |
- 用Razor語法寫範本-RazorEngine組件介紹【转——非常好,可以用它来代替NVelocity】
RazorEngine 官網網址:http://razorengine.codeplex.com 在找到RazorEngine之前曾經想過其他的方案,如T4與V8 Engine載jquery.temp ...
- 開賣!下集 -- ASP.NET 4.5 專題實務(II)-範例應用與 4.5新功能【VB/C# 雙語法】
開賣!下集 -- ASP.NET 4.5 專題實務(II)-範例應用與 4.5新功能[VB/C# 雙語法] 我.....作者都沒拿到書呢! 全台灣最專業的電腦書店 -- 天瓏書局 已經開賣了! 感謝天 ...
- Java學習筆記(基本語法)
本文件是以學習筆記的概念為基礎,用於自我的複習紀錄,不過也開放各位的概念指證.畢竟學習過程中難免會出現觀念錯誤的問題.也感謝各位的觀念指證. 安裝JDK 在Oracle網站中找自己系統的JDK下載位置 ...
- vue起步和模板語法
vue構造器里有哪些內容: var a=new Vue({}) 模板語法: 文本插值: html: html的屬性里的值應該使用v-bind: 表達式: 指令; 參數:v-bind,v-on 雙向用戶 ...
- 查看LINQ Expression編譯後的SQL語法(转)
在用了LINQ語法之後的一個月,我幾乎把SQL語法全部拋到腦後了,不過 LINQ好用歸好用,但是實際上操作資料庫的還是SQL語法,如果不知道LINQ語法 編譯過後產生怎樣的SQL語法,一不小心效能就會 ...
- Delphi APP 開發入門(六)Object Pascal 語法初探
Delphi APP 開發入門(六)Object Pascal 語法初探 分享: Share on facebookShare on twitterShare on google_plusone_sh ...
- GO語言基礎教程:數組,切片,map
這節課我們來講解數組,切片和map,或許您是從其他語言轉到GO語言這邊的,那麼在其他語言的影響下您可能會不太適應GO語言的數組,因為GO語言把數組給拆分成了array,slice和map,接下來的時間 ...
- 何解決 LinqToExcel 發生「無法載入檔案或組件」問題何解決 LinqToExcel 發生「無法載入檔案或組件」問題
在自己的主機上透過 Visual Studio 2013 與 IISExpress 開發與測試都還正常,但只要部署到測試機或正式機,就是沒辦法順利執行,卡關許久之後找我協助.我發現錯誤訊息確實很「一般 ...
- jquery 語法
基本形式: $(selector).action() 文檔加載函數: $(document).Ready{ function(){ //將所有的函數寫到文檔加載函數里,可以防止頁面未加載完全,就執行j ...
随机推荐
- greenDao 介绍
greenDAO是一个针对Android的轻快速ORM解决方案,它将对象映射到SQLite数据库.http://greenrobot.org/greendao/ greenDAO is a light ...
- 洛谷P1133 教主的花园
题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树 ...
- 7、Redis中对ZSet类型的操作命令
写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- ---------- ...
- Redis "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk"问题的解决(转)
今天第二次遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persis ...
- STM32 TIMER OUTPUT DIAGRAM
- C - 项目收藏
Web框架 [荐]Kore:开源 C 语言 Web 框架 Raphters:A web framework for C ulfius:Web Framework for REST API in C, ...
- IIS发布以后,handle文件找不到,404错误
昨天碰到一个奇怪问题,开发环境没有问题,发布到IIS7.5以后,保存操作不能成功,跟踪发现,是handle方法找不到,抛错. 想了很多方法,最后把怀疑是GET方式和客户数据引起的问题,改成POST方式 ...
- .NET开源分布式日志框架ExceptionLess实战演练(公开版)
一.课程介绍 在以前,我们做日志收集大多使用 Log4net,Nlog 等框架,在应用程序变得复杂并且集群的时候,可能传统的方式已经不是很好的适用了,因为收集各个日志并且分析他们将变得麻烦而且浪费时间 ...
- 使用React改版网站
网站是毕业设计的作品,开发这个网站的目的主要用于记录一些笔记,以及聚合一些资讯信息,也算自己在网络世界中的一块静地吧,可以在这里一些技术上想法的实践. 网站最初前端使用vue开发,在前段时间由于项目的 ...
- Win10年度更新开发必备:VS2015 Update 2正式版下载汇总
========================================================================== 微软在03月30日发布了Visual Studio ...