閱讀523 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Razor Engine,實現代碼生成器的又一件利器

Razor Engine,之前僅僅是ASP.NET MVC的一種View引擎,目前已經完全成為一種可以獨立使用的模版引擎,並且已經成為了CodePlex上一個開源的項目(https://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 
   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提供代碼生成


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-25 15:34:14

  上一篇:go  ASP.NET Web API路由係統:Web Host下的URL路由
  下一篇:go  如何讓ASP.NET Web API的Action方法在希望的Culture下執行