RazorEngine @Html助手工作,但转义 Html
本文关键字:转义 Html 工作 @Html RazorEngine | 更新日期: 2023-09-27 18:35:52
我正在使用RazorEngine从网页上的html片段中解析模板。(这是一个旧系统,无法切换到 Mvc Razor 视图,因此我们将小部分切换到有意义的使用 RazorEngine)。关于SO和互联网上有很多问题试图让Mvc的HTML和URL助手与Razor引擎一起工作。为了使@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 是:
<label for="MyNumber">MyNumber</label>
当它显然应该是:
<label for="MyNumber">MyNumber</label>
我对如何解决这个问题感到困惑。在查看RazorEngine源代码时,我无法找到编码是如何发生的。我最初的想法是文本编写器必须对值进行编码,但我无法确认这一点。如何让@Html.BlahFor()
呈现未转义的 html?
我已经找到了解决我面临的问题的解决方法。RazorEngine 的基本模板将自动对字符串(或对象)进行编码,如果它没有强制转换为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 帮助程序返回实现 IHtmlString 的 MvcHtmlString,因此通过向此接口添加强制转换,我们可以避免对帮助程序返回的 html 进行编码,同时仍然为此方法的任何其他调用者提供安全性。
作者Antaris提供了另一种有趣的方法来处理这个问题,并解释了为什么默认情况下不这样做(为了尽可能减少RazorEngine的依赖性)。
以下是他关于相应 github 问题的回答的相关部分:
我认为最简单的 这里要做的事情是实现自定义
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.Web
,或System.Web.Mvc
。您需要通过配置将其连接起来:
var config = new TemplateServiceConfiguration() { BaseTemplateType = typeof(MvcTemplateBase<>), EncodedStringFactory = new MvcHtmlStringFactory() };
就个人而言,在使用他的代码之前,我已经将MvcHtmlString
切换为IHtmlString
。从MVC 5开始,MvcHtmlString
也实现了它。(请注意,在某些较旧的 MVC 版本中并非如此。
感谢您的启发,我将数据存储在 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", " ");
strOut = strOut.Replace("'", "'");
return new RawString(strOut);
}