【问题标题】:RazorEngine @Html helpers work, but escape the HtmlRazorEngine @Html 助手工作,但逃避 Html
【发布时间】:2013-10-17 15:47:05
【问题描述】:

我正在使用 RazorEngine 从网页上的 html sn-ps 解析模板。 (这是一个遗留系统,无法切换到 Mvc Razor 视图,因此我们将小部分切换为在有意义的情况下使用 RazorEngine)。 SO和互联网上有很多问题试图让Mvc的Html和Url助手与Razor引擎一起工作。为了让@Html 语法正常工作,我修改了一些找到here 的代码,将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?

【问题讨论】:

  • 您可能应该使用 MVC/Razor 基本类型,而不是 RazorEngine 的基本类型。
  • @SLaks,我将研究使用WebViewPage,但它可能比弄清楚如何正确构造它更麻烦,因为 MVC 通常会处理它。此外,我将不得不在这个新的子类上重新实现 RazorEngine ITemplate。我将继续寻求解决最初的问题,因为我真的不知道哪个会更努力。

标签: c# razor razorengine


【解决方案1】:

我找到了解决我所面临问题的方法。如果 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 助手返回一个 MvcHtmlString,它实现了 IHtmlString,所以通过向这个接口添加强制转换,我们可以避免对助手返回的 html 进行编码,同时仍然具有安全性为该方法的任何其他调用者准备好。

【讨论】:

  • MvcHtmlString 并不总是实现IHtmlString,请注意这一点。它在 MVC 5 中实现它,但在一些较旧的 MVC 版本中没有实现(支持 fx 3.5 的版本,其中 IHtmlString 不可用)。
  • 使用 WriteTo 覆盖 Html.BeginForm() 输出仍然是编码的 (stackoverflow.com/questions/41531298/…) 。我们是否也应该覆盖其他 Write 方法?
【解决方案2】:

RazorEngine 的作者 Antaris 提供了另一种有趣的方式来处理这个问题,并解释了为什么默认情况下不这样做(为了尽可能减少 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.Web,或System.Web.Mvc

您需要通过您的配置将其连接起来:

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

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

【讨论】:

    【解决方案3】:

    感谢您的启发,我将数据存储在 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);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-23
      相关资源
      最近更新 更多