Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MvcHtmlString still gets HtmlEncoded #1

Closed
icrf opened this issue Nov 18, 2011 · 2 comments
Closed

MvcHtmlString still gets HtmlEncoded #1

icrf opened this issue Nov 18, 2011 · 2 comments
Labels

Comments

@icrf
Copy link

icrf commented Nov 18, 2011

I'm sharing a partial view with a full MVC3 view and a RazorEngine template. It needs to be strongly typed, so I pulled the latest from github this morning to get support for @model.

The problem is my view has an HtmlHelper in it that returns an MvcHtmlString. I have the helper working fine (cobbled together below, will change to MvcTemplateBase if that makes the cut), but the problem is RazorEngine is escaping it and I'm seeing raw HTML in the result. RazorEngine 2.1 did not do this. Any idea where I should look?

This is the basic code I'm using:

public string SomeMethod<T>(string templateDocument, T model)
{
    //Razor.SetTemplateBase(typeof(MyCustomTemplateBase<>));
    var config = new TemplateServiceConfiguration
    {
        BaseTemplateType = typeof(MyCustomTemplateBase<>)
    };

    using (var service = new TemplateService(config))
    {
        try
        {
            return service.Parse(templateDocument, model);
        }
        catch (TemplateCompilationException ex)
        {
            // exception says "see errors" but the errors aren't actually caught and logged automatically
            throw new Exception(string.Join("\n", ex.Errors), ex);
        }
    }
}

public abstract class MyCustomTemplateBase<T> : TemplateBase<T>
{
    public TemplateWriter RenderPart<T>(string path, T model = default(T))
    {
        var text = System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath(path));
        var tmpl = this.TemplateService.GetTemplate(text, model, path);
        return this.Include(path, model);
        //return RazorEngine.Razor.Parse(System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath(path)), model);
    }

    private HtmlHelper _Html = null;
    public HtmlHelper Html
    {
        get
        {
            if (this._Html == null)
            {
                var container = new InternalViewDataContainer<T>(this.Model);
                var context = new ViewContext(
                    new ControllerContext(),
                    new InternalView(),
                    new ViewDataDictionary(),
                    new TempDataDictionary(),
                    new System.IO.StringWriter(new System.Text.StringBuilder()));
                this._Html = new HtmlHelper<T>(context, container);
            }
            return this._Html;
        }
    }

    private class InternalView : IView
    {
        public void Render(ViewContext context, System.IO.TextWriter writer) { }
    }

    private class InternalViewDataContainer<T> : IViewDataContainer
    {
        public InternalViewDataContainer(T model)
        {
            ViewData = new ViewDataDictionary<T>(model);
        }
        public ViewDataDictionary ViewData { get; set; }
    }
}
@Antaris
Copy link
Owner

Antaris commented Nov 18, 2011

My intention with MvcTemplateBase is to introduce a standardised base template that allows integration with MVC (so you can use the same views, etc), and also to automatically translate between MvcHtmlString and IEncodedString instances. 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()
};

@icrf
Copy link
Author

icrf commented Nov 19, 2011

That works beautifully. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants