Add `BeginRouteForm()` HTML helper

- refactor `DefaultHtmlGenerator.GenerateForm()` to support new method

nits:
- correct XML comments
- add a few more code comments
This commit is contained in:
Doug Bunting 2014-11-08 22:03:41 -08:00
parent 47d0afbe38
commit 22fafe298c
6 changed files with 356 additions and 46 deletions

View File

@ -6,11 +6,9 @@ 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;
@ -157,21 +155,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
string method,
object htmlAttributes)
{
var tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
var defaultMethod = false;
if (string.IsNullOrEmpty(method))
{
defaultMethod = true;
method = FormMethod.Post.ToString();
}
else if (string.Equals(method, FormMethod.Post.ToString(), StringComparison.OrdinalIgnoreCase))
{
defaultMethod = true;
}
string formAction;
string action;
if (actionName == null && controllerName == null && routeValues == null && defaultMethod &&
htmlAttributes == null)
{
@ -179,20 +173,28 @@ namespace Microsoft.AspNet.Mvc.Rendering
// 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;
action = request.PathBase + request.Path + request.QueryString;
}
else
{
formAction = _urlHelper.Action(action: actionName, controller: controllerName, values: routeValues);
action = _urlHelper.Action(action: actionName, controller: controllerName, values: routeValues);
}
// action is implicitly generated, so htmlAttributes take precedence.
tagBuilder.MergeAttribute("action", formAction);
return GenerateFormCore(viewContext, action, method, htmlAttributes);
}
// method is an explicit parameter, so it takes precedence over the htmlAttributes.
tagBuilder.MergeAttribute("method", method, replaceExisting: true);
/// <inheritdoc />
public TagBuilder GenerateRouteForm(
[NotNull]ViewContext viewContext,
string routeName,
object routeValues,
string method,
object htmlAttributes)
{
var action =
_urlHelper.RouteUrl(routeName, values: routeValues, protocol: null, host: null, fragment: null);
return tagBuilder;
return GenerateFormCore(viewContext, action, method, htmlAttributes);
}
/// <inheritdoc />
@ -780,6 +782,44 @@ namespace Microsoft.AspNet.Mvc.Rendering
return null;
}
/// <summary>
/// Generate a &lt;form&gt; element.
/// </summary>
/// <param name="viewContext">A <see cref="ViewContext"/> instance for the current scope.</param>
/// <param name="action">The URL where the form-data should be submitted.</param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// A <see cref="TagBuilder"/> instance for the &lt;/form&gt; element.
/// </returns>
protected virtual TagBuilder GenerateFormCore(
[NotNull] ViewContext viewContext,
string action,
string method,
object htmlAttributes)
{
var tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
// action is implicitly generated from other parameters, so htmlAttributes take precedence.
tagBuilder.MergeAttribute("action", action);
if (string.IsNullOrEmpty(method))
{
// Occurs only when called from a tag helper.
method = FormMethod.Post.ToString();
}
// For tag helpers, htmlAttributes will be null; replaceExisting value does not matter.
// method is an explicit parameter to HTML helpers, so it takes precedence over the htmlAttributes.
tagBuilder.MergeAttribute("method", method, replaceExisting: true);
return tagBuilder;
}
protected virtual TagBuilder GenerateInput(
[NotNull] ViewContext viewContext,
InputType inputType,

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
@ -218,6 +217,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributes);
}
/// <inheritdoc />
public MvcForm BeginRouteForm(string routeName, object routeValues, FormMethod method, object htmlAttributes)
{
return GenerateRouteForm(routeName, routeValues, method, htmlAttributes);
}
/// <inheritdoc />
public void EndForm()
{
@ -611,8 +616,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
@ -623,10 +628,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">An <see cref="IDictionary{string, object}"/> instance containing HTML
/// attributes to set for the element.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which emits the &lt;/form&gt; end tag when disposed.
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
@ -653,6 +660,49 @@ namespace Microsoft.AspNet.Mvc.Rendering
return CreateForm();
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="routeName">The name of the route.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
protected virtual MvcForm GenerateRouteForm(
string routeName,
object routeValues,
FormMethod method,
object htmlAttributes)
{
var tagBuilder = _htmlGenerator.GenerateRouteForm(
ViewContext,
routeName,
routeValues,
GetFormMethodString(method),
htmlAttributes);
if (tagBuilder != null)
{
ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
}
return CreateForm();
}
protected virtual HtmlString GenerateHidden(
ModelMetadata metadata,
string name,

View File

@ -49,9 +49,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
string name);
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Generate a &lt;form&gt; element. When the user submits the form, the <paramref name="actionName"/> method
/// will process the request.
/// </summary>
/// <param name="viewContext">A <see cref="ViewContext"/> instance for the current scope.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="routeValues">
@ -61,14 +62,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">An <see cref="IDictionary{string, object}"/> instance containing HTML
/// attributes to set for the element.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which emits the &lt;/form&gt; end tag when disposed.
/// A <see cref="TagBuilder"/> instance for the &lt;/form&gt; element.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
TagBuilder GenerateForm(
[NotNull] ViewContext viewContext,
string actionName,
@ -77,6 +77,33 @@ namespace Microsoft.AspNet.Mvc.Rendering
string method,
object htmlAttributes);
/// <summary>
/// Generate a &lt;form&gt; element. When the user submits the form, the <paramref name="routeName"/> route
/// will forward the request to an action method.
/// </summary>
/// <param name="viewContext">A <see cref="ViewContext"/> instance for the current scope.</param>
/// <param name="routeName">The name of the route.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// A <see cref="TagBuilder"/> instance for the &lt;/form&gt; element.
/// </returns>
TagBuilder GenerateRouteForm(
[NotNull] ViewContext viewContext,
string routeName,
object routeValues,
string method,
object htmlAttributes);
TagBuilder GenerateHidden(
[NotNull] ViewContext viewContext,
ModelMetadata metadata,

View File

@ -28,8 +28,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// current action method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
@ -46,8 +46,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// current action method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
@ -72,8 +72,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// current action method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeValues">
@ -96,8 +96,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="actionName">The name of the action method.</param>
@ -118,8 +118,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="actionName">The name of the action method.</param>
@ -148,8 +148,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="actionName">The name of the action method.</param>
@ -172,8 +172,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="actionName">The name of the action method.</param>
@ -204,8 +204,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="actionName">The name of the action method.</param>
@ -232,5 +232,161 @@ namespace Microsoft.AspNet.Mvc.Rendering
return htmlHelper.BeginForm(actionName, controllerName, routeValues: null,
method: method, htmlAttributes: htmlAttributes);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// default route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="System.Collections.Generic.IDictionary{string, object}"/> instance containing the route
/// parameters.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm([NotNull] this IHtmlHelper htmlHelper, object routeValues)
{
return htmlHelper.BeginRouteForm(
routeName: null,
routeValues: routeValues,
method: FormMethod.Post,
htmlAttributes: null);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeName">The name of the route.</param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm([NotNull] this IHtmlHelper htmlHelper, string routeName)
{
return htmlHelper.BeginRouteForm(
routeName,
routeValues: null,
method: FormMethod.Post,
htmlAttributes: null);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeName">The name of the route.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="System.Collections.Generic.IDictionary{string, object}"/> instance containing the route
/// parameters.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm(
[NotNull] this IHtmlHelper htmlHelper,
string routeName,
object routeValues)
{
return htmlHelper.BeginRouteForm(routeName, routeValues, FormMethod.Post, htmlAttributes: null);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeName">The name of the route.</param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm(
[NotNull] this IHtmlHelper htmlHelper,
string routeName,
FormMethod method)
{
return htmlHelper.BeginRouteForm(routeName, routeValues: null, method: method, htmlAttributes: null);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeName">The name of the route.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="System.Collections.Generic.IDictionary{string, object}"/> instance containing the route
/// parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm(
[NotNull] this IHtmlHelper htmlHelper,
string routeName,
object routeValues,
FormMethod method)
{
return htmlHelper.BeginRouteForm(routeName, routeValues, method, htmlAttributes: null);
}
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
/// <param name="routeName">The name of the route.</param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="System.Collections.Generic.IDictionary{string, object}"/> instance containing the HTML
/// attributes.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
public static MvcForm BeginRouteForm(
[NotNull] this IHtmlHelper htmlHelper,
string routeName,
FormMethod method,
object htmlAttributes)
{
return htmlHelper.BeginRouteForm(
routeName,
routeValues: null,
method: method,
htmlAttributes: htmlAttributes);
}
}
}

View File

@ -82,8 +82,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString AntiForgeryToken();
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form,
/// the request will be processed by an action method.
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="actionName"/> method will process the request.
/// </summary>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
@ -111,6 +111,34 @@ namespace Microsoft.AspNet.Mvc.Rendering
FormMethod method,
object htmlAttributes);
/// <summary>
/// Renders a &lt;form&gt; start tag to the response. When the user submits the form, the
/// <paramref name="routeName"/> route will forward the request to an action method.
/// </summary>
/// <param name="routeName">The name of the route.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="method">The HTTP method for processing the form, either GET or POST.</param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// An <see cref="MvcForm"/> instance which renders the &lt;/form&gt; end tag when disposed.
/// </returns>
/// <remarks>
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
/// </remarks>
MvcForm BeginRouteForm(
string routeName,
object routeValues,
FormMethod method,
object htmlAttributes);
/// <summary>
/// Returns an &lt;input&gt; element of type "checkbox" with value "true" and an &lt;input&gt; element of type
/// "hidden" with value "false".

View File

@ -758,6 +758,15 @@ Environment.NewLine;
throw new NotImplementedException();
}
public MvcForm BeginRouteForm(
string routeName,
object routeValues,
FormMethod method,
object htmlAttributes)
{
throw new NotImplementedException();
}
public HtmlString CheckBox(string name, bool? isChecked, object htmlAttributes)
{
return new HtmlString("__CheckBox__");