Razor Engine,之前僅僅是ASP.NET MVC的一種View引擎,目前已經完全成為一種可以獨立使用的模版引擎,并且已經成為了CodePlex上一個開源的項目(http://razorengine.codeplex.com/)。對于使用過ASP.NET MVC Razor視圖引擎的朋友們一定已經領略過它的靈活性和易用性,在這篇文章中我們將利用它來實現一個代碼生成器使我們可以以Razor的語法來定義代碼模版。[源代碼從這里下載]
在《一個簡易版的T4代碼生成"框架"》這篇文章中,我創建了一個能夠生成多個文件的代碼生成器,其核心是兩個基本的類型:Template類生成代碼文件的內容,Generator執行Template。現在我將通過自定義一個基于Razor Engine的Template,讓它讀取以Razor語法編寫的模版文件并生成相應的代碼。
不過在具體介紹實現原理之前,還是先來看看它能夠達到的效果。如右圖所示,我們還是通過一個.tt文件(Generator.tt)來生成相應的代碼文件,具體生成的代碼文件就是依賴于該.tt文件的三個.cs 文件:Foo.cs、Bar.cs和Baz.cs。簡單起見,我們僅僅在這三個文件中生成了一個與文件同名的空Class,它們的定義如下。
1: public class Foo
2: {
3: }
4:
5: public class Bar
6: {
7: }
8:
9: public class Baz
10: {
11: }
如下所示的是Generator.tt的內容,它直接執行一個類型為DemoGenerator的生成器。
1: <#@ template hostspecific="true" language="C#" #>
2: <#@ assembly name="$(TargetDir)Artech.CodeGeneration.dll" #>
3: <#@ import namespace="Artech.CodeGeneration" #>
4: <#@ output extension=".empty" #>
5: <#this.RunCodeGenerator(this.Host, new DemoGenerator());#>
作為代碼生成器的DemoGenerator定義如下,它重寫了CreateTemplates方法并返回一個包含三個RazorTemplate<TModel>的字典,該字典的Key表示生成的文件名。
1: public class DemoGenerator: Generator
2: {
3: protected override IDictionary<string, Template> CreateTemplates()
4: {
5: Dictionary<string, Template> templates = new Dictionary<string, Template>();
6: templates.Add("Foo.cs", new RazorTemplate<string>("template.razor", "Foo"));
7: templates.Add("Bar.cs", new RazorTemplate<string>("template.razor", "Bar"));
8: templates.Add("Baz.cs", new RazorTemplate<string>("template.razor", "Baz"));
9: return templates;
10: }
11: }
構建RazorTemplate<TModel>需要傳入兩個參數,第一個參數是用于定義Razor模版的文件路徑(可以是絕對路徑,也可以是相對于.tt文件的相對路徑),另一個是作為Model的對象(相當于ASP.NET強類型View的Model)。通過上面的代碼可以看出,三個RazorTemplate<TModel>均使用同一個Model類型為字符串的模版文件template.razor,該模版內容定義如下。可以看出作為Model的字符串在模版中作為了生成類型的名稱。
1: public class @Model
2: {
3: }
我假設你已經了解了《一個簡易版的T4代碼生成"框架"》這篇文章的內容,所以我們只需要簡單介紹RazorTemplate<TModel>的定義就可以了。首選RazorTemplate<TModel>是一個具有如下定義的RazorTemplate類型的子類。RazorTemplate的只讀屬性TemplateFileName 表示Razor模版的路徑,用于讀取模版文本內容的虛方法GetTemplateText直接讀取指定模版文件的內容。在重寫的TransformText方法中,我們調用Razor的靜態方法Parse對模版內容進行解析并生成代碼文本。
1: public class RazorTemplate : Template
2: {
3: public string TemplateFileName { get; private set; }
4: public RazorTemplate(string templateFileName)
5: {
6: this.TemplateFileName = templateFileName;
7: }
8: protected virtual string GetTemplateText()
9: {
10: string path = this.TemplateFileName;
11: if (!Path.IsPathRooted(path))
12: {
13: path = Path.Combine(Path.GetDirectoryName(TransformContext.Current.Host.TemplateFile), path);
14: }
15: return File.ReadAllText(path);
16: }
17:
18: public override string TransformText()
19: {
20: return Razor.Parse(this.GetTemplateText());
21: }
22: }
繼承自RazorTemplate的泛型RazorTemplate<TModel>定義如下。它具有一個表示Model的只讀屬性,該屬性在構造函數中被初始化。在重寫的TransformText方法中,我們調用Razor泛型的靜態方法Parse<TModel>解析模版文本并傳入Model對象。
1: public class RazorTemplate<TModel> : RazorTemplate
2: {
3: public TModel Model { get; private set; }
4: public RazorTemplate(string templateFileName, TModel model)
5: : base(templateFileName)
6: {
7: this.Model = model;
8: }
9:
10: public override string TransformText()
11: {
12: return Razor.Parse<TModel>(this.GetTemplateText(), this.Model);
13: }
14: }
相關閱讀:
與VS集成的若干種代碼生成解決方案[博文匯總(共8篇)]
通過CodeDOM定義生成代碼的結構
通過Visual Studio的Custom Tool定義代碼生成器
不同于CodeDOM的代碼生成機制——T4
通過T4模板實現單文件的代碼生成
通過T4模板實現多文件的代碼生成
解決T4模板的程序集引用的五種方案
編寫T4模板進行代碼生成無法避免的兩個話題:"Assembly Locking"&"Debug"
通過自定義BuildProvider為ASP.NET提供代碼生成
文章列表