RazorEngine @Html helpers work, but escape the Html

人盡茶涼 提交于 2019-12-01 23:47:27

I have found a workaround for the problem I was facing. RazorEngine's base Template will automatically encode a string (or object) if it doesn't cast to an IEncodedString. In my case, I solved this issue by overriding the WriteTo method in my template class:

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

I have yet to see if this change will cause any errors, but now that I found the method it should be relatively easy to change in the future.

EDIT: Checked to see Html helpers return an MvcHtmlString, which implements IHtmlString, so by adding a cast to this interface, we can avoid encoding the html returned by the helpers, while still having a safety in place for any other callers of this method.

Antaris, author of RazorEngine, has supplied another interesting way for handling this issue, and explained by the way why it is not done by default (for reducing as much as possible RazorEngine dependencies).

Here is for your case the relevant part of his answer on the corresponding github issue:

I think the easiest thing to do here, would be to implement a custom IEncodedStringFactory which handles MvcHtmlString. Something like:

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

This would enable existing MvcHtmlString instances to bypass RazorEngine's built in encoding mechanism. This would not be part of the base library because we don't take any dependencies on System.Web, or System.Web.Mvc.

You would need to wire this up via your configuration:

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

Personally, I have switched MvcHtmlString for IHtmlString before using his code. As of MVC 5, MvcHtmlString does implement it too. (Beware, it was not the case in some older MVC version.)

Thanks for the inspiration, I had my data stored in a xml and created a different workaround without overwriting the WriteTo method. I used a class that inherited from the TemplateBase and created 2 new methods.

    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);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!