2013-10-17 40 views
1

我使用RazorEngine從網頁上的HTML片段分析模板。 (這是一個遺留系統,切換到Mvc Razor視圖是不可能的,所以我們將小部分切換到使用RazorEngine的地方)。有很多關於SO的問題,互聯網試圖讓Mvc的Html和Url助手與Razor引擎一起工作。爲了得到@Html語法的工作,我已經修改了一些代碼,發現here到HTML代碼添加到基礎模板:RazorEngine @Html助手工作,但轉義Html

public HtmlHelper<t> Html 
{ 
    get 
    { 
     if (helper == null) 
     {   
      var writer = this.CurrentWriter; //TemplateBase.CurrentWriter 
      var vcontext = new ViewContext() { Writer = writer, ViewData = this.ViewData}; 

      helper = new HtmlHelper<t>(vcontext, this); 
     } 
     return helper; 
    } 
} 
public ViewDataDictionary ViewData 
{ 
    get 
    { 
     if (viewdata == null) 
     { 

      viewdata = new ViewDataDictionary(); 
      viewdata.TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = string.Empty }; 

      if (this.Model != null) 
      { 
       viewdata.Model = Model; 
      } 

     } 

    return viewdata; 
    } 
    set 
    { 
     viewdata = value; 
    } 
} 

大量的調試後進入的HTML源代碼,我想我已經成功地實例化一切在HTML輔助需求,併成功運行了@Html.Label ...問題是,生成的HTML是:

&lt;label for=&quot;MyNumber&quot;&gt;MyNumber&lt;/label&gt; 

當它顯然應該是:

<label for="MyNumber">MyNumber</label> 

我難以理解如何解決這個問題。在查看RazorEngine源代碼時,我無法找到編碼是如何發生的。我最初的想法是TextWriter必須對值進行編碼,但我無法確認這一點。我怎樣才能讓@Html.BlahFor()呈現未經轉義的html?

+0

您應該使用MVC/Razor基本類型而不是RazorEngine的基本類型。 – SLaks

+0

@SLaks,我會研究使用'WebViewPage',但它可能會比麻煩更多的麻煩,因爲MVC通常會處理該問題,因此找出如何正確構建它是值得的。此外,我將不得不在這個新的子類上重新實現RazorEngine'ITemplate'。我會繼續尋找解決原來的問題,因爲我不知道哪一個會更加努力。 – mao47

回答

1

我找到了解決我面臨的問題的解決方法。 RazorEngine的基本模板將自動編碼一個字符串(或對象),如果它不投射到IEncodedString

public override void WriteTo(TextWriter writer, object value) 
{ 
    if (writer == null) 
     throw new ArgumentNullException("writer"); 

    if (value == null) return; 

    var encodedString = value as IEncodedString; 
    if (encodedString != null) 
    { 
     writer.Write(encodedString); 
    } 
    else 
    { 
     var htmlString = value as IHtmlString; 
     if(htmlString != null) 
      writer.Write(htmlString.ToHtmlString()); 
     else 
     { 
      //This was the base template's implementation: 
      encodedString = TemplateService.EncodedStringFactory.CreateEncodedString(value); 
      writer.Write(encodedString); 
     } 
    } 
} 

我還沒有看到,如果這種變化將引起任何錯誤,但現在我發現它應該是比較容易的方法:在我的情況,我在我的模板類中重寫WriteTo方法解決了這個問題在未來改變。

編輯:只要加入強制轉換爲這個接口檢查,以查看HTML輔助返回MvcHtmlString,它實現IHtmlString,我們能避免編碼由助手返回的HTML,同時還具有對任何地方安全這種方法的其他調用者。

+1

'MvcHtmlString'並不總是實現'IHtmlString',注意這一點。它是在MVC 5中實現的,但不是在一些較老的MVC版本(支持fx 3.5,其中沒有IHtmlString)的版本中。 –

+0

使用'WriteTo'重寫'Html.BeginForm()'輸出仍然是編碼(http://stackoverflow.com/questions/41531298/how-to-render-html-beginform-output-unescaped)。我們是否應該重寫其他寫入方法? – Andrus

0

感謝您的靈感,我將數據存儲在xml中,並創建了一個不同的解決方法,而不覆蓋WriteTo方法。我使用了一個從TemplateBase繼承的類並創建了2個新方法。

public IEncodedString HtmlOf(NBrightInfo info, String xpath) 
    { 
     var strOut = info.GetXmlProperty(xpath); 
     strOut = System.Web.HttpUtility.HtmlDecode(strOut); 
     return new RawString(strOut); 
    } 

    public IEncodedString BreakOf(NBrightInfo info, String xpath) 
    { 
     var strOut = info.GetXmlProperty(xpath); 
     strOut = System.Web.HttpUtility.HtmlEncode(strOut); 
     strOut = strOut.Replace(Environment.NewLine, "<br/>"); 
     strOut = strOut.Replace("\t", "&nbsp;&nbsp;&nbsp;"); 
     strOut = strOut.Replace("'", "&apos;"); 
     return new RawString(strOut); 
    } 
0

ANTARIS,RazorEngine的作家,已提供了處理這個問題的另一種有趣的方式,並通過它爲什麼不是默認設置的方式解釋(減少儘可能RazorEngine依賴)。

這裏是你的情況他answer on the corresponding github issue相關部分:

我認爲最簡單的 的事情在這裏,將實現自定義 IEncodedStringFactory它處理MvcHtmlString。喜歡的東西:

public class MvcHtmlStringFactory : IEncodedStringFactory 
{ 
    public IEncodedString CreateEncodedString(string rawString) 
    { 
    return new HtmlEncodedString(rawString); 
    } 

    public IEncodedString CreateEncodedString(object obj) 
    { 
    if (obj == null) 
     return new HtmlEncodedString(string.Empty); 

    var htmlString = obj as HtmlEncodedString; 
    if (htmlString != null) 
     return htmlString; 

    var mvcHtmlString = obj as MvcHtmlString; 
    if (mvcHtmlString != null) 
     return new MvcHtmlStringWrapper(mvcHtmlString); 

    return new HtmlEncodedString(obj.Tostring()); 
    } 
} 

public MvcHtmlStringWrapper : IEncodedString 
{ 
    private readonly MvcHtmlString _value; 

    public MvcHtmlStringWrapper(MvcHtmlString value) 
    { 
    _value = value; 
    } 

    public string ToEncodedString() 
    { 
    return _value.ToString(); 
    } 

    public override string ToString() 
    { 
    return ToEncodedString(); 
    } 
} 

這將使現有MvcHtmlString情況下繞過 RazorEngine內置的編碼機制。這不會成爲 基礎庫的一部分,因爲我們不會依賴 System.WebSystem.Web.Mvc

您需要通過您的配置,這樣組裝起來:

var config = new TemplateServiceConfiguration() 
{ 
    BaseTemplateType = typeof(MvcTemplateBase<>), 
    EncodedStringFactory = new MvcHtmlStringFactory() 
}; 

就個人而言,我一直在使用他的代碼之前切換MvcHtmlStringIHtmlString。從MVC 5開始,MvcHtmlString也實現了它。 (請注意,在一些較舊的MVC版本中情況並非如此)。