1. 程式人生 > >【搬運外國同行文章】在非網頁程式裡使用razor模板引擎

【搬運外國同行文章】在非網頁程式裡使用razor模板引擎

【前言】近日研究程式碼生成,急需一個模板引擎,找到了一篇外國同行的文章,裡面有如何在其他環境裡面使用razor而且詳細說明了原理,非常好,本人雖然英語戰力<=5,但是也勉強看得懂,ok,原文地址如下:

下面是本人的渣翻,如有錯漏,請指正,謝謝。

如何在非網頁程式裡使用razor模板引擎?

  微軟最近推出了razor模板引擎技術,雖然該技術與asp.net mvc 預覽版捆綁在一起,但是它可以應用於非asp.net程式裡面。 Razor是asp.net webform外的另一種模板技術,它可以代替目前廣泛應用在webform和mvc上面的aspx模板技術。 【我就不逐句逐句翻譯了,如何使用的翻譯如下:】 假如你還沒有下載這個專案的話,請返回原網址下載,或者點選這裡下載:

開始

下面看一個基本的例子:
@inherits RazorHosting.RazorTemplateBase
@using System.Reflection
Hello @Context.FirstName! Your entry was entered on: @Context.Entered

@{
    // Code block: Update the host Windows Form passed in through the context
    Context.WinForm.Text = "Hello World from Razor at " + DateTime.Now.ToString();
}

AppDomain Id:
    @AppDomain.CurrentDomain.FriendlyName
            
Assembly:
    @Assembly.GetExecutingAssembly().FullName

Code based output: 
@{
    // Write output with Response object from code
    string output = string.Empty;
    for (int i = 0; i < 10; i++)
    {
        output += i.ToString() + " ";
    }
    Response.Write(output);
}

@inherits RazorHosting.RazorTemplateBase
備註:上面 的 inheribts將預設的模板型別改寫成為 RazorTemplateBase,它並非必須的,但是它最大的好處在於,能夠讓 vs 提供這個模板型別的智慧提示,何樂而不為? 上面是模板的內容,下面將介紹如何解析這個模板:
var engine = new RazorEngine<RazorTemplateBase>();

// we can pass any object as context - here create a custom context
var context = new CustomContext()
{
    WinForm = this,
    FirstName = "Rick",
    Entered = DateTime.Now.AddDays(-10)
};

string output = engine.RenderTemplate(this.txtSource.Text
                                      new string[] { "System.Windows.Forms.dll" },
                                      context);

if (output == null)
    this.txtResult.Text = "*** ERROR:\r\n" + engine.ErrorMessage;
else
    this.txtResult.Text = output;

這是最簡單最快捷的方式,其中 CustomContext是作者(譯者注:作者為 Rick Strahl)新增的一個上下文變數,用來傳遞到模板裡面,在模板裡面可以這樣呼叫context的引數:
@Context.FirstName
值得提醒的是,並非所有物件都可以放進context裡面,只有可序列化的物件才可以(假如包含有方法的物件,那麼就不行了),否則會報錯。 假如你不想將字串傳進來而直接用檔案流來解析模板,那麼可以這樣用:
using (reader = new StreamReader("templates\\simple.csHtml", true))
{
    result = host.RenderTemplate(reader,  new string[] { "System.Windows.Forms.dll" }, 
                                 this.CustomContext);
}

上面解析模板的api都是RenderTemplate,這個是封裝好的高階用法,假如您希望更加精確控制模板的分析行為,那麼可以使用較底層的api,例如:
// we can pass any object as context - here create a custom context
var context = new CustomContext()
{
    WinForm = this,
    FirstName = "Rick",
    Entered = DateTime.Now.AddDays(-10)
};

var engine = new RazorEngine<RazorTemplateBase>();
string assId = null;

using (StringReader reader = new StringReader(this.txtSource.Text))
{
    assId = engine.ParseAndCompileTemplate(new string[] { "System.Windows.Forms.dll" }, reader);
}

string output = engine.RenderTemplateFromAssembly(assId, context);

if (output == null)
    this.txtResult.Text = "*** ERROR:\r\n" + engine.ErrorMessage;
else
    this.txtResult.Text = output;

注意:翻譯到這裡我就明白如何用這個東西了,假如你要呼叫自己的dll,譬如:Mytools.Common類庫,那麼就必須在解析模板的時候宣告該dll,譬如:
    result = host.RenderTemplate(reader,  new string[] { "System.Windows.Forms.dll","Mytools.Common.dll" }, 
                                 this.CustomContext);

接下來的都是一些高階用法,各位有興趣可以去原網址查閱。

備註:如何在vs裡面獲得程式碼提示功能?任意類庫的提示。

這裡以vs2010為例,其中: 這位兄弟幫了大忙。 首先,在專案下面新增一個web.config 裡面內容如下:
<?xml version="1.0" encoding="utf-8"?>
<!--
  有關如何配置 ASP.NET 應用程式的詳細資訊,請訪問
  http://go.microsoft.com/fwlink/?

LinkId=169433
  -->
<configuration>
  <configSections>

  </configSections>

  <connectionStrings>

  </connectionStrings>


  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true">


      <assemblies>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

      </assemblies>

      <!--
      <buildProviders>
    
        <add extension=".cshtml" 

type="Microsoft.WebPages.Compilation.InlinePageBuildProvider" />
       
      
      </buildProviders>
      -->


    </compilation>

    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
        <add namespace="Easis.Common"/>
      </namespaces>
    </pages>
  </system.web>


  <system.webServer>

    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />
    
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule"

scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64"

responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding  xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers"   publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>


      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>


  </runtime>

</configuration>

有了這個東西,以後在這個專案下面新建的任何cshtml文件都會有智慧程式碼提示功能,但是對於第三方類庫是沒有提示的,如何解決? 請看:
    <compilation debug="true">


      <assemblies>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add assembly="RazorHosting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        <add assembly="Easis.Common,Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        <add assembly="Easis.Security, Version=1.0.0.0, Culture=neutral,PublicKeyToken=null"/>
      </assemblies>

在assemblies標籤下面新增第三方類庫,然後將第三方的dll都放到bin目錄。。注意:沒有bin目錄的要新建一個,並且不能放在bin/debug或者bin/release下面,因為web config匯入去的路徑就是bin,你可以在 專案的生成裡面設定輸出路徑為: bin/ ok,做完這些你應該可以看到完美的程式碼提示功能了, 請注意,使用這個razorHosting的時候要請順便將dll導進去,否則會報錯。 下面再分享一個小工具,這個小工具的作用是分析dll檔案,獲得具體的引用資訊,免得大家不知道version,publicktoken之類的資訊 無法新增到web config裡面。