How Forms work in MVC ?

This document demonstrates working with Forms and the HTML elements commonly used on a Form. The HTML Form element provides the primary mechanism web apps use to post back data to the server. Most of this document describes Tag Helpers and how they can help you productively create robust HTML forms. We recommend you read Introduction to Tag Helpersbefore you read this document.

In many cases, HTML Helpers provide an alternative approach to a specific Tag Helper, but it’s important to recognize that Tag Helpers do not replace HTML Helpers and there is not a Tag Helper for each HTML Helper. When an HTML Helper alternative exists, it is mentioned.

Sections:

The Form Tag Helper

The Input Tag Helper

The Textarea Tag Helper

The Label Tag Helper

The Validation Tag Helpers

The Select Tag Helper

Additional Resources

The Form Tag Helper

The Form Tag Helper:

Generates the HTML <FORM> action attribute value for a MVC controller action or named route

Generates a hidden Request Verification Token to prevent cross-site request forgery (when used with the [ValidateAntiForgeryToken] attribute in the HTTP Post action method)

Provides the asp-route-<ParameterName> attribute, where <ParameterName> is added to the route values. The routeValues parameters to Html.BeginForm and Html.BeginRouteForm provide similar functionality.

The MVC runtime generates the action attribute value from the Form Tag Helper attributesasp-controller and asp-action. The Form Tag Helper also generates a hidden Request Verification Token to prevent cross-site request forgery (when used with the [ValidateAntiForgeryToken]attribute in the HTTP Post action method). Protecting a pure HTML Form from cross-site request forgery is very difficult, the Form Tag Helper provides this service for you.

Using a named route

The asp-route Tag Helper attribute can also generate markup for the HTML action attribute. An app with a route named register could use the following markup for the registration page:

With the built in templates, returnUrl is only populated automatically when you try to access an authorized resource but are not authenticated or authorized. When you attempt an unauthorized access, the security middleware redirects you to the login page with the returnUrl set.

The Input Tag Helper

Generates the id and name HTML attributes for the expression name specified in the asp-forattribute. asp-for="Property1.Property2" is equivalent to m=>m.Property1.Property2, that is the attribute value literally is part of an expression. The name of the expression is what’s used for the asp-for attribute value.

Sets the HTML type attribute value based on the model type and data annotation attributes applied to the model property

Will not overwrite the HTML type attribute value when one is specified

Has an HTML Helper feature overlap with Html.TextBoxFor and Html.EditorFor. See the HTML Helper alternatives to Input Tag Helper section for details.

Provides strong typing. If the name of the property changes and you don’t update the Tag Helper you’ll get an error similar to the following:

An error occurred during the compilation of a resource required to process
this request. Please review the following specific error details and modify
your source code appropriately.
Type expected
'RegisterViewModel' does not contain a definition for 'Email' and no
extension method 'Email' accepting a first argument of type 'RegisterViewModel'
could be found (are you missing a using directive or an assembly reference?)

The Input Tag Helper sets the HTML type attribute based on the .NET type. The following table lists some common .NET types and generated HTML type (not every .NET type is listed).

.NET type

Input Type

Bool

type=”checkbox”

String

type=”text”

DateTime

type=”datetime”

Byte

type=”number”

Int

type=”number”

Single, Double

type=”number”

The following table shows some common data annotations attributes that the input tag helper will map to specific input types (not every validation attribute is listed):

<formmethod="post"action="/Demo/RegisterInput">
Email:
<inputtype="email"data-val="true"data-val-email="The Email Address field is not a valid e-mail address."data-val-required="The Email Address field is required."id="Email"name="Email"value=""/><br>
Password:
<inputtype="password"data-val="true"data-val-required="The Password field is required."id="Password"name="Password"/><br><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

The data annotations applied to the Email and Password properties generate metadata on the model. The Input Tag Helper consumes the model metadata and produces HTML5 data-val-*attributes (see Model Validation). These attributes describe the validators to attach to the input fields. This provides unobtrusive HTML5 and jQuery validation. The unobtrusive attributes have the format data-val-rule="ErrorMessage", where rule is the name of the validation rule (such asdata-val-required, data-val-email, data-val-maxlength, etc.) If an error message is provided in the attribute, it is displayed as the value for the data-val-rule attribute. There are also attributes of the form data-val-ruleName-argumentName="argumentValue" that provide additional details about the rule, for example, data-val-maxlength-max="1024" .

HTML Helper alternatives to Input Tag Helper

Html.TextBox, Html.TextBoxFor, Html.Editor and Html.EditorFor have overlapping features with the Input Tag Helper. The Input Tag Helper will automatically set the type attribute; Html.TextBox andHtml.TextBoxFor will not. Html.Editor and Html.EditorFor handle collections, complex objects and templates; the Input Tag Helper does not. The Input Tag Helper, Html.EditorFor andHtml.TextBoxFor are strongly typed (they use lambda expressions); Html.TextBox and Html.Editorare not (they use expression names).

Expression names

The asp-for attribute value is a ModelExpression and the right hand side of a lambda expression. Therefore, asp-for="Property1" becomes m=>m.Property1 in the generated code which is why you don’t need to prefix with Model. You can use the “@” character to start an inline expression and move before the m.:

@{
var joe = "Joe";
}
<inputasp-for="@joe"/>

Generates the following:

<inputtype="text"id="joe"name="joe"value="Joe"/>

Navigating child properties

You can also navigate to child properties using the property path of the view model. Consider a more complex model class that contains a child Address property.

<formmethod="post"action="/Demo/RegisterTextArea"><textareadata-val="true"data-val-maxlength="The field Description must be a string or array type with a maximum length of &#x27;1024&#x27;."data-val-maxlength-max="1024"data-val-minlength="The field Description must be a string or array type with a minimum length of &#x27;5&#x27;."data-val-minlength-min="5"id="Description"name="Description"></textarea><buttontype="submit">Test</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

The Label Tag Helper

Generates the label caption and for attribute on a <label> element for an expression name

HTML Helper alternative: Html.LabelFor.

The Label Tag Helper provides the following benefits over a pure HTML label element:

You automatically get the descriptive label value from the Display attribute. The intended display name might change over time, and the combination of Display attribute and Label Tag Helper will apply the Display everywhere it’s used.

The Label Tag Helper generated the for attribute value of “Email”, which is the ID associated with the <input> element. The Tag Helpers generate consistent id and for elements so they can be correctly associated. The caption in this sample comes from the Display attribute. If the model didn’t contain a Display attribute, the caption would be the property name of the expression.

The Validation Tag Helpers

There are two Validation Tag Helpers. The Validation Message Tag Helper (which displays a validation message for a single property on your model), and the Validation Summary Tag Helper(which displays a summary of validation errors). The Input Tag Helper adds HTML5 client side validation attributes to input elements based on data annotation attributes on your model classes. Validation is also performed on the server. The Validation Tag Helper displays these error messages when a validation error occurs.

The Validation Message Tag Helper

Adds the HTML5 data-valmsg-for="property" attribute to the span element, which attaches the validation error messages on the input field of the specified model property. When a client side validation error occurs, jQuery displays the error message in the <span> element.

Validation also takes place on the server. Clients may have JavaScript disabled and some validation can only be done on the server side.

HTML Helper alternative: Html.ValidationMessageFor

The Validation Message Tag Helper is used with the asp-validation-for attribute on a HTML spanelement.

You generally use the Validation Message Tag Helper after an Input Tag Helper for the same property. Doing so displays any validation error messages near the input that caused the error.

Note:

You must have a view with the correct JavaScript and jQuery script references in place for client side validation. See Model Validation for more information.

When a server side validation error occurs (for example when you have custom server side validation or client-side validation is disabled), MVC places that error message as the body of the<span> element.

<spanclass="field-validation-error"data-valmsg-for="Email"data-valmsg-replace="true">
The Email Address field is required.
</span>

The Validation Summary Tag Helper

Targets <div> elements with the asp-validation-summary attribute

HTML Helper alternative: @Html.ValidationSummary

The Validation Summary Tag Helper is used to display a summary of validation messages. Theasp-validation-summary attribute value can be any of the following:

asp-validation-summary

Validation messages displayed

ValidationSummary.All

Property and model level

ValidationSummary.ModelOnly

Model

ValidationSummary.None

None

Sample

In the following example, the data model is decorated with DataAnnotation attributes, which generates validation error messages on the <input> element. When a validation error occurs, the Validation Tag Helper displays the error message:

<formaction="/DemoReg/Register"method="post"><divclass="validation-summary-valid"data-valmsg-summary="true"><ul><listyle="display:none"></li></ul></div> Email: <inputname="Email"id="Email"type="email"value=""data-val-required="The Email field is required."data-val-email="The Email field is not a valid e-mail address."data-val="true"><br><spanclass="field-validation-valid"data-valmsg-replace="true"data-valmsg-for="Email"></span><br> Password: <inputname="Password"id="Password"type="password"data-val-required="The Password field is required."data-val="true"><br><spanclass="field-validation-valid"data-valmsg-replace="true"data-valmsg-for="Password"></span><br><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

<formmethod="post"action="/"><selectid="Country"name="Country"><optionvalue="MX">Mexico</option><optionselected="selected"value="CA">Canada</option><optionvalue="US">USA</option></select><br/><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

Note:

We do not recommend using ViewBag or ViewData with the Select Tag Helper. A view model is more robust at providing MVC metadata and generally less problematic.

The asp-for attribute value is a special case and doesn’t require a Model prefix, the other Tag Helper attributes do (such as asp-items)

<selectasp-for="Country"asp-items="Model.Countries"></select>

Enum binding

It’s often convenient to use <select> with an enum property and generate the SelectListItemelements from the enum values.

<formmethod="post"action="/Home/IndexEnum"><selectdata-val="true"data-val-required="The EnumCountry field is required."id="EnumCountry"name="EnumCountry"><optionvalue="0">United Mexican States</option><optionvalue="1">United States of America</option><optionvalue="2">Canada</option><optionvalue="3">France</option><optionvalue="4">Germany</option><optionselected="selected"value="5">Spain</option></select><br/><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

Option Group

The HTML <optgroup> element is generated when the view model contains one or moreSelectListGroup objects.

The CountryViewModelGroup groups the SelectListItem elements into the “North America” and “Europe” groups:

<formmethod="post"action="/Home/IndexMultiSelect"><selectid="CountryCodes"multiple="multiple"name="CountryCodes"><optionvalue="MX">Mexico</option><optionvalue="CA">Canada</option><optionvalue="US">USA</option><optionvalue="FR">France</option><optionvalue="ES">Spain</option><optionvalue="DE">Germany</option></select><br/><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>

No selection

To allow for no selection, add a “not specified” option to the select list. If the property is a value type, you’ll have to make it nullable.

The correct <option> element will be selected ( contain the selected="selected" attribute) depending on the current Country value.

<formmethod="post"action="/Home/IndexEmpty"><selectid="Country"name="Country"><optionvalue="">&lt;none&gt;</option><optionvalue="MX">Mexico</option><optionvalue="CA"selected="selected">Canada</option><optionvalue="US">USA</option></select><br/><buttontype="submit">Register</button><inputname="__RequestVerificationToken"type="hidden"value="<removed for brevity>"/></form>