I wish to encode my HTML sent to the browser. In my .ASPX pages I can use the <%: %> syntax. In a HTML helper of mine I try...
public static string Image(this HtmlHelper helper, string imageName, string altText)
{
return helper.Encode(String.Format("<image src='/images/{0}' alt='{1}' />", imageName, altText));
}
However, when the HTML reaches the browser the HTML just displays as text and no image is shown. How does one encode their HTML from a helper method?
remove the "helper.Encode"
public static String MyImg(this HtmlHelper helper, string imageName, string altText) {
return String.Format("<image src='/images/{0}' alt='{1}' />", imageName, altText);
}
Related
I created an extension method based on this answer to the SO question c# - How can I create a Html Helper like Html.BeginForm - Stack Overflow and it works fine.
Can I move the embedded HTML in the extension method into a partial view and use that partial view in the method while preserving it's current behavior? In particular, I want to be able to 'wrap' a block of arbitrary HTML.
I ask not out of any pressing need, but simply out of a desire to maintain HTML consistently, e.g. as views and partial views. I imagine it will be a lot easier to spot any problems with the HTML if it's in a view or partial view too.
Here's the HtmlHelper extension method:
public static IDisposable HelpTextMessage(this HtmlHelper helper, bool isHidden, string heading)
{
TextWriter writer = helper.ViewContext.Writer;
writer.WriteLine(
String.Format(
"<div class=\"help-text {0}\">",
isHidden ? "help-text-hidden" : ""));
writer.WriteLine(
String.Format(
"<div class=\"help-text-heading\">{0}</div>",
heading));
writer.Write("<div class=\"help-text-body\">");
return new HelpTextMessageContainer(writer);
}
Here's the HelpTextMessageContainer class:
private class HelpTextMessageContainer : IDisposable
{
private readonly TextWriter _writer;
public HelpTextMessageContainer(TextWriter writer)
{
_writer = writer;
}
public void Dispose()
{
_writer.Write("</div></div>");
}
}
In a view, I can use the extension method like this:
#using(Html.HelpTextMessage(Model.HelpText.IsHelpTextHidden(Model.SomeHelpMessage), "Something"))
{
#:To do something, first do something-more-specific, then do another-something-more-specific.
}
Or I could use it like this too:
#using(Html.HelpTextMessage(Model.HelpText.IsHelpTextHidden(Model.SomeHelpMessage), "Something"))
{
<p>To do something, first do something-more-specific, then do another-something-more-specific.</p>
<p>Also, keep in mind that you might need to do something-else-entirely if blah-blah-blah.</p>
}
I haven't found any way to move the "embedded HTML" into a partial view exactly, but a slightly more-friendly way to encapsulate the HTML in a way that provides HTML and Razor syntax highlighting and Intellisense is to move into a view helper function in a file under the app App_Code folder as described in this post on "Hugo Bonacci's Blog".
Here's my helper function:
#helper HelpTextMessage(bool isHidden, string heading, Func<object, object> content)
{
<div class="help-text #(isHidden ? "help-text-hidden" : "")">
<div class="help-text-heading">
#heading
</div>
<div class="help-text-body">
#content(null)
</div>
</div>
}
Assuming the above helper function is in a file named ViewHelpers.cshtml in the App_Code folder, it can be called in a view like this:
#ViewHelpers.HelpTextMessage(false, "Something",
#:To do something, first do something-more-specific, then do another-something-more-specific.
)
or this:
#ViewHelpers.HelpTextMessage(false, "Something",
<p>To do something, first do something-more-specific, then do another-something-more-specific.</p>
<p>Also, keep in mind that you might need to do something-else-entirely if blah-blah-blah.</p>
)
I like having the embedded HTML in a view more than I do being able to use the #using(Html.HelpTextMessage(...){ ... } syntax, so I'm pretty happy with this as a solution.
i'm trying to display an image in my view.
i've written an Image helper:
public static class Helpers
{
public static FileContentResult Image(this HtmlHelper htmlHelper,
byte[] imageData, string mimeType)
{
return new FileContentResult(imageData, mimeType);
}
}
myImage - is a byte array.
<img src="#Html.Image(myImage, "image/jpeg")" />
but my image is not displayed...
when i look at the source code all i see is:
<img src="System.Web.Mvc.FileContentResult">
anyone? :)
The way you are doing it you are returning the FileContentResult in between the quotes of the src="".
I see what you are trying to do, but in order for this to work, the <img src=> needs to request the URL of the image not simply put the byte[] in the src. So you'll need to set up an action method that takes in some parameter and returns the FileContentResult.
Is it possible to put a HTML link in validation summary message? For example I want to put a link to another page in case there is validation error:
#Html.ValidationSummary(False, "read more")
or
#Html.ValidationSummary(False, "read " &
Html.ActionLink("more", "helpforerror").ToHtmlString)
But in the browser the tag is escaped so it doesn't form a link.
I know you have accepted an answer, but i think my solution is more simple and will require less rewriting if you want to add links to existing validation summaries.
You need to put a {0} type format item in your validation message like below, which will be replaced by your link.
ModelState.AddModelError("", "Some error message with a link here {0}.");
then in your view call your validation summary like so:
#string.Format(Html.ValidationSummary().ToString(), Html.ActionLink("Click Here", "Action_To_Link_To")).ToHtmlString()
In this case i have used an extension method I added to the string object .ToHtmlString() that basically just converts the string to an HtmlString preventing any of the markup being escaped. it looks like this:
public static HtmlString ToHtmlString(this String str)
{
return new HtmlString(str);
}
Finally I chose another way to do it: create a div containing the link etc. outside of validation summary, and add the div only if modelstate is not valid:
#If Not ViewData.ModelState.IsValid Then
#<div>read more</div>
End If
This is inspired by an answer to similar question.
The validation text is encoded before the ValidationSumary or ValidationFor, etc...
you just need tu decode the html, then create an MvcHtmlString ...
Exemple :
#HttpUtility.HtmlDecode(Html.ValidationSummary().ToString()).ToMvcHtmlString()
this is an extension i have made to make MvcHtmlString :
namespace System
{
public static class StringExtension
{
public static System.Web.Mvc.MvcHtmlString ToMvcHtmlString(this string value)
{
return System.Web.Mvc.MvcHtmlString.Create(value);
}
}
}
or you can create an HtmlHelper if you plan to reuse this:
namespace System.Web.Mvc.Html
{
public static class FormHelper
{
public static MvcHtmlString ValidationSummaryEx(this HtmlHelper htmlHelper, bool excludePropertyErrors)
{
var original = htmlHelper.ValidationSummary(excludePropertyErrors);
var decoded = HttpUtility.HtmlDecode(original.ToString());
return decoded.ToMvcHtmlString();
}
}
}
Hope it help you or future viewer.
Note: it work for all validations Summary and ValidationFor ...
No, the default behaviour doesn't allow it, but you can make your own. This is what you need: Html raw in validationsummary
You can check if form is valid by jquery and update div with link text:
<div id="divToUpdate">
</div>
$('form').submit(function(){
if(!this.valid())
$('#divToUpdate').html("read <a href='anotherpage.html'>more</a>");
});
If you're sending back HTML in the ModelStateError, you can use this one liner:
#Html.Raw(HttpUtility.HtmlDecode(Html.ValidationSummary().ToHtmlString()))
It's very similar to what #Benoit had suggested, just without needing the extension.
Embarrassingly newbie question:
I have a string field in my model that contains line breaks.
#Html.DisplayFor(x => x.MultiLineText)
does not display the line breaks.
Obviously I could do some fiddling in the model and create another field that replaces \n with <br/>, but that seems kludgy. What's the textbook way to make this work?
A HtmlHelper extension method to display string values with line breaks:
public static MvcHtmlString DisplayWithBreaksFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var model = html.Encode(metadata.Model).Replace("\r\n", "<br />\r\n");
if (String.IsNullOrEmpty(model))
return MvcHtmlString.Empty;
return MvcHtmlString.Create(model);
}
And then you can use the following syntax:
#Html.DisplayWithBreaksFor(m => m.MultiLineField)
i recommend formatting the output with css instead of using cpu consuming server side strings manipulation like .replace,
just add this style property to render multiline texts :
.multiline
{
white-space: pre-wrap;
}
then
<div class="multiline">
my
multiline
text
</div>
newlines will render like br elements, test it here https://refork.codicode.com/xaf4
In your view, you can try something like
#Html.Raw(Html.Encode(Model.MultiLineText).Replace("\n", "<br />"))
The display template is probably the best solution but there is another easy option of using an html helper if you know you're just displaying a string, e.g.:
namespace Shaul.Web.Helpers
{
public static class HtmlHelpers
{
public static IHtmlString ReplaceBreaks(this HtmlHelper helper, string str)
{
return MvcHtmlString.Create(str.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None).Aggregate((a, b) => a + "<br />" + b));
}
}
}
And then you'd use it like:
#using Shaul.Web.Helpers
#Html.ReplaceBreaks(Model.MultiLineText)
You create a display template for your data.
Here's a post detailing how to do it.
How do I create a MVC Razor template for DisplayFor()
In that template you do the actual translating of newlines into and whatever other work needs to be done for presentation.
Inspired by DisplayTemplates for common DataTypes,
I override (introduce?) a default DisplayTemplate for DataType.MultilineText, /Views/Shared/DisplayTemplates/MultilineText.cshtml containing just this line:
<span style="white-space: pre-wrap">#this.Model</span>
(Of course you could replace this style, by a css-class, or replace newlines inside the view, if you prefer that.)
I guess this template is automatically resolved, because I had no need for UIHint or any other reference or registration.
Using the DisplayTemplate instead of introducing a HtmlHelper-method has the advantage, that it trickles down to properties and views that are not explicitly defined.
E.g. DisplayFor(MyClassWithMultilineProperties) will now also correctly display MyClassWithMultilineProperties.MyMultilineTextProperty, if the property was annotated with [DataType(DataType.MultilineText)].
Try using
#Html.Raw("<p>" + Html.LabelFor(x => x.Name) + "</p>")
Here's another extension method option.
public static IHtmlString DisplayFormattedFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, string>> expression)
{
string value = Convert.ToString(ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model);
if (string.IsNullOrWhiteSpace(value))
{
return MvcHtmlString.Empty;
}
value = string.Join("<br/>", value.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Select(HttpUtility.HtmlEncode));
return new HtmlString(value);
}
I had this problem with ASP.NET Core 6. The previous answers here did not work with a linq expression in Html.DisplayFor. Instead I was constantly getting the <br/> tag escaped out in the output HTML. Trying HtmlString helper methods suggestions did not work.
The following solution was discovered through trial and error. The InfoString had CRLF replaced with the <br/> tags as shown in the property code.
Works
#Html.Raw(#Convert.ToString(item.InfoString))
Did not work
#Html.DisplayFor(modelItem => item.InfoString)
FYI - my Info String property:
public string InfoString
{
get { return MyInfo.Replace(Environment.NewLine,"<br />"); }
}
I'm creating a custom helper to automate some code in my application. I'd like now how display a control in my helper. When I return the GetHTML() method, the page display the HTML like a plain text. When I use the Render() method the control is rendere in body, out of order.
public static string EntityForm(this HtmlHelper helper, Type TypeModel)
{
return "My Helper" + DevExpress.Web.Mvc.UI.ExtensionsFactory.Instance.TextBox(settings =>
{
settings.Name = att.Nome;
}).GetHtml()
}
Use HtmlString, this way it does not encode the output.
Example from inside a view
#(new HtmlString("<div>some html</div>"))
Changing your Html Helper
Try changing your method to the following:
public static HtmlString EntityForm(this HtmlHelper helper, Type TypeModel)
{
var html = "My Helper" + DevExpress.Web.Mvc.UI.ExtensionsFactory.Instance.TextBox(settings =>
{
settings.Name = att.Nome;
}).GetHtml();
return new HtmlString(html);
}
Razor will escape all strings written to the page.
You need to change your helper method to return an HtmlString so that Razor won't escape it.