To render a textarea for a model property in ASP.NET MVC you usually perform a call to @Html.TextAreaFor(…):
@Html.TextAreaFor(m => m.MyProperty)
Recently I encountered the strange behavior that it always adds a new line at the beginning of the textarea. How comes?
Analysis
Note: if you just look for a workaround for this bug scroll down to “Conclusion and solution”.
Internally the TextAreaFor(…) method uses the TextAreaExtensions class in System.Web.Mvc.Html. The code responsible for generating the html output looks roughly like the following:
private static MvcHtmlString TextAreaHelper(HtmlHelper htmlHelper, ModelMetadata modelMetadata, string name, IDictionary<string, object> rowsAndColumns, IDictionary<string, object> htmlAttributes)
{
// Some initialization here...
TagBuilder tagBuilder = new TagBuilder("textarea");
// Some more logic...
tagBuilder.SetInnerText(Environment.NewLine + attemptedValue);
return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}
So, the intended output of TextAreaFor is:
<textarea>
This is the content...</textarea>
This should be fine and not add an extra new line at the beginning, right? Well, the actual html output looks like this:
<textarea> This is the content...</textarea>
There seems to be some more magic in place. And by risking a deeper look at TagBuilder.SetInnerText(…) we discover that it does a call to HttpUtility.HtmlEncode(…):
public void SetInnerText(string innerText)
{
this.InnerHtml = HttpUtility.HtmlEncode(innerText);
}
Now the pieces come together and one important fact surfaces: the bug only appears when the popular AntiXssEncoder is used as HttpEncoder. The AntiXSS encoder encodes output in views in a safer way by using a white list approach for allowed characters. Till now you had to manually include the AntiXSSEncoder in your ASP.NET MVC project, but up from the next version (ASP.NET 4.5) it is already included and can be activated via web.config.
Conclusion and solution
In contrast to the default HttpEncoder the AntiXssEncoder also encodes new line characters to “ ”, but for the browser this is not the same like just a new line in the html markup. In ASP.NET MVC4 Developer Preview (and most likely also in the soon coming stable version) this is fixed, but till then the probably easiest workaround is to create your own helper for rendering textarea markup in views:
public static MvcHtmlString FixedTextAreaFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return new MvcHtmlString(htmlHelper.TextAreaFor(expression)
.ToHtmlString()
.Replace("> ", ">" + Environment.NewLine));
}
(On demand you can just create fixed versions of TextAreaFor(…) for the other overloaded methods like in the example above.)