I recently started learning Asp.Net with Razor Pages and I'm working on this project where users can enter his name last name and pin code for his credit card and if inputs are in the database, it redirects him to user page and shows him how much money he has on his card.
But my validation is wrong, even when input is not in the database or is different from values in the database it redirects me to User page.Can someone help me to make my validation right.
Thanks in advance.
Here is all my code:
Index page:
#page
#model BanlAcc.Pages.BankAcc.IndexModel
<br />
<h2 class="text-info">Enter your data</h2>
<div class=" border container" style="padding: 30px;">
<form method="post">
<div class="text-danger" asp-validation-summary="ModelOnly"></div>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Name"></label>
</div>
<div class="col-6">
<input asp-for="Account.Name" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Name"></span>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Surname"></label>
</div>
<div class="col-6">
<input asp-for="Account.Surname" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Surname"></span>
<div class="form-group row">
<div class="col-3">
<label asp-for="Account.Pin"></label>
</div>
<div class="col-6">
<input asp-for="Account.Pin" class="form-control" />
</div>
</div>
<span class="text-danger" asp-validation-for="Account.Pin"></span>
<div class="form-group row">
<div class="col-3">
<input type="submit" value="Check" class="btn btn-primary form-control" />
</div>
</div>
</form>
</div>
#section Scripts{
<partial name="_ValidationScriptsPartial" />
}
Index.cshtml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BanlAcc.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
namespace BanlAcc.Pages.BankAcc
{
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
private object _userRepository;
public IndexModel(ApplicationDbContext db)
{
_db = db;
}
[BindProperty]
public Account Account { get; set; }
public void OnGet()
{
}
public IActionResult OnPost()
{
if (ModelState.IsValid)
{
return RedirectToPage("User");
}
else
{
return Page();
}
}
}
}
Account.cs:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace BanlAcc.Model
{
public class Account
{
[Key]
public int Id { get; set; }
[Required, MaxLength(20)]
public string Name { get; set; }
[Required, MaxLength(20)]
public string Surname { get; set; }
[Required]
public int Pin { get; set; }
public int Amount { get; set; }
}
}
User page:
#page
#model BanlAcc.Pages.BankAcc.AccountModel
<br />
<h2 class="text-info">Wellcome</h2>
Related
When saving the details from the view, the details is not binding into the nested class (BOUser) in ViewModel.The nested class data is showing null(Refer the debug result image). I am using .net core 6 in Mac for the development. Please help me out what I am missed in this coding.
Controller Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NearMeBuy.Models.Masters.ViewModels;
namespace NearMeBuyWebApp.Areas.Admin.Controllers
{
[Area("Admin")]
public class TestOPSController : Controller
{
public IActionResult Index()
{
RegisterVM registerVM = new RegisterVM()
{
ApplicationRoles = null,
BOUser = new(),
DepartmentMaster = null,
Mode = 1
};
return View(registerVM);
}
[HttpPost]
public IActionResult Index(RegisterVM vM )
{
if (ModelState.IsValid)
{
return View("Hi");
}
return View();
}
}
}
View Model Class
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Rendering;
using NearMeBuy.Models.Tokens.User;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NearMeBuy.Models.Masters.ViewModels
{
public class RegisterVM
{
public int Mode { get; set; }
//public RegisterModel RegisterModel { get; set; }
public BOUser BOUser { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem> ApplicationRoles { get; set; }
[ValidateNever]
public IEnumerable<SelectListItem> DepartmentMaster { get; set; }
}
}
BOUser Class
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.EntityFrameworkCore;
namespace NearMeBuy.Models.Masters
{
public class BOUser
{
public string UserId { get; set; }
[Required(ErrorMessage = "First Name can't be empty")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name can't be empty")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email can't be empty")]
public string Email { get; set; }
[Required(ErrorMessage = "Phone can't be empty")]
public string PhoneNo { get; set; }
[Required(ErrorMessage = "Username can't be empty")]
public string UserName { get; set; }
[Required(ErrorMessage = "Account Confirmation can't be empty")]
public bool AccountConfirmed { get; set; } = false;
/// <summary>
/// The user type field to store the type of user 1: for BackOffice User , 2: for Supplier Registration, 3: for End Users/ Customers.
/// </summary>
[Required(ErrorMessage = "User Type Field can't be empty")]
[Comment("The user type field to store the type of user 1: for BackOffice User , 2: for Supplier Registration, 3: for End Users/ Customers., 0: for Administrator")]
public Int16 UserType { get; set; }
[Required(ErrorMessage = "Password can't be empty")]
public string Password { get; set; }
[ValidateNever]
public string? returnUrl { get; set; }
}
}
View
#model RegisterVM
#{
ViewData["Title"] = "Register Page";
}
<form id="registrationForm" asp-controller="TestOPS" asp-action="Index" method="post">
<div class="card">
<div class="card-header">
<h5 class="card-title">
#{
#if (#Model.Mode == 1)
{
<b>Create</b>
}
else if (#Model.Mode == 2)
{
<b>Edit</b>
}
else if (#Model.Mode == 3)
{
<b>Delete</b>
}
}
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-12">
<input type="hidden" id="hdnMode" asp-for="Mode" />
<input type="hidden" id="hdnUserId" asp-for="BOUser.UserId" />
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>First Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="#Model.BOUser.FirstName" name="firstname" />
<span asp-validation-for="BOUser.FirstName" class="text-danger"></span>
</div>
<div class="col-lg-2">
<label>Last Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.LastName" name="lastname" />
<span asp-validation-for="BOUser.LastName" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Email</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.Email" name="email" />
<span asp-validation-for="BOUser.Email" class="text-danger"></span>
</div>
<div class="col-lg-2">
<label>Phone No.</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.PhoneNo" name="phoneno" />
<span asp-validation-for="BOUser.PhoneNo" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>User Name</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.UserName" name="username" />
<span asp-validation-for="BOUser.UserName" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Password</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" asp-for="BOUser.Password" name="password" id="txtPassword" />
<span asp-validation-for="BOUser.Password" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Confirm Password</label>
</div>
<div class="col-lg-4 form-group">
<input class="form-control form-control-sm" name="confirmPassword" />
<span asp-validation-for="BOUser.Password" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Roles</label>
</div>
<div class="col-lg-5">
<table>
#if (Model.ApplicationRoles != null)
{
#foreach (var roles in Model.ApplicationRoles)
{
<tr>
<td>
<input id="#roles.Value" type="checkbox" name="roles" value="#roles.Value" checked="#roles.Selected" asp-for="#roles.Selected" />
</td>
<td>
<label asp-for="#roles.Value">#roles.Text</label>
</td>
</tr>
}
}
</table>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Department</label>
</div>
<div class="col-lg-5">
<table>
#if (Model.DepartmentMaster != null)
{
#foreach (var dept in Model.DepartmentMaster)
{
<tr>
<td>
<input id="#dept.Value" type="checkbox" name="departments" value="#dept.Value" checked="#dept.Selected" asp-for="#dept.Selected" />
</td>
<td>
<label asp-for="#dept.Value">#dept.Text</label>
</td>
</tr>
}
}
</table>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label>Approved</label>
</div>
<div class="col-lg-4">
<input type="checkbox" asp-for="BOUser.AccountConfirmed" />
</div>
</div>
</div>
<div class="card-footer text-right">
<input type="submit" class="btn btn-secondary" value="Save" />
</div>
</div>
</form>
#section Scripts{
<script src="~/js/regLogin.js"></script>
}
Debug Result
enter image description here
Remove a name attirbute from ALL web controls, for example should be just
<input class="form-control form-control-sm" asp-for="BOUser.LastName" />
When I try to get data from data for edit page it's showing me the following error:
So I am building a website where I want to implement a edit banner form when the User can Edit his banner data.
And here is where the problem I raise, when I run the code, it return always as null.
Here is my controller:
[HttpGet]
public ActionResult EditBanner(int id)
{
var abd = (from a in _db.Banner
where id == a.BannerId
select a).FirstOrDefault();
return View(abd);
}
[HttpPost]
public ActionResult UpdateBannerDatas(BannerViewModels bnrupdate)
{
var bnrdata = _db.Banner.Where(x => x.BannerId == bnrupdate.BannerId).FirstOrDefault();
if (bnrdata != null)
{
bnrdata.BannerTitle = bnrupdate.BannerTitle;
bnrdata.BannerUrl = bnrupdate.BannerUrl;
bnrdata.BannerIndex = bnrupdate.BannerIndex;
bnrdata.BannerDescription = bnrupdate.BannerDescription;
bnrdata.BannerIndex = bnrupdate.BannerIndex;
_db.SaveChanges();
}
return Redirect("BannerDetails");
}
Here is my viewmodel:
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SZGMC.Web.Models;
namespace SZGMC.Web.Areas.Admin.ViewModels
{
public class BannerViewModels
{
public int BannerId { get; set; }
public string BannerTitle { get; set; }
public string BannerDescription { get; set; }
public string BannerImg { get; set; }
public IFormFile BannerImg1 { get; set; }
public string BannerUrl { get; set; }
public string BannerIndex { get; set; }
public int? BMasterId { get; set; }
public byte? IsDeleted { get; set; }
public virtual BannerMaster BMaster { get; set; }
}
}
Here is my model:
using System;
using System.Collections.Generic;
// Code scaffolded by EF Core assumes nullable reference types (NRTs) are not used or disabled.
// If you have enabled NRTs for your project, then un-comment the following line:
// #nullable disable
namespace SZGMC.Web.Models
{
public partial class Banner
{
public int BannerId { get; set; }
public string BannerTitle { get; set; }
public string BannerDescription { get; set; }
public string BannerImg { get; set; }
public string BannerUrl { get; set; }
public string BannerIndex { get; set; }
public int? BMasterId { get; set; }
public byte? IsDeleted { get; set; }
public virtual BannerMaster BMaster { get; set; }
}
}
Here is my view:
<form asp-controller="Home" asp-action="UpdateBannerDatas" enctype="multipart/form-data" method="post">
<div id="main-content">
<div class="container-fluid">
<!-- Page header section -->
<div class="block-header">
<div class="row clearfix">
<div class="col-lg-6 col-md-5 col-sm-12">
<h1>Hi, Welcomeback!</h1>
<span>You can edit banner here</span>
</div>
<div class="col-xl-6 col-md-7 col-sm-12 text-md-right">
<div class="d-flex align-items-center justify-content-md-end mt-4 mt-md-0 flex-wrap vivify pullUp delay-550">
<div class="mb-3 mb-xl-0 ">
<a asp-action="BannerDetails" class="btn btn-dark">Banner List</a>
</div>
</div>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-12">
<div class="card">
<div class="body">
<div class="header">
<h2><strong>Enter Banner Details</strong></h2>
</div>
<br />
<input asp-for="BannerId" type="hidden" />
<div class="row">
<div class="col-12">
<div class="form-group c_form_group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"></span>
</div>
<input type="text" class="form-control" asp-for="BannerTitle" placeholder="Banner Title" aria-label="bannertitle" aria-describedby="basic-addon1">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-group c_form_group">
<label>Banner Description</label>
<div class="input-group">
<textarea class="form-control" asp-for="BannerDescription" aria-label="Banner Description" rows="6"></textarea>
</div>
</div>
</div>
<div class="col-6">
<div class="drop-zone">
<span class="drop-zone__prompt">Drop file here or click to upload</span>
<input type="file" asp-for="BannerImg1" name="myFile" class="drop-zone__input" accept="image/*" data-allowed-file-extensions='["jpg", "png" , "jpeg"]' required>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-group c_form_group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"></span>
</div>
<input type="text" class="form-control" asp-for="BannerIndex" placeholder="Banner Index" aria-label="bannerindex" aria-describedby="basic-addon1">
</div>
</div>
</div>
<div class="col-6">
<div class="form-group c_form_group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"></span>
</div>
</div>
</div>
</div>
</div>
<div class="mb-2" align="center">
<button type="submit" class="btn btn-success btn-round">Edit Banner</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
When i try To Edit the data in the browser it Throw exception, in database i have value but when i tried to fetch data its showing error.
thank you in advance to everybody for any help or advice.
According to the error message it is necessary to pass the BannerViewModels instance instead of the Banner entity:
public ActionResult EditBanner(int id)
{
var abd = _db.Banner.Where(a => a.BannerId == id)
.Select(b => new BannerViewModels()
{
BannerId = b.BannerId,
BannerTitle = b.BannerTitle,
BannerDescription = b.BannerDescription,
BannerImg = b.BannerImg,
BannerUrl = b.BannerUrl,
BannerIndex = b.BannerIndex,
BMasterId = b.BMasterId,
IsDeleted = b.IsDeleted
})
.FirstOrDefault();
return View(abd);
}
Passing an entity to the view as a data model is bad idea.
See the following post: Why it's not a good idea to pass entities as Models in MVC?
I am a beginner really and not quite grasping why I have this issue. I am wanting fill a drop down menu with names from the Types model. I am using the Types model as a lookup referencing a parent table. Below is my Types model. I know I am missing something glaringly obvious but experience isnt on my side here
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace MaskFit.Model
{
public class Types
{
[Key]
public int TypeId { get; set; }
public string Name { get; set; }
}
}
And here is my page where I am attempting to implement a foreach but running into an error shown below
#model MaskFit.Pages.MaskList.CreateModel
#{
<h2 class="text-info">Create New Mask Fitting</h2>
<br />
<div class="border container" style="padding : 30px;">
<form method="post">
<div class="text-danger" asp-validation-summary="ModelOnly"></div>
<div class="form-group row">
<div class="col-2">
<label asp-for="MaskFittings.Surname"></label>
</div>
<div class="col-6">
<input asp-for="MaskFittings.Surname" class="form-control" />
</div>
<span asp-validation-for="MaskFittings.Surname" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="MaskFittings.FirstName">First Name</label>
</div>
<div class="col-6">
<input asp-for="MaskFittings.FirstName" class="form-control" />
</div>
<span asp-validation-for="MaskFittings.FirstName" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="MaskFittings.TypeId">Mask Type</label>
</div>
<div class="col-6 form-group">
<select class="form-control" id="exampleFormControlSelect1" asp-for="MaskFittings.TypeId">
<option selected disabled>Choose...</option>
#foreach (var type in Model.Types)
{
<option value="#type.TypeId">#type.Name</option>
}
</select>
#*<input class="form-control" />*#
</div>
You change your model Types class to:
public class MyType
{
[Key]
public int TypeId { get; set; }
public string Name { get; set; }
}
and add new model class for View
public class ModelForPage
{
public List<MyType> Types { get; set; }
}
Property Types is data source for your select control in page.
I'm setting up a first C# ASP.NET MVC application using Microsofts tutorial. https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-2.2&tabs=visual-studio
In the process of this tutorial, it asks to check if the create movies works, but when I attempt to use it, I get an HTTP error 400 - bad request. I believe the data I am entering is accurate, but I can't seem to get anything but a bad request, does anyone know how to fix this.
Model class:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
Razor view:
#model MvcMovie.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Controller action method:
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
The expected output is to add to the database, but but the actual output is bad request.
Do you have httpPost over method of controller and why you not use model?
[HttpPost]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price")] ....
I was using google chrome, and firefox. Apparently it won't let me test on anything except edge or IE
I have an ASP.NET Core application with Entity framework 7.
I am using Data annotations to display warnings when editing content on the website.
When adding the input field and their respective warning span in a loop this didn't work.
It is blocking the submit, it is not showing any warning.
Am I doing something wrong?
my code:
Razor view:
#model Receptenboek.Models.RecipeViewModels.RecipeEdit
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Recipe</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Recipe.ID" />
<input type="hidden" asp-for="Recipe.Ingredients" />
<div class="form-group">
<label asp-for="Recipe.Name" class="control-label"></label>
<input asp-for="Recipe.Name" class="form-control" />
<span asp-validation-for="Recipe.Name" class="text-danger"></span>
</div>
<div class="form-group">
<h3 asp-for="Book" class="control-label">Book</h3>
<select asp-for="Recipe.RecipeBookID" asp-items="#(new SelectList(Model.Books, "ID", "BookName", Model.Recipe.RecipeBookID))"></select><br />
<span asp-validation-for="Books" class="text-danger"></span>
</div>
<div id="fields" class="form-actions">
#foreach (Recipe_Ingredient ri in Model.Recipe.Ingredients)
{
<div id="IngredientDiv">
<label class="control-label">Ingredient name </label><br />
<select name="ingredients" asp-for="#ri.IngredientID" asp-items="#(new SelectList(Model.Ingredients, "ID", "Name"))"></select><br />
<label class="control-label">Amount </label>
<input name="Amount" class="form-control" asp-for="#ri.Amount" asp-route-amounts="#ViewData["amounts"]" />
<span asp-validation-for="#ri.Amount" class="text-danger"></span>
<hr />
</div>
}
</div>
<span class="text-danger">#ViewData["Warning"]</span><br/>
<a onclick="duplicate()">Add Ingredient</a>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Receptenboek.Models.RecipeViewModels
{
public class RecipeEdit
{
public Recipe Recipe { get; set; }
public ICollection<Ingredient> Ingredients { get; set; }
public ICollection<RecipeBook> Books { get; set; }
}
}
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Receptenboek.Models
{
public class Recipe
{
public int ID { get; set; }
[Required]
[Display(Name = "Book")]
public int RecipeBookID { get; set; }
[Required]
[Display(Name = "Recipe Name")]
public string Name { get; set; }
public ICollection<Recipe_Ingredient> Ingredients { get; set; }
public RecipeBook Book { get; set; }
}
}
Because you are using a foreach loop, your code will render HTML with duplicate IDs. This will cause the model binding to fail on POST. You need to replace it with a for loop and then either;
Use the index to distinguish the different items such as in this solution: ASP.NET Core 1.0 POST IEnumerable<T> to controller
Use Html.EditorFor such as in this documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-input-tag-helper