2013-10-17 39 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版本中情况并非如此)。