Remove HTML helpers with `IDictionary<string, object>` parameters

- see line 2 of #874
- focus on `TextBox[For]()` and `ValidationSummary()`

related fixes included here:
- `TextArea[For]()` documentation incorrectly indicated their `htmlAttributes` parameters were dictionaries
- handle `htmlAttributes` parameters more consistently; create a dictionary only when necessary
This commit is contained in:
dougbu 2014-08-03 22:37:42 -07:00
parent c9b2323592
commit 3db0a80306
6 changed files with 62 additions and 132 deletions

View File

@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes) object htmlAttributes)
{ {
var url = _urlHelper.Action(actionName, controllerName, routeValues); var url = _urlHelper.Action(actionName, controllerName, routeValues);
return GenerateLink(linkText, url, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
} }
/// <summary> /// <summary>
@ -186,13 +186,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public MvcForm BeginForm(string actionName, string controllerName, object routeValues, FormMethod method, public MvcForm BeginForm(string actionName, string controllerName, object routeValues, FormMethod method,
object htmlAttributes) object htmlAttributes)
{ {
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null. var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
}
return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributeDictionary); return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributeDictionary);
} }
@ -427,7 +421,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes) object htmlAttributes)
{ {
var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment); var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment);
return GenerateLink(linkText, url, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
} }
/// <inheritdoc /> /// <inheritdoc />
@ -437,12 +431,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
/// <inheritdoc /> /// <inheritdoc />
public HtmlString ValidationSummary(bool excludePropertyErrors, public HtmlString ValidationSummary(
bool excludePropertyErrors,
string message, string message,
IDictionary<string, object> htmlAttributes, object htmlAttributes,
string tag) string tag)
{ {
return GenerateValidationSummary(excludePropertyErrors, message, htmlAttributes, tag); return GenerateValidationSummary(
excludePropertyErrors,
message,
GetHtmlAttributeDictionaryOrNull(htmlAttributes),
tag);
} }
/// <summary> /// <summary>
@ -476,7 +475,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
/// <inheritdoc /> /// <inheritdoc />
public HtmlString TextBox(string name, object value, string format, IDictionary<string, object> htmlAttributes) public HtmlString TextBox(string name, object value, string format, object htmlAttributes)
{ {
return GenerateTextBox(metadata: null, name: name, value: value, format: format, return GenerateTextBox(metadata: null, name: name, value: value, format: format,
htmlAttributes: htmlAttributes); htmlAttributes: htmlAttributes);
@ -563,17 +562,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
} }
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null. var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
var explicitValue = isChecked.HasValue; var explicitValue = isChecked.HasValue;
if (explicitValue && htmlAttributeDictionary != null) if (explicitValue && htmlAttributeDictionary != null)
{ {
@ -691,17 +680,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
bool useViewData, bool useViewData,
object htmlAttributes) object htmlAttributes)
{ {
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
// Special-case opaque values and arbitrary binary data. // Special-case opaque values and arbitrary binary data.
var byteArrayValue = value as byte[]; var byteArrayValue = value as byte[];
if (byteArrayValue != null) if (byteArrayValue != null)
@ -709,6 +687,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
value = Convert.ToBase64String(byteArrayValue); value = Convert.ToBase64String(byteArrayValue);
} }
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateInput(InputType.Hidden, return GenerateInput(InputType.Hidden,
metadata, metadata,
name, name,
@ -750,7 +729,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName), ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName),
IdAttributeDotReplacement)); IdAttributeDotReplacement));
tag.SetInnerText(resolvedLabelText); tag.SetInnerText(resolvedLabelText);
tag.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), replaceExisting: true); tag.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes), replaceExisting: true);
return tag.ToHtmlString(TagRenderMode.Normal); return tag.ToHtmlString(TagRenderMode.Normal);
} }
@ -794,17 +773,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
protected virtual HtmlString GeneratePassword(ModelMetadata metadata, string name, object value, protected virtual HtmlString GeneratePassword(ModelMetadata metadata, string name, object value,
object htmlAttributes) object htmlAttributes)
{ {
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null. var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
return GenerateInput(InputType.Password, return GenerateInput(InputType.Password,
metadata, metadata,
name, name,
@ -820,17 +789,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
protected virtual HtmlString GenerateRadioButton(ModelMetadata metadata, string name, object value, protected virtual HtmlString GenerateRadioButton(ModelMetadata metadata, string name, object value,
bool? isChecked, object htmlAttributes) bool? isChecked, object htmlAttributes)
{ {
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null. var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
if (metadata == null) if (metadata == null)
{ {
// RadioButton() case. Do not override checked attribute if isChecked is implicit. // RadioButton() case. Do not override checked attribute if isChecked is implicit.
@ -941,7 +900,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
{ {
InnerHtml = listItemBuilder.ToString() InnerHtml = listItemBuilder.ToString()
}; };
tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes)); tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */); tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
tagBuilder.GenerateId(fullName, IdAttributeDotReplacement); tagBuilder.GenerateId(fullName, IdAttributeDotReplacement);
if (allowMultiple) if (allowMultiple)
@ -998,7 +957,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var tagBuilder = new TagBuilder("textarea"); var tagBuilder = new TagBuilder("textarea");
tagBuilder.GenerateId(fullName, IdAttributeDotReplacement); tagBuilder.GenerateId(fullName, IdAttributeDotReplacement);
tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), true); tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes), true);
if (rows > 0) if (rows > 0)
{ {
tagBuilder.MergeAttribute("rows", rows.ToString(CultureInfo.InvariantCulture), true); tagBuilder.MergeAttribute("rows", rows.ToString(CultureInfo.InvariantCulture), true);
@ -1026,8 +985,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
protected virtual HtmlString GenerateTextBox(ModelMetadata metadata, string name, object value, string format, protected virtual HtmlString GenerateTextBox(ModelMetadata metadata, string name, object value, string format,
IDictionary<string, object> htmlAttributes) object htmlAttributes)
{ {
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateInput(InputType.Text, return GenerateInput(InputType.Text,
metadata, metadata,
name, name,
@ -1037,7 +997,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
setId: true, setId: true,
isExplicitValue: true, isExplicitValue: true,
format: format, format: format,
htmlAttributes: htmlAttributes); htmlAttributes: htmlAttributeDictionary);
} }
protected virtual HtmlString GenerateInput(InputType inputType, ModelMetadata metadata, string name, protected virtual HtmlString GenerateInput(InputType inputType, ModelMetadata metadata, string name,
@ -1189,7 +1149,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
tag = ViewContext.ValidationMessageElement; tag = ViewContext.ValidationMessageElement;
} }
var builder = new TagBuilder(tag); var builder = new TagBuilder(tag);
builder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes)); builder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
// Only the style of the span is changed according to the errors if message is null or empty. // Only the style of the span is changed according to the errors if message is null or empty.
// Otherwise the content and style is handled by the client-side validation. // Otherwise the content and style is handled by the client-side validation.
@ -1349,6 +1309,22 @@ namespace Microsoft.AspNet.Mvc.Rendering
new ClientModelValidationContext(metadata, MetadataProvider))); new ClientModelValidationContext(metadata, MetadataProvider)));
} }
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
private static IDictionary<string, object> GetHtmlAttributeDictionaryOrNull(object htmlAttributes)
{
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
return htmlAttributeDictionary;
}
private static string GetInputTypeString(InputType inputType) private static string GetInputTypeString(InputType inputType)
{ {
switch (inputType) switch (inputType)

View File

@ -206,7 +206,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <inheritdoc /> /// <inheritdoc />
public HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, public HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
string format, IDictionary<string, object> htmlAttributes) string format, object htmlAttributes)
{ {
var metadata = GetModelMetadata(expression); var metadata = GetModelMetadata(expression);
return GenerateTextBox(metadata, GetExpressionName(expression), metadata.Model, format, htmlAttributes); return GenerateTextBox(metadata, GetExpressionName(expression), metadata.Model, format, htmlAttributes);

View File

@ -144,17 +144,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
string format, string format,
object htmlAttributes) object htmlAttributes)
{ {
return htmlHelper.TextBox(name, value, format, return htmlHelper.TextBox(name, value, format, htmlAttributes);
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static HtmlString TextBox(
[NotNull] this IHtmlHelper htmlHelper,
string name,
object value,
IDictionary<string, object> htmlAttributes)
{
return htmlHelper.TextBox(name, value, format: null, htmlAttributes: htmlAttributes);
} }
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper, public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
@ -178,14 +168,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper, public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, string format, object htmlAttributes) [NotNull] Expression<Func<TModel, TProperty>> expression, string format, object htmlAttributes)
{ {
return htmlHelper.TextBoxFor(expression, format: format, return htmlHelper.TextBoxFor(expression, format: format, htmlAttributes: htmlAttributes);
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
return htmlHelper.TextBoxFor(expression, format: null, htmlAttributes: htmlAttributes);
} }
public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper,

View File

@ -138,10 +138,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
string message, string message,
object htmlAttributes) object htmlAttributes)
{ {
return htmlHelper.ValidationSummary(excludePropertyErrors: false, return htmlHelper.ValidationSummary(
message: message, excludePropertyErrors: false, message: message, htmlAttributes: htmlAttributes, tag: null);
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: null);
} }
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper, public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -149,10 +147,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes, object htmlAttributes,
string tag) string tag)
{ {
return htmlHelper.ValidationSummary(excludePropertyErrors: false, return htmlHelper.ValidationSummary(
message: message, excludePropertyErrors: false, message: message, htmlAttributes: htmlAttributes, tag: tag);
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: tag);
} }
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper, public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -171,10 +167,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
string message, string message,
object htmlAttributes) object htmlAttributes)
{ {
return htmlHelper.ValidationSummary(excludePropertyErrors, return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes, tag: null);
message,
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: null);
} }
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper, public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -183,31 +176,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes, object htmlAttributes,
string tag) string tag)
{ {
return htmlHelper.ValidationSummary(excludePropertyErrors, return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes, tag);
message,
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
string message,
IDictionary<string, object> htmlAttributes)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: htmlAttributes,
tag: null);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
string message,
IDictionary<string, object> htmlAttributes,
string tag)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: htmlAttributes,
tag: tag);
} }
} }
} }

View File

@ -414,8 +414,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// </param> /// </param>
/// <param name="rows">Number of rows in the textarea.</param> /// <param name="rows">Number of rows in the textarea.</param>
/// <param name="columns">Number of columns in the textarea.</param> /// <param name="columns">Number of columns in the textarea.</param>
/// <param name="htmlAttributes"> /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes. /// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param> /// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns> /// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes); HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes);
@ -431,11 +431,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// If non-<c>null</c>, value to include in the element. Ignore if named value is found in submitted data. /// If non-<c>null</c>, value to include in the element. Ignore if named value is found in submitted data.
/// </param> /// </param>
/// <param name="format"></param> /// <param name="format"></param>
/// <param name="htmlAttributes"> /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes. /// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param> /// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns> /// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextBox(string name, object value, string format, IDictionary<string, object> htmlAttributes); HtmlString TextBox(string name, object value, string format, object htmlAttributes);
/// <summary> /// <summary>
/// Returns the validation message if an error exists in the <see cref="ModelStateDictionary"/> object. /// Returns the validation message if an error exists in the <see cref="ModelStateDictionary"/> object.
@ -458,7 +458,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <param name="excludePropertyErrors">true to have the summary display model-level errors only, or false to /// <param name="excludePropertyErrors">true to have the summary display model-level errors only, or false to
/// have the summary display all errors.</param> /// have the summary display all errors.</param>
/// <param name="message">The message to display with the validation summary.</param> /// <param name="message">The message to display with the validation summary.</param>
/// <param name="htmlAttributes">A dictionary that contains the HTML attributes for the element.</param> /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <param name="tag">The tag to wrap the <paramref name="message"/> in the generated HTML. /// <param name="tag">The tag to wrap the <paramref name="message"/> in the generated HTML.
/// Its default value is <see cref="ViewContext.ValidationMessageElement" />.</param> /// Its default value is <see cref="ViewContext.ValidationMessageElement" />.</param>
/// <returns>An <see cref="HtmlString"/> that contains an unordered list (ul element) of validation messages. /// <returns>An <see cref="HtmlString"/> that contains an unordered list (ul element) of validation messages.
@ -466,7 +468,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString ValidationSummary( HtmlString ValidationSummary(
bool excludePropertyErrors, bool excludePropertyErrors,
string message, string message,
IDictionary<string, object> htmlAttributes, object htmlAttributes,
string tag); string tag);
/// <summary> /// <summary>

View File

@ -223,8 +223,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <param name="expression">An expression, relative to the current model.</param> /// <param name="expression">An expression, relative to the current model.</param>
/// <param name="rows">Number of rows in the textarea.</param> /// <param name="rows">Number of rows in the textarea.</param>
/// <param name="columns">Number of columns in the textarea.</param> /// <param name="columns">Number of columns in the textarea.</param>
/// <param name="htmlAttributes"> /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes. /// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param> /// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns> /// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextAreaFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, HtmlString TextAreaFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
@ -237,12 +237,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// An expression that identifies the object that contains the properties to render. /// An expression that identifies the object that contains the properties to render.
/// </param> /// </param>
/// <param name="format"></param> /// <param name="format"></param>
/// <param name="htmlAttributes"> /// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes. /// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param> /// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns> /// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, string format, HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, string format,
IDictionary<string, object> htmlAttributes); object htmlAttributes);
/// <summary> /// <summary>
/// Returns the validation message for the specified expression /// Returns the validation message for the specified expression