diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs
index 5cfba3228b..ba04cf35a1 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs
@@ -55,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
foreach (var item in TriStateValues(value))
{
var encodedText = html.Encode(item.Text);
- var option = HtmlHelper.GenerateOption(item, encodedText);
+ var option = DefaultHtmlGenerator.GenerateOption(item, encodedText);
builder.Append(option);
}
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs
index e52d226334..4c63fe1407 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs
@@ -26,8 +26,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
private readonly IModelMetadataProvider _metadataProvider;
private readonly IUrlHelper _urlHelper;
- public string IdAttributeDotReplacement { get; set; }
-
///
/// Initializes a new instance of the class.
///
@@ -43,6 +41,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
_urlHelper = urlHelper;
}
+ ///
+ public string IdAttributeDotReplacement { get; set; }
+
///
public string Encode(string value)
{
@@ -252,32 +253,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return tagBuilder;
}
- ///
- public virtual TagBuilder GenerateOption(SelectListItem item, string encodedText)
- {
- var tagBuilder = new TagBuilder("option")
- {
- InnerHtml = encodedText,
- };
-
- if (item.Value != null)
- {
- tagBuilder.Attributes["value"] = item.Value;
- }
-
- if (item.Selected)
- {
- tagBuilder.Attributes["selected"] = "selected";
- }
-
- if (item.Disabled)
- {
- tagBuilder.Attributes["disabled"] = "disabled";
- }
-
- return tagBuilder;
- }
-
///
public virtual TagBuilder GeneratePassword(
[NotNull] ViewContext viewContext,
@@ -725,6 +700,56 @@ namespace Microsoft.AspNet.Mvc.Rendering
new ClientModelValidationContext(metadata, _metadataProvider)));
}
+ internal static string EvalString(ViewContext viewContext, string key, string format)
+ {
+ return Convert.ToString(viewContext.ViewData.Eval(key, format), CultureInfo.CurrentCulture);
+ }
+
+ ///
+ /// Not used directly in HtmlHelper. Exposed for use in DefaultDisplayTemplates.
+ ///
+ internal static TagBuilder GenerateOption(SelectListItem item, string encodedText)
+ {
+ var tagBuilder = new TagBuilder("option")
+ {
+ InnerHtml = encodedText,
+ };
+
+ if (item.Value != null)
+ {
+ tagBuilder.Attributes["value"] = item.Value;
+ }
+
+ if (item.Selected)
+ {
+ tagBuilder.Attributes["selected"] = "selected";
+ }
+
+ if (item.Disabled)
+ {
+ tagBuilder.Attributes["disabled"] = "disabled";
+ }
+
+ return tagBuilder;
+ }
+
+ internal static string GetFullHtmlFieldName(ViewContext viewContext, string name)
+ {
+ var fullName = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
+ return fullName;
+ }
+
+ internal static object GetModelStateValue(ViewContext viewContext, string key, Type destinationType)
+ {
+ ModelState modelState;
+ if (viewContext.ViewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null)
+ {
+ return modelState.Value.ConvertTo(destinationType, culture: null);
+ }
+
+ return null;
+ }
+
protected virtual TagBuilder GenerateInput(
[NotNull] ViewContext viewContext,
InputType inputType,
@@ -843,6 +868,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
return tagBuilder;
}
+ // Only render attributes if client-side validation is enabled, and then only if we've
+ // never rendered validation for a field with this name in this form.
protected virtual IDictionary GetValidationAttributes(
ViewContext viewContext,
ModelMetadata metadata,
@@ -876,13 +903,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return Convert.ToString(viewContext.ViewData.Eval(key), CultureInfo.CurrentCulture);
}
- // Only render attributes if client-side validation is enabled, and then only if we've
- // never rendered validation for a field with this name in this form.
- private static string EvalString(ViewContext viewContext, string key, string format)
- {
- return Convert.ToString(viewContext.ViewData.Eval(key, format), CultureInfo.CurrentCulture);
- }
-
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
private static IDictionary GetHtmlAttributeDictionaryOrNull(object htmlAttributes)
{
@@ -899,12 +919,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return htmlAttributeDictionary;
}
- private static string GetFullHtmlFieldName(ViewContext viewContext, string name)
- {
- var fullName = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
- return fullName;
- }
-
private static string GetInputTypeString(InputType inputType)
{
switch (inputType)
@@ -924,17 +938,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
}
- private static object GetModelStateValue(ViewContext viewContext, string key, Type destinationType)
- {
- ModelState modelState;
- if (viewContext.ViewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null)
- {
- return modelState.Value.ConvertTo(destinationType, culture: null);
- }
-
- return null;
- }
-
private static IEnumerable GetSelectListItems([NotNull] ViewContext viewContext, string name)
{
var value = viewContext.ViewData.Eval(name);
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
index 68c26b196a..69ae036396 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
@@ -2,13 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
using System.Linq;
-using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
@@ -29,12 +26,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
public static readonly string ValidationSummaryCssClassName = "validation-summary-errors";
public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";
- private const string HiddenListItem = @"";
-
- private readonly IUrlHelper _urlHelper;
+ private readonly IHtmlGenerator _htmlGenerator;
private readonly ICompositeViewEngine _viewEngine;
- private readonly AntiForgery _antiForgeryInstance;
- private readonly IActionBindingContextProvider _actionBindingContextProvider;
private ViewContext _viewContext;
@@ -42,17 +35,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// Initializes a new instance of the class.
///
public HtmlHelper(
+ [NotNull] IHtmlGenerator htmlGenerator,
[NotNull] ICompositeViewEngine viewEngine,
- [NotNull] IModelMetadataProvider metadataProvider,
- [NotNull] IUrlHelper urlHelper,
- [NotNull] AntiForgery antiForgeryInstance,
- [NotNull] IActionBindingContextProvider actionBindingContextProvider)
+ [NotNull] IModelMetadataProvider metadataProvider)
{
_viewEngine = viewEngine;
+ _htmlGenerator = htmlGenerator;
MetadataProvider = metadataProvider;
- _urlHelper = urlHelper;
- _antiForgeryInstance = antiForgeryInstance;
- _actionBindingContextProvider = actionBindingContextProvider;
// Underscores are fine characters in id's.
IdAttributeDotReplacement = "_";
@@ -72,7 +61,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
///
- public string IdAttributeDotReplacement { get; set; }
+ public string IdAttributeDotReplacement
+ {
+ get
+ {
+ return _htmlGenerator.IdAttributeDotReplacement;
+ }
+ set
+ {
+ _htmlGenerator.IdAttributeDotReplacement = value;
+ }
+ }
///
public ViewContext ViewContext
@@ -113,21 +112,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
///
public IModelMetadataProvider MetadataProvider { get; private set; }
- ///
- public HtmlString ActionLink(
- [NotNull] string linkText,
- string actionName,
- string controllerName,
- string protocol,
- string hostname,
- string fragment,
- object routeValues,
- object htmlAttributes)
- {
- var url = _urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment);
- return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
- }
-
///
/// Creates a dictionary from an object, by adding each public instance property as a key with its associated
/// value to the dictionary. It will expose public properties from derived types as well. This is typically
@@ -186,19 +170,55 @@ namespace Microsoft.AspNet.Mvc.Rendering
ViewContext = viewContext;
}
+ ///
+ public HtmlString ActionLink(
+ [NotNull] string linkText,
+ string actionName,
+ string controllerName,
+ string protocol,
+ string hostname,
+ string fragment,
+ object routeValues,
+ object htmlAttributes)
+ {
+ var tagBuilder = _htmlGenerator.GenerateActionLink(
+ linkText,
+ actionName,
+ controllerName,
+ protocol,
+ hostname,
+ fragment,
+ routeValues,
+ htmlAttributes);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ return tagBuilder.ToHtmlString(TagRenderMode.Normal);
+ }
+
///
public HtmlString AntiForgeryToken()
{
- var tagBuilder = _antiForgeryInstance.GetHtml(ViewContext.HttpContext);
+ var tagBuilder = _htmlGenerator.GenerateAntiForgery(ViewContext);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
}
///
- public MvcForm BeginForm(string actionName, string controllerName, object routeValues, FormMethod method,
- object htmlAttributes)
+ public MvcForm BeginForm(
+ string actionName,
+ string controllerName,
+ object routeValues,
+ FormMethod method,
+ object htmlAttributes)
{
- var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
- return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributeDictionary);
+ return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributes);
}
///
@@ -217,19 +237,19 @@ namespace Microsoft.AspNet.Mvc.Rendering
///
public string Encode(string value)
{
- return (!string.IsNullOrEmpty(value)) ? WebUtility.HtmlEncode(value) : string.Empty;
+ return _htmlGenerator.Encode(value);
}
///
public string Encode(object value)
{
- return value != null ? WebUtility.HtmlEncode(value.ToString()) : string.Empty;
+ return _htmlGenerator.Encode(value);
}
///
public string FormatValue(object value, string format)
{
- return ViewDataDictionary.FormatValue(value, format);
+ return _htmlGenerator.FormatValue(value, format);
}
///
@@ -431,8 +451,20 @@ namespace Microsoft.AspNet.Mvc.Rendering
object routeValues,
object htmlAttributes)
{
- var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment);
- return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
+ var tagBuilder = _htmlGenerator.GenerateRouteLink(
+ linkText,
+ routeName,
+ protocol,
+ hostName,
+ fragment,
+ routeValues,
+ htmlAttributes);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}
///
@@ -448,11 +480,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes,
string tag)
{
- return GenerateValidationSummary(
- excludePropertyErrors,
- message,
- GetHtmlAttributeDictionaryOrNull(htmlAttributes),
- tag);
+ return GenerateValidationSummary(excludePropertyErrors, message, htmlAttributes, tag);
}
///
@@ -508,89 +536,24 @@ namespace Microsoft.AspNet.Mvc.Rendering
return new MvcForm(ViewContext);
}
- protected bool EvalBoolean(string key)
- {
- return Convert.ToBoolean(ViewData.Eval(key), CultureInfo.InvariantCulture);
- }
-
- protected string EvalString(string key)
- {
- return Convert.ToString(ViewData.Eval(key), CultureInfo.CurrentCulture);
- }
-
- protected string EvalString(string key, string format)
- {
- return Convert.ToString(ViewData.Eval(key, format), CultureInfo.CurrentCulture);
- }
-
- protected object GetModelStateValue(string key, Type destinationType)
- {
- ModelState modelState;
- if (ViewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null)
- {
- return modelState.Value.ConvertTo(destinationType, culture: null);
- }
-
- return null;
- }
-
- // Only render attributes if client-side validation is enabled, and then only if we've
- // never rendered validation for a field with this name in this form.
- protected virtual IDictionary GetValidationAttributes(ModelMetadata metadata, string name)
- {
- var formContext = ViewContext.ClientValidationEnabled ? ViewContext.FormContext : null;
- if (formContext == null)
- {
- return null;
- }
-
- var fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name);
- if (formContext.RenderedField(fullName))
- {
- return null;
- }
-
- formContext.RenderedField(fullName, true);
- var clientRules = GetClientValidationRules(metadata, name);
- return UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(clientRules);
- }
-
protected virtual HtmlString GenerateCheckBox(ModelMetadata metadata, string name, bool? isChecked,
object htmlAttributes)
{
- if (metadata != null)
- {
- // CheckBoxFor() case. That API does not support passing isChecked directly.
- Contract.Assert(!isChecked.HasValue);
-
- if (metadata.Model != null)
- {
- bool modelChecked;
- if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
- {
- isChecked = modelChecked;
- }
- }
- }
-
- var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
- var explicitValue = isChecked.HasValue;
- if (explicitValue && htmlAttributeDictionary != null)
- {
- // Explicit value must override dictionary
- htmlAttributeDictionary.Remove("checked");
- }
-
- return GenerateInput(InputType.CheckBox,
+ var checkbox = _htmlGenerator.GenerateCheckBox(
+ ViewContext,
metadata,
name,
- value: "true",
- useViewData: !explicitValue,
- isChecked: isChecked ?? false,
- setId: true,
- isExplicitValue: false,
- format: null,
- htmlAttributes: htmlAttributeDictionary);
+ isChecked,
+ htmlAttributes);
+ var hidden = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, metadata, name);
+ if (checkbox == null || hidden == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ var elements = checkbox.ToString(TagRenderMode.SelfClosing) + hidden.ToString(TagRenderMode.SelfClosing);
+
+ return new HtmlString(elements);
}
protected virtual string GenerateDisplayName([NotNull] ModelMetadata metadata, string htmlFieldName)
@@ -616,8 +579,20 @@ namespace Microsoft.AspNet.Mvc.Rendering
protected HtmlString GenerateDropDown(ModelMetadata metadata, string expression,
IEnumerable selectList, string optionLabel, object htmlAttributes)
{
- return GenerateSelect(metadata, optionLabel, expression, selectList, allowMultiple: false,
+ var tagBuilder = _htmlGenerator.GenerateSelect(
+ ViewContext,
+ metadata,
+ optionLabel,
+ name: expression,
+ selectList: selectList,
+ allowMultiple: false,
htmlAttributes: htmlAttributes);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}
protected virtual HtmlString GenerateEditor(ModelMetadata metadata, string htmlFieldName, string templateName,
@@ -659,34 +634,24 @@ namespace Microsoft.AspNet.Mvc.Rendering
///
/// In this context, "renders" means the method writes its output using .
///
- protected virtual MvcForm GenerateForm(string actionName, string controllerName, object routeValues,
- FormMethod method, IDictionary htmlAttributes)
+ protected virtual MvcForm GenerateForm(
+ string actionName,
+ string controllerName,
+ object routeValues,
+ FormMethod method,
+ object htmlAttributes)
{
- var tagBuilder = new TagBuilder("form");
- tagBuilder.MergeAttributes(htmlAttributes);
-
- string formAction;
- if (actionName == null && controllerName == null && routeValues == null && method == FormMethod.Post &&
- htmlAttributes == null)
+ var tagBuilder = _htmlGenerator.GenerateForm(
+ ViewContext,
+ actionName,
+ controllerName,
+ routeValues,
+ GetFormMethodString(method),
+ htmlAttributes);
+ if (tagBuilder != null)
{
- // Submit to the original URL in the special case that user called the BeginForm() overload without
- // parameters. Also reachable in the even-more-unusual case that user called another BeginForm()
- // overload with default argument values.
- var request = ViewContext.HttpContext.Request;
- formAction = request.PathBase + request.Path + request.QueryString;
+ ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
}
- else
- {
- formAction = _urlHelper.Action(action: actionName, controller: controllerName, values: routeValues);
- }
-
- // action is implicitly generated, so htmlAttributes take precedence.
- tagBuilder.MergeAttribute("action", formAction);
-
- // method is an explicit parameter, so it takes precedence over the htmlAttributes.
- tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), replaceExisting: true);
-
- ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return CreateForm();
}
@@ -698,29 +663,26 @@ namespace Microsoft.AspNet.Mvc.Rendering
bool useViewData,
object htmlAttributes)
{
- // Special-case opaque values and arbitrary binary data.
- var byteArrayValue = value as byte[];
- if (byteArrayValue != null)
+ var tagBuilder =
+ _htmlGenerator.GenerateHidden(
+ ViewContext,
+ metadata,
+ name,
+ value,
+ useViewData,
+ htmlAttributes);
+ if (tagBuilder == null)
{
- value = Convert.ToBase64String(byteArrayValue);
+ return HtmlString.Empty;
}
- var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
- return GenerateInput(InputType.Hidden,
- metadata,
- name,
- value,
- useViewData,
- isChecked: false,
- setId: true,
- isExplicitValue: true,
- format: null,
- htmlAttributes: htmlAttributeDictionary);
+ return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
}
protected virtual string GenerateId(string expression)
{
- return ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
+ var fullName = DefaultHtmlGenerator.GetFullHtmlFieldName(ViewContext, name: expression);
+ return fullName;
}
protected virtual HtmlString GenerateLabel([NotNull] ModelMetadata metadata,
@@ -728,42 +690,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
string labelText,
object htmlAttributes)
{
- var resolvedLabelText = labelText ?? metadata.DisplayName ?? metadata.PropertyName;
- if (resolvedLabelText == null)
- {
- resolvedLabelText =
- string.IsNullOrEmpty(htmlFieldName) ? string.Empty : htmlFieldName.Split('.').Last();
- }
-
- if (string.IsNullOrEmpty(resolvedLabelText))
+ var tagBuilder = _htmlGenerator.GenerateLabel(
+ ViewContext,
+ metadata,
+ name: htmlFieldName,
+ labelText: labelText,
+ htmlAttributes: htmlAttributes);
+ if (tagBuilder == null)
{
return HtmlString.Empty;
}
- var tag = new TagBuilder("label");
- tag.Attributes.Add(
- "for",
- TagBuilder.CreateSanitizedId(
- ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName),
- IdAttributeDotReplacement));
- tag.SetInnerText(resolvedLabelText);
- tag.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes), replaceExisting: true);
- return tag.ToHtmlString(TagRenderMode.Normal);
- }
-
- protected virtual HtmlString GenerateLink(
- [NotNull] string linkText,
- [NotNull] string url,
- IDictionary htmlAttributes)
- {
- var tagBuilder = new TagBuilder("a")
- {
- InnerHtml = WebUtility.HtmlEncode(linkText),
- };
-
- tagBuilder.MergeAttributes(htmlAttributes);
- tagBuilder.MergeAttribute("href", url);
-
return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}
@@ -773,354 +710,94 @@ namespace Microsoft.AspNet.Mvc.Rendering
IEnumerable selectList,
object htmlAttributes)
{
- return GenerateSelect(
+ var tagBuilder = _htmlGenerator.GenerateSelect(
+ ViewContext,
metadata,
optionLabel: null,
name: name,
selectList: selectList,
allowMultiple: true,
htmlAttributes: htmlAttributes);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}
protected virtual string GenerateName(string name)
{
- var fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name);
+ var fullName = DefaultHtmlGenerator.GetFullHtmlFieldName(ViewContext, name);
return fullName;
}
protected virtual HtmlString GeneratePassword(ModelMetadata metadata, string name, object value,
object htmlAttributes)
{
- var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
- return GenerateInput(InputType.Password,
+ var tagBuilder = _htmlGenerator.GeneratePassword(
+ ViewContext,
metadata,
name,
value,
- useViewData: false,
- isChecked: false,
- setId: true,
- isExplicitValue: true,
- format: null,
- htmlAttributes: htmlAttributeDictionary);
+ htmlAttributes);
+ if (tagBuilder == null)
+ {
+ return HtmlString.Empty;
+ }
+
+ return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
}
protected virtual HtmlString GenerateRadioButton(ModelMetadata metadata, string name, object value,
bool? isChecked, object htmlAttributes)
{
- var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
- if (metadata == null)
- {
- // RadioButton() case. Do not override checked attribute if isChecked is implicit.
- if (!isChecked.HasValue &&
- (htmlAttributeDictionary == null || !htmlAttributeDictionary.ContainsKey("checked")))
- {
- // Note value may be null if isChecked is non-null.
- if (value == null)
- {
- throw new ArgumentNullException("value");
- }
-
- // isChecked not provided nor found in the given attributes; fall back to view data.
- var valueString = Convert.ToString(value, CultureInfo.CurrentCulture);
- isChecked = !string.IsNullOrEmpty(name) &&
- string.Equals(EvalString(name), valueString, StringComparison.OrdinalIgnoreCase);
- }
- }
- else
- {
- // RadioButtonFor() case. That API does not support passing isChecked directly.
- Contract.Assert(!isChecked.HasValue);
-
- // Need a value to determine isChecked.
- Contract.Assert(value != null);
-
- var model = metadata.Model;
- var valueString = Convert.ToString(value, CultureInfo.CurrentCulture);
- isChecked = model != null &&
- string.Equals(model.ToString(), valueString, StringComparison.OrdinalIgnoreCase);
- }
-
- var explicitValue = isChecked.HasValue;
- if (explicitValue && htmlAttributeDictionary != null)
- {
- // Explicit value must override dictionary
- htmlAttributeDictionary.Remove("checked");
- }
-
- return GenerateInput(InputType.Radio,
+ var tagBuilder = _htmlGenerator.GenerateRadioButton(
+ ViewContext,
metadata,
name,
value,
- useViewData: false,
- isChecked: isChecked ?? false,
- setId: true,
- isExplicitValue: true,
- format: null,
- htmlAttributes: htmlAttributeDictionary);
- }
-
- protected virtual HtmlString GenerateSelect(ModelMetadata metadata,
- string optionLabel, string name, IEnumerable selectList, bool allowMultiple,
- object htmlAttributes)
- {
- var fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name);
- if (string.IsNullOrEmpty(fullName))
+ isChecked,
+ htmlAttributes);
+ if (tagBuilder == null)
{
- throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "name");
+ return HtmlString.Empty;
}
- var usedViewData = false;
-
- // If we got a null selectList, try to use ViewData to get the list of items.
- if (selectList == null)
- {
- if (string.IsNullOrEmpty(name))
- {
- // Avoid ViewData.Eval() throwing an ArgumentException with a different parameter name. Note this
- // is an extreme case since users must pass a non-null selectList to use CheckBox() or ListBox()
- // in a template, where a null or empty name has meaning.
- throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "name");
- }
-
- selectList = GetSelectListItems(name);
- usedViewData = true;
- }
-
- var defaultValue = (allowMultiple) ?
- GetModelStateValue(fullName, typeof(string[])) :
- GetModelStateValue(fullName, typeof(string));
-
- // If we haven't already used ViewData to get the entire list of items then we need to
- // use the ViewData-supplied value before using the parameter-supplied value.
- if (defaultValue == null && !string.IsNullOrEmpty(name))
- {
- if (!usedViewData)
- {
- defaultValue = ViewData.Eval(name);
- }
- else if (metadata != null)
- {
- defaultValue = metadata.Model;
- }
- }
-
- if (defaultValue != null)
- {
- selectList = UpdateSelectListItemsWithDefaultValue(selectList, defaultValue, allowMultiple);
- }
-
- // Convert each ListItem to an
public HtmlHelper(
+ [NotNull] IHtmlGenerator htmlGenerator,
[NotNull] ICompositeViewEngine viewEngine,
- [NotNull] IModelMetadataProvider metadataProvider,
- [NotNull] IUrlHelper urlHelper,
- [NotNull] AntiForgery antiForgeryInstance,
- [NotNull] IActionBindingContextProvider actionBindingContextProvider)
- : base(viewEngine, metadataProvider, urlHelper, antiForgeryInstance, actionBindingContextProvider)
+ [NotNull] IModelMetadataProvider metadataProvider)
+ : base(htmlGenerator, viewEngine, metadataProvider)
{
}
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs
index 78a626d740..6d67b9a641 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs
@@ -1,19 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
-using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
-using Microsoft.AspNet.Mvc.Rendering.Expressions;
namespace Microsoft.AspNet.Mvc.Rendering
{
@@ -22,6 +11,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
///
public interface IHtmlGenerator
{
+ string IdAttributeDotReplacement { get; set; }
+
string Encode(string value);
string Encode(object value);
@@ -101,11 +92,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
string labelText,
object htmlAttributes);
- ///
- /// Not used directly in HtmlHelper. Exposed publicly for use in DefaultDisplayTemplates.
- ///
- TagBuilder GenerateOption(SelectListItem item, string encodedText);
-
TagBuilder GeneratePassword(
[NotNull] ViewContext viewContext,
ModelMetadata metadata,
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultTemplatesUtilities.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultTemplatesUtilities.cs
index 71f3b7caa4..05443e1585 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultTemplatesUtilities.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultTemplatesUtilities.cs
@@ -145,15 +145,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
.Setup(o => o.RequestServices)
.Returns(serviceProvider.Object);
- var viewContext = new ViewContext(actionContext, Mock.Of(), viewData, new StringWriter());
+ var htmlGenerator = new DefaultHtmlGenerator(
+ actionBindingContextProvider.Object,
+ GetAntiForgeryInstance(),
+ provider,
+ urlHelper);
// TemplateRenderer will Contextualize this transient service.
- var innerHelper = (IHtmlHelper)new HtmlHelper(
- viewEngine,
- provider,
- urlHelper,
- GetAntiForgeryInstance(),
- actionBindingContextProvider.Object);
+ var innerHelper = (IHtmlHelper)new HtmlHelper(htmlGenerator, viewEngine, provider);
if (innerHelperWrapper != null)
{
innerHelper = innerHelperWrapper(innerHelper);
@@ -162,12 +161,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
.Setup(s => s.GetService(typeof(IHtmlHelper)))
.Returns(() => innerHelper);
- var htmlHelper = new HtmlHelper(
- viewEngine,
- provider,
- urlHelper,
- GetAntiForgeryInstance(),
- actionBindingContextProvider.Object);
+ var htmlHelper = new HtmlHelper(htmlGenerator, viewEngine, provider);
+ var viewContext = new ViewContext(actionContext, Mock.Of(), viewData, new StringWriter());
htmlHelper.Contextualize(viewContext);
return htmlHelper;