RazorEngine @Html helpers work, but escape the Html

戏子无情 提交于 2019-12-02 02:12:36

问题


I am using RazorEngine to parse templates from html snippets on a web page. (This is a legacy system that switching to Mvc Razor views isn't possible, so we are switching small sections over to using RazorEngine where it makes sense). There are many of questions on SO and the internet trying to get Mvc's Html and Url helpers to work with Razor engine. To get @Html syntax to work, I've modified some code found here to add Html to the base template:

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

After a lot of debugging into the Html source code I think I've managed to instantiate everything that the Html helper needs, and it runs successfully for @Html.Label... The problem is that the resulting html is:

&lt;label for=&quot;MyNumber&quot;&gt;MyNumber&lt;/label&gt;

When it obviously should be:

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

I am stumped as to how to fix this. I was not able to find how the encoding happens when looking through the RazorEngine source. My initial thought was that the TextWriter must be encoding the value but I have not been able to confirm this. How can I get @Html.BlahFor() to render un-escaped html?


回答1:


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.




回答2:


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.)




回答3:


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


来源:https://stackoverflow.com/questions/19431365/razorengine-html-helpers-work-but-escape-the-html

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