According to https://blog.cindypotvin.com/character-encodings-with-razor-helpers/ and some other resources #Helper blocks return a HelperResult class that Implements IHtmlString.
Being and HtmlString all the string inside the #helper blocks should not be encoded.
But I have the following scenario (the real scenario is more complex) where the html is encoded
#helper Test(){
#(new HtmlString("<label>Test 1</label>"))
#(new HtmlString("<label>Test 2</label>"))
}
When I check the view in browser I see literally <label> Test 1 .... because the Html code generate inside the #helper Test is between quotes.
But adding a RawString then it works correctly.
#helper Test(){
#(new RawString(new HtmlString("<label>Test 1</label>").ToString()))
#(new RawString(new HtmlString("<label>Test 2</label>").ToString()))
}
Taking into account that HtmlString it´s for Razor to not encode a string and #Helper returns HtmlString, I don´t get why I need to add RawString to render correctly the html code on browser.
This looks like a matter of incorrect expectations and/or interpretations...
A #helper method renders its output to an output stream, resulting in a plain text string. That string may contain HTML, and if so, then that HTML may or may not have been HTML encoded along the way (depending on how the helper was written). The resulting plain text string is then returned inside an IHtmlString wrapper object.
If an IHtmlString object is rendered using #(...), to Razor this means 'don't HTML-encode this, that was done already if/when/where needed'.
In short, doing #Test() sends the exact string content without further encoding to the browser (which then interprets it). If your aim was to encode it, then you could use #(Test().ToString()) because that pulls the string out of its IHtmlString protective cover, and then it will be HTML-Encoded.
If you inspect Test().ToString() then you can see the plain-text content, which for your Test() will look like "<label>...</label><label>...</label>". There's not a trace of the original HtmlString objects that you used, they were all rendered, and nothing was HTML-Encoded because you used #(new HtmlString(...)) for each.
It may be worth noting that these three #helper methods all have exactly the same output (except perhaps for some whitespace):
#helper Test()
{
<label>Test</label>
}
#helper Test()
{
#(new HtmlString("<label>Test</label>"))
}
#helper Test()
{
#(Html.Raw("<label>Test</label>"))
}
The result for all of these is the plain string "<label>Test</label>" wrapped as an IHtmlString.
Finally, if you would WANT the <label> to be HTML-Encoded, then this is what you'd need to use:
#helper Test()
{
#("<label>Test</label>")
}
The result of this is the plain string "<label>Test</label>" wrapped as an IHtmlString.
Related
I'm writing an html helper extension for MVC5.
I need to access the ViewContext's stream to edit it.
(like a textreader)
htmlHelper.ViewContext.Writer.Write("<div>");
Is there any way to access the stream; so that I can manipulate or add some html code above the last "div" tag in the example ?
I was not able to find any clue about at where I can find the stream that textwriter writes to?
It depends on what view engine you are using but if you write an html helper, it will be a lot easier. See Creating Custom HTML Helpers
Simple html helpers can be written like this:
#helper CustomDiv(var param1, var param2){
Write("something to html encode & stuff");
WriteLiteral("<div>something that is html</div>");
}
In Razor, You can also just call #Write() and it will encode the string to HTML. If you need a TextWriter, reference Context.Response.Output but this will not allow you to manipulate the HTML inline like an HtmlHelper does - it's intended more for overriding the normal handler.
or just the Output property of WebPageBase which is also a TextWriter
I am experimenting with custom HtmlHelpers, but can't get even a basic one to work correctly. My code (just for testing sake) looks like this -
My class -
namespace HtmlHelpers.Extensions
{
public static class Helpers
{
public static string MySubmitButton(this HtmlHelper helper)
{
return String.Format("<input type=\"submit\" value=\"Submit This\">");
}
}
}
In my view -
#using HtmlHelpers.Extensions;
#Html.MySubmitButton()
This I believe should generate a simple submit button, but instead, it justs writes the following text to the screen -
<input type="submit" value="Submit">
I inspected the element, and for some reason the entire input element is being surrounded with double quotes.
Anyone know why? Thanks!
I believe you should be returning a MvcHtmlString class. Try
public static MvcHtmlString MySubmitButton(this HtmlHelper helper)
{
return MvcHtmlString.Create("<input type=\"submit\" value=\"Submit This\">");
}
although there's probably better ways to do this using a TagBuilder if you look at examples online, or the MVC source code since it's open source, you can look at their html helpers(although they are pretty complicated due to the way they layer them).
To directly answer your question of "why" it was displaying that as if it were a string, is Razor tries to be safe and convert anything you display as text instead of HTML/script. For example, #Model.PeronName will escape any characters in the peron's name with HTML character codes. Consider if there was no protection like this, and one of your users changed their name to be <script>someDangerousJavascriptThatWouldChangeCurrentUsersPassword()</script>, then posted on your forum or anywhere their name would appear, then other users visit the page, and that javascript runs and POSTS a change password form for that current user's password to some password that the hacker chose in the script. There are a wide variety of complicated attacks like this, or users might accidentally enter angle brackets(and while fairly harmless if treated as HTML they will mess up your page display).
For that reason MVC will assume just about any string is not HTML and thus replace things like <script> with <script> which basically is a way of saying "this is not html/script, I want you to display the less-than symbol and greater than symbol". If you wanted to display something as HTML, there is a #Html.Raw() helper for that, and it won't clean output, and thus should never be used with a string that you concatenated together from any data that a user my supply.
Part of my MVC application includes a wiki. As well as the standard wiki formatting there are a number of special tags for rendering data into templates. When parsing these tags it gets the data from the repository, instantiates a viewmodel and renders it to a partial, this partial then gets inserted into the markup replacing the original tag. The finalised markup itself is rendered as part of a DisplayFor in any properties with the relevant UIHint.
The relevant part of the code is:
private static void MatchSpecial(WikiHelper wh)
{
wh.match = SpecialTagRegex.Match(wh.sb.ToString());
while (wh.match.Success)
{
wh.sb.Remove(wh.match.Index, wh.match.Length);
string[] args = wh.match.Groups[2].Value.Split('|');
switch (wh.match.Groups[1].Value.ToUpperInvariant())
{
case "IMAGE":
string imageid;
imageid = args[0];
Image i = baserepo.imagerepo.GetImage(imageid);
ViewModels.ImageViewModel ivm = new ViewModels.ImageViewModel(i, args);
wh.sb.Insert(wh.match.Index, wh.Html.Partial("ImageViewModel",ivm));
break;
}
wh.match = SpecialTagRegex.Match(wh.sb.ToString(), ws.end);
}
}
The relevant members of WikiHelper are:
wh.sb - StringBuilder containing the markup
wh.html - the HtmlHelper from the main view
wh.match - holds the current regex matches
In MVC2 this worked fine. I'm now in the process of upgrading to MVC3 and the Razor ViewEngine. Despite the fact that Html.Partial is supposed to return the MvcHtmlString of the partial it is instead returning an empty string and writing the content directly into the response, which has the result of all similarly templated elements appearing at the very top of the HTML file (even before anything in my layout file).
Given the symptoms you are describing, I suspect that you are directly writing to the response stream somewhere in your custom helpers. So wherever you are outputing to the response make sure you replace:
htmlHelper.ViewContext.HttpContext.Response.Write("some string");
with:
htmlHelper.ViewContext.Writer.Write("some string");
Writing directly to the response stream worked in WebForms view engine because it is legacy from classic WebForms where this was how things were supposed to work. In ASP.NET MVC though this is incorrect. It worked but is incorrect. All helpers should be writing to ViewContext.Writer instead. Razor writes things into temporary buffers which are then flushed to the response. It uses an inside-out rendering.
I take user input into a text area, store it and eventually display it back to the user.
In my View (Razor) I want to do something like this...
#Message.Replace("\n", "</br>")
This doesn't work because Razor Html Encodes by default. This is great but I want my line breaks.
If I do this I get opened up to XSS problems.
#Html.Raw(Message.Replace("\n", "</br>"))
What's the right way to handle this situation?
Use HttpUtility.HtmlEncode then do the replace.
#Html.Raw(HttpUtility.HtmlEncode(Message).Replace("\n", "<br/>"))
If you find yourself using this more than once it may be helpful to wrap it in a custom HtmlHelper like this:
namespace Helpers
{
public static class ExtensionMethods
{
public static IHtmlString PreserveNewLines(this HtmlHelper htmlHelper, string message)
{
return message == null ? null : htmlHelper.Raw(htmlHelper.Encode(message).Replace("\n", "<br/>"));
}
}
}
You'll then be able to use your custom HtmlHelper like this:
#Html.PreserveNewLines(Message)
Keep in mind that you'll need to add a using to your Helpers namespace for the HtmlHelper to be available.
You can encode your message, then display it raw. Something like:
#Html.Raw(Server.HtmlEncode(Message).Replace("\n", "<br/>"))
For those who use AntiXssEncoder.HtmlEncode
As AntiXssEncoder.HtmlEncode encode the /r/n character to
so the statement should be
_mDraftMsgModel.wnItem.Description = AntiXssEncoder.HtmlEncode(draftModel.txtMsgContent, false).Replace("
", "<br/>");
In my case, my string contained html that I wanted to encode but I also wanted the HTML line breaks to remain in place. The code below turns the HTML line breaks in to \n then encodes everything. It then turns all instances of \n back in to HTML line breaks:
#Html.Raw(HttpUtility.HtmlEncode(message.Replace("<br/>", "\n").Replace("<br />", "\n")).Replace("\n", "<br/>"))
In an ASP.NET MVC view I'd like to include a link of the form:
Link text <span>with further descriptive text</span>
Trying to include the <span> element in the linkText field of a call to Html.ActionLink() ends up with it being encoded (as would be expected).
Are there any recommended ways of achieving this?
You could use Url.Action to build the link for you:
link text <span>with further blablah</span>
or use Html.BuildUrlFromExpression:
text <span>text</span>
if you like using Razor, this should work:
link text <span>with further blablah</span>
Another option is to render your action link to an MvcHtmlString as per normal, using either HTML.ActionLink, or Ajax.ActionLink (depending on your context), then write a class that takes the rendered MvcHtmlString and hacks your html link text directly into the already rendered MvcHtmlString, and returns another MvcHtmlString.
So this is the class that does that: [please note that the insertion/substitution code is VERY simple, and you may need to beef it up to handle more nested html]
namespace Bonk.Framework
{
public class CustomHTML
{
static public MvcHtmlString AddLinkText(MvcHtmlString htmlString, string linkText)
{
string raw = htmlString.ToString();
string left = raw.Substring(0, raw.IndexOf(">") + 1);
string right = raw.Substring(raw.LastIndexOf("<"));
string composed = left + linkText + right;
return new MvcHtmlString(composed);
}
}
}
And then you would use it in the view like this:
#Bonk.Framework.CustomHTML.AddLinkText(Ajax.ActionLink("text to be replaced", "DeleteNotificationCorporateRecipient"), #"Link text <span>with further descriptive text</span>")
This approach has the advantage of not having to reproduce/understand the tag-rendering process.