diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs index 794710399c..73ed23a559 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultHtmlGenerator.cs @@ -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); + /// + 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); } /// @@ -780,6 +782,44 @@ namespace Microsoft.AspNet.Mvc.Rendering return null; } + /// + /// Generate a <form> element. + /// + /// A instance for the current scope. + /// The URL where the form-data should be submitted. + /// The HTTP method for processing the form, either GET or POST. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// A instance for the </form> element. + /// + 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, diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs index 8d17a3172d..e133912408 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs @@ -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); } + /// + public MvcForm BeginRouteForm(string routeName, object routeValues, FormMethod method, object htmlAttributes) + { + return GenerateRouteForm(routeName, routeValues, method, htmlAttributes); + } + /// public void EndForm() { @@ -611,8 +616,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The name of the action method. /// The name of the controller. @@ -623,10 +628,12 @@ namespace Microsoft.AspNet.Mvc.Rendering /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. - /// An instance containing HTML - /// attributes to set for the element. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// /// - /// An instance which emits the </form> end tag when disposed. + /// An instance which renders the </form> end tag when disposed. /// /// /// In this context, "renders" means the method writes its output using . @@ -653,6 +660,49 @@ namespace Microsoft.AspNet.Mvc.Rendering return CreateForm(); } + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The name of the route. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route parameters. + /// + /// The HTTP method for processing the form, either GET or POST. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + 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, diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs index 09595bf8f4..65a4c1ed7a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/IHtmlGenerator.cs @@ -49,9 +49,10 @@ namespace Microsoft.AspNet.Mvc.Rendering string name); /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Generate a <form> element. When the user submits the form, the method + /// will process the request. /// + /// A instance for the current scope. /// The name of the action method. /// The name of the controller. /// @@ -61,14 +62,13 @@ namespace Microsoft.AspNet.Mvc.Rendering /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. - /// An instance containing HTML - /// attributes to set for the element. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// /// - /// An instance which emits the </form> end tag when disposed. + /// A instance for the </form> element. /// - /// - /// In this context, "renders" means the method writes its output using . - /// TagBuilder GenerateForm( [NotNull] ViewContext viewContext, string actionName, @@ -77,6 +77,33 @@ namespace Microsoft.AspNet.Mvc.Rendering string method, object htmlAttributes); + /// + /// Generate a <form> element. When the user submits the form, the route + /// will forward the request to an action method. + /// + /// A instance for the current scope. + /// The name of the route. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route parameters. + /// + /// The HTTP method for processing the form, either GET or POST. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// A instance for the </form> element. + /// + TagBuilder GenerateRouteForm( + [NotNull] ViewContext viewContext, + string routeName, + object routeValues, + string method, + object htmlAttributes); + TagBuilder GenerateHidden( [NotNull] ViewContext viewContext, ModelMetadata metadata, diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperFormExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperFormExtensions.cs index fbfda8af2a..76508bbd7f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperFormExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperFormExtensions.cs @@ -28,8 +28,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// current action method will process the request. /// /// The instance this method extends. /// The HTTP method for processing the form, either GET or POST. @@ -46,8 +46,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// current action method will process the request. /// /// The instance this method extends. /// The HTTP method for processing the form, either GET or POST. @@ -72,8 +72,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// current action method will process the request. /// /// The instance this method extends. /// @@ -96,8 +96,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The instance this method extends. /// The name of the action method. @@ -118,8 +118,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The instance this method extends. /// The name of the action method. @@ -148,8 +148,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The instance this method extends. /// The name of the action method. @@ -172,8 +172,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The instance this method extends. /// The name of the action method. @@ -204,8 +204,8 @@ namespace Microsoft.AspNet.Mvc.Rendering } /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The instance this method extends. /// The name of the action method. @@ -232,5 +232,161 @@ namespace Microsoft.AspNet.Mvc.Rendering return htmlHelper.BeginForm(actionName, controllerName, routeValues: null, method: method, htmlAttributes: htmlAttributes); } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// default route will forward the request to an action method. + /// + /// The instance this method extends. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route + /// parameters. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm([NotNull] this IHtmlHelper htmlHelper, object routeValues) + { + return htmlHelper.BeginRouteForm( + routeName: null, + routeValues: routeValues, + method: FormMethod.Post, + htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The instance this method extends. + /// The name of the route. + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm([NotNull] this IHtmlHelper htmlHelper, string routeName) + { + return htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: FormMethod.Post, + htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The instance this method extends. + /// The name of the route. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route + /// parameters. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm( + [NotNull] this IHtmlHelper htmlHelper, + string routeName, + object routeValues) + { + return htmlHelper.BeginRouteForm(routeName, routeValues, FormMethod.Post, htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The instance this method extends. + /// The name of the route. + /// The HTTP method for processing the form, either GET or POST. + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm( + [NotNull] this IHtmlHelper htmlHelper, + string routeName, + FormMethod method) + { + return htmlHelper.BeginRouteForm(routeName, routeValues: null, method: method, htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The instance this method extends. + /// The name of the route. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route + /// parameters. + /// + /// The HTTP method for processing the form, either GET or POST. + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm( + [NotNull] this IHtmlHelper htmlHelper, + string routeName, + object routeValues, + FormMethod method) + { + return htmlHelper.BeginRouteForm(routeName, routeValues, method, htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The instance this method extends. + /// The name of the route. + /// The HTTP method for processing the form, either GET or POST. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML + /// attributes. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm( + [NotNull] this IHtmlHelper htmlHelper, + string routeName, + FormMethod method, + object htmlAttributes) + { + return htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: method, + htmlAttributes: htmlAttributes); + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs index b9e302236f..73ce13e961 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs @@ -82,8 +82,8 @@ namespace Microsoft.AspNet.Mvc.Rendering HtmlString AntiForgeryToken(); /// - /// Renders a <form> start tag to the response. When the user submits the form, - /// the request will be processed by an action method. + /// Renders a <form> start tag to the response. When the user submits the form, the + /// method will process the request. /// /// The name of the action method. /// The name of the controller. @@ -111,6 +111,34 @@ namespace Microsoft.AspNet.Mvc.Rendering FormMethod method, object htmlAttributes); + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// route will forward the request to an action method. + /// + /// The name of the route. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route parameters. + /// + /// The HTTP method for processing the form, either GET or POST. + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + MvcForm BeginRouteForm( + string routeName, + object routeValues, + FormMethod method, + object htmlAttributes); + /// /// Returns an <input> element of type "checkbox" with value "true" and an <input> element of type /// "hidden" with value "false". diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs index f2d1982bfa..c0f94ae584 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Rendering/DefaultEditorTemplatesTests.cs @@ -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__");