RazorEngine @Html帮助程序工作,但逃避Html

我正在使用RazorEngine来解析网页上html代码段的模板。 (这是一个遗留系统,切换到Mvc Razor视图是不可能的,所以我们将小部分切换到使用RazorEngine,这是有道理的)。 有很多关于SO和互联网的问题试图让Mvc的Html和Url助手与Razor引擎一起工作。 为了使@Html语法起作用,我修改了一些代码,将Html添加到基本模板中:

 public HtmlHelper Html { get { if (helper == null) { var writer = this.CurrentWriter; //TemplateBase.CurrentWriter var vcontext = new ViewContext() { Writer = writer, ViewData = this.ViewData}; helper = new HtmlHelper(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是:

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

当它显然应该是:

  

我很难过如何解决这个问题。 在查看RazorEngine源时,我无法找到编码的发生方式。 我最初的想法是TextWriter必须对值进行编码,但我无法确认这一点。 如何让@Html.BlahFor()呈现未转义的html?

我找到了解决我面临的问题的解决方法。 RazorEngine的基本模板将自动编码一个字符串(或对象),如果它没有IEncodedString转换为IEncodedString 。 在我的例子中,我通过覆盖模板类中的WriteTo方法解决了这个问题:

 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); } } } 

我还没有看到这个改变是否会导致任何错误,但现在我发现这个方法将来应该相对容易改变。

编辑:检查看到Html助手返回一个MvcHtmlString,它实现了IHtmlString,所以通过向这个接口添加一个强制转换,我们可以避免对助手返回的html进行编码,同时仍然为这个方法的任何其他调用者提供安全保护。

感谢您的灵感,我将数据存储在xml中,并创建了一个不同的解决方法,而不会覆盖WriteTo方法。 我使用了一个inheritance自TemplateBase的类,并创建了两个新方法。

  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, "
"); strOut = strOut.Replace("\t", "   "); strOut = strOut.Replace("'", "'"); return new RawString(strOut); }

RazorEngine的作者Antaris提供了另一种处理这个问题的有趣方法,并解释了默认情况下没有完成的方法(尽可能减少RazorEngine依赖关系)。

以下是针对您的案例,他对相应github问题的回答的相关部分:

我认为这里最简单的方法是实现一个处理MvcHtmlString的自定义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() }; 

就个人而言,在使用他的代码之前,我已经为IHtmlString切换了IHtmlString 。 从MVC 5开始, MvcHtmlString也实现了它。 (请注意,在一些较旧的MVC版本中并非如此。)