• 用Razor語法寫範本-RazorEngine組件介紹


    最近剛好有要寫寄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上,我太落伍了。

    image

    圖一 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,如何產生結果(有點累,還是用別人的組件比較好)。

    01namespace RezorCodeDomSample
    02{
    03    internal class Program
    04    {
    05        private static void Main(string[] args)
    06        {
    07            //簡單的範本
    08            string template = @"@{var name=""Would"";}
    09                                Hello @name!!";
    10 
    11            var input = new System.IO.StringReader(template);
    12 
    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);
    19 
    20            //取得結果的CodeDom
    21            var code = engine.GenerateCode(input);
    22            var codeType = code.GeneratedCode.Namespaces[0].Types[0];
    23            var codeProvider = new CSharpCodeProvider();
    24 
    25            //將CodeDom輸出到檔案中
    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());
    31 
    32            //將CodeDom編譯
    33            var options = new CompilerParameters()
    34            {
    35                GenerateInMemory = true,
    36                GenerateExecutable = false,
    37            };
    38            options.ReferencedAssemblies.Add(typeof(Program).Assembly.Location);
    39            var asselby = codeProvider.CompileAssemblyFromDom(options, code.GeneratedCode);
    40 
    41            //執行Template
    42            var type = asselby.CompiledAssembly.GetType("RezorCodeDomSample.MyTemplateResult");
    43            var ins = Activator.CreateInstance(type) as MyTemplate;
    44            ins.Execute();
    45            Console.Write(ins.Reault);
    46        }
    47    }
    48 
    49    //如果沒有Base類會不好處理
    50    public class MyTemplate
    51    {
    52        private StringBuilder sb = new StringBuilder();
    53 
    54        public virtual void Execute()
    55        {
    56        }
    57 
    58        public void Write(object value)
    59        {
    60            sb.Append(value);
    61        }
    62 
    63        public void WriteLiteral(object value)
    64        {
    65            sb.Append(value);
    66        }
    67 
    68        public string Reault
    69        {
    70            get { return sb.ToString(); }
    71        }
    72    }
    73}

     

    使用範例(部份直接使用官網的範例)

    一般用法

    1string template = "Hello @Model.Name! Welcome to Razor!";
    2string 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#的語法都支援。

    image

    1string result = Razor.Parse(File.ReadAllText("test.cshtml"), new { IsVip = true, Name = "Wade" });

     

    進階用法

    Template的Include

    RazorEngine雖然不支援RanderAction或RanderPartial,不過他有提供Include方法,載入已經Compile(或Parse)過的範本,以下是使用範例:

    1string template1 = "Hello @Model.Name";
    2string template2 = "This is my sample template, @Include("Template1",Model)";
    3Razor.Compile(template1, "Template1");
    4string result = Razor.Parse(template2, new { Name = "Wade" });

     

    內嵌方法

    如果只有單一個範本會用到的方法可以使用內嵌方法,以下是使用範例:

    1string template = @"
    2@helper MyMethod(string name) {
    3  Hello @name
    4}
    5 
    6@MyMethod(Model.Name)! Welcome to Razor!";
    7 
    8string result = Razor.Parse(template, new { Name = "World" });

     

    BaseType

    每一個範本,最後都會使用System.Web.Razor.RazorTemplateEngine編譯成Class,而且繼承BaseType,所以BaseType決定了範本能使用的功能,如果還是不清楚以第一個範例為例:

    1@"@{var name=""Would"";}
    2  Hello @name!!";

     

    這些內容經剖析後會變成這樣

    01//與第一個範例拿掉註解後所產生的test.cs檔案相同
    02namespace RezorCodeDomSample
    03{
    04    public class MyTemplateRsult : RezorCodeDomSample.MyTemplate
    05    {
    06        public MyTemplateRsult()
    07        {
    08        }
    09 
    10        public override void Execute()
    11        {
    12            var name = "Would";
    13 
    14            WriteLiteral("Hello ");
    15 
    16 
    17            Write(name);
    18            WriteLiteral("!! ");
    19        }
    20    }
    21}

     

    這樣有比較清楚BaseType的功用了嗎?

    所以如果希望所有的範本都可以使用的功能,可以繼承RazorEngine.Templating.TemplateBase,將擴充功能寫在子類別,然後註冊子類別,以下是使用範例:

    01public abstract class MyCustomTemplateBase<T> : TemplateBase<T>
    02{
    03  public string ToUpperCase(string name)
    04  {
    05    return name.ToUpperCase();
    06  }
    07}
    08 
    09//註冊子類
    10Razor.SetTemplateBase(typeof(MyCustomTemplateBase<>));
    11 
    12string template = "My name in UPPER CASE is: @ToUpperCase(Model.Name)";
    13string result = Razor.Parse(template, new { Name = "Matt" });

     

    載入組件與命名空間

    RazorEngine註冊CodeDom所使用的組件是使用AppDomain.CurrentDomain.GetAssemblies()的方式,所以只要在專案中所參考的組件,範本中都可以使用,還有為了增加撰寫的便利性,可以增加命名空間,以下是使用範例:

    1Razor.DefaultTemplateService.Namespaces.Add("System.Xml");
    2 
    3string template = @"@{
    4     var xml = new XmlDocument();
    5     xml.LoadXml(Model);
    6     Write(xml.InnerXml);
    7}";
    8string result = Razor.Parse<string>(template, "<Test>test</Test>");

     

     

    設定檔

    跟ASP.NET MVC 3一樣,命名空間或BaseType等等都可以寫在設定檔中,詳情請參考官網

    增加區段

    1<?xml version="1.0" encoding="UTF-8" ?>
    2<configuration>
    3    <configSections>
    4        <section name="razorEngine" type="RazorEngine.Configuration.RazorEngineConfigurationSection, RazorEngine" requirePermission="false" />
    5    </configSections>
    6</configuration>

     

    增加設定

    01<razorEngine activator="RazorEngineSamples.Activators.MySampleActivator, RazorEngineSamples"
    02             factory="RazorEngine.Web.WebCompilerServiceFactory, RazorEngine.Web">
    03    <namespaces>
    04        <add namespace="System.Linq" />
    05    </namespaces>
    06    <templateServices default="myCustomTemplateService">
    07        <add name="myCustomTemplateService1" language="CSharp" />
    08        <add name="myCustomTemplateService2" templateBase="MyTemplateBase"/>
    09    </templateServices>
    10</razorEngine>
    1  

    TemplateService可以讓某些範本使用不同的設定,以下是使用範例:

    1var service = Razor.Services["myCustomTemplateService"];
    2string result = service.Parse("Hello @Model.Name", new { Name = "World" });
  • 相关阅读:
    [C++]猜词游戏简版
    [C++]异常处理实例-基础版
    C++Primer Plus习题记录-Chapter12
    C++Primer Plus习题记录-Chapter11
    [C++]MI(多继承)实例-基础版
    Windows下编译libevent及使用
    jquery点击回到顶部
    简体繁体转换
    检测ip和地区
    点击复制到剪切板
  • 原文地址:https://www.cnblogs.com/cxd4321/p/3365500.html
Copyright © 2020-2023  润新知