MVC 6 Form Tag Helper

So for in my series covering MVC 6 tag helpers, I have covered all the tag helpers that you would use to generate the contents of a form:

In this post, I will cover the Form tag helper that is used to bind a Form element to a particular MVC controller action or named route. This tag helper is an alternative to the following HTML helper method syntax:

@using (Html.BeginForm("ControllerName", "ActionName"))
{
   //Form Contents Here
}
@using (Html.BeginForm("ControllerName", "ActionName"))
{
   //Form Contents Here
}

Binding to Controller Action

With the form tag helper, you can bind a form to a specific controller action by adding the asp-controller and asp-action tag helper attributes to a form element.

For example, you can bind a form to the Login action of the Account controller as follows:

<form asp-controller="Account" 
      asp-action="Login">
//Your form elements here
</form>
<form asp-controller="Account" 
      asp-action="Login">
//Your form elements here
</form>

Any elements that you add inside the form will be included in the generated HTML. The example above would generate the following HTML:

<form action="/Account/Login" method="post">
 
//Your form elements here
 
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>
<form action="/Account/Login" method="post">

//Your form elements here

    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>

The form method was defaulted to post. You can specify this manually in your markup if you want. Any HTML attributes you add to the form element will be included in the generated HTML. However, if you attempt to both manually set the action attribute AND the asp-controller / asp-action attributes, the form tag helper will raise an error.

Cannot override the ‘action’ attribute for <form>. A <form> with a specified ‘action’ must not have attributes starting with ‘asp-route-‘ or an ‘asp-action’ or ‘asp-controller’ attribute.

The form tag helper also automatically adds an Anti forgery token which will cover in more detail below.

Adding Parameters

In some cases, you might need to specify additional parameters for the controller action that you are binding to. You can specify values for these parameters by adding attributes with the asp-route- prefix. For example, it is common for the Login action to have a returnUrl parameter. This can be specified as follows:

<form asp-controller="Account" 
      asp-action="Login" 
      asp-route-returnurl="@ViewBag.ReturnUrl" 
      method="post" >
</form>
<form asp-controller="Account" 
      asp-action="Login" 
      asp-route-returnurl="@ViewBag.ReturnUrl" 
      method="post" >
</form>

…which would generate a form element with the action attribute containing the specified value for the returnurl parameter:

<form action="/Account/Login?returnurl=%2FHome%2FAbout" method="post">
 
//Your form elements here
 
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>
<form action="/Account/Login?returnurl=%2FHome%2FAbout" method="post">

//Your form elements here

    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>

You can specify values for as many parameters as you need using attributes with the asp-route- prefix.

Binding to a Named Route

Another option is to specify the controller and action using a named route.  For example, if I had a route named login defined as follows in my MVC route configuration:

routes.MapRoute(
    name: "login",
    template: "login",
    defaults: new { controller = "Account", action = "Login" });
routes.MapRoute(
    name: "login",
    template: "login",
    defaults: new { controller = "Account", action = "Login" });

Then I could bind my form to the login route using the asp-route tag helper attribute:

<form asp-route="login" 
      asp-route-returnurl="@ViewBag.ReturnUrl" 
      method="post" >
</form>
<form asp-route="login" 
      asp-route-returnurl="@ViewBag.ReturnUrl" 
      method="post" >
</form>

…which would generate the following HTML:

<form action="/login?returnurl=%2FHome%2FAbout" method="post">
 
//Your form elements here
 
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>
<form action="/login?returnurl=%2FHome%2FAbout" method="post">

//Your form elements here

    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgqnOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg">
</form>

Anti-Forgery Token Option

As we saw earlier, the form tag helper attribute adds a hidden __RequestVerificationToken input. This hidden input contains an anti-forgery token that when used in combination with the [ValidateAntiForgeryToken] attribute on the controller action will help to protect your application against cross-site request forgery. You really should use this on all your forms but if for some reason you need to turn this off for a particular form, you can simply set the asp-anti-forgery token to false.

<form asp-controller="Account" 
      asp-anti-forgery="false"
      asp-action="Login">
//Your form elements here
</form>
<form asp-controller="Account" 
      asp-anti-forgery="false"
      asp-action="Login">
//Your form elements here
</form>

Conclusion

That wraps up the functionality provided by the form tag helper in MVC 6. I think it provides a much cleaner syntax than the @using(Html.BeginForm()){…} syntax. What do you think? What will be your preferred syntax for forms in MVC 6?

MVC6 Select Tag Helper

In this post from my series exploring the MVC 6 tag helpers, I will be covering the select tag helper.

The select tag helper is used to generated select and associated option elements for properties of your models. This is an alternative to the Html.DropDownListFor HTML helper method.

Select Tag Helper

The select tag helper is used by adding the asp-for attribute to a select element. For example consider a simple view model class containing a CountryCode property:

public class SimpleViewModel
{
    public string CountryCode { get; set; }
}
public class SimpleViewModel
{
    public string CountryCode { get; set; }
}

You can bind a select element to the CountryCode property as follows:

<select asp-for="CountryCode"></select>
<select asp-for="CountryCode"></select>

…which would generate the following HTML:

<select name="CountryCode" 
           id="CountryCode"></select>
<select name="CountryCode" 
           id="CountryCode"></select>

Now this is not overly useful because it is an empty drowdown list. You will probably want to add some options to your select.

Adding options

There are a couple ways you can add options to the select. You can simply add options directly in the markup:

<select asp-for="CountryCode">
    <option value="CA">Canada</option>
    <option value="US">US</option>
    <option value="--">Other</option>
</select>
<select asp-for="CountryCode">
    <option value="CA">Canada</option>
    <option value="US">US</option>
    <option value="--">Other</option>
</select>

In this case, the options specified in markup will be included in the generated HTML. The selected option will automatically be determined based on the value of the model property. For example, if the CountryCode property is set to ‘CA’ in the model, then the following HTML would be generated:

<select name="CountryCode" id="CountryCode">
    <option selected="selected" value="CA">Canada</option>
    <option value="US">US</option>
    <option value="--">Other</option>
</select>
<select name="CountryCode" id="CountryCode">
    <option selected="selected" value="CA">Canada</option>
    <option value="US">US</option>
    <option value="--">Other</option>
</select>

If the list of options is dynamically loaded from a data source, you can use the asp-items tag helper attribute. All you need to do is set the asp-items attribute to an IEnumerable<SelectListItem>. For example, if we had a list of countries available on the ViewBag, we could specify the select options as follows:

<select asp-for="CountryCode" 
         asp-items="ViewBag.Countries">
</select>
<select asp-for="CountryCode" 
         asp-items="ViewBag.Countries">
</select>

This will generate a select with options for each of the SelectListItems in the Countries collection.

Multiple Select

The select tag helper will automatically generate a multi-select if the property specified in the asp-for attribute is an IEnumerable. For example, given the following model class:

public class SimpleViewModel
{
    public IEnumerable<string> CountryCodes { get; set; }
}
public class SimpleViewModel
{
    public IEnumerable<string> CountryCodes { get; set; }
}

Binding the asp-for attribute to the CountryCodes property as follows:

<select asp-for="CountryCodes" 
        asp-items="ViewBag.Countries">
</select>
<select asp-for="CountryCodes" 
        asp-items="ViewBag.Countries">
</select>

…would generate the following HTML:

<select name="CountryCodes" 
        id="CountryCodes" 
        multiple="multiple">
    <option selected="selected" 
            value="CA">Canada</option>
    <option value="USA">United States</option>
    <option value="--">Other</option>
</select>
<select name="CountryCodes" 
        id="CountryCodes" 
        multiple="multiple">
    <option selected="selected" 
            value="CA">Canada</option>
    <option value="USA">United States</option>
    <option value="--">Other</option>
</select>

Conclusion

That covers all the functionality provided by the select tag helper in MVC 6, which provides a clean syntax for generating select elements based on the values in your model. In the next post, I will cover the Form tag helper.