Get up to 80 % extra points for free! More info:

Lesson 5 - Form handling in ASP.NET Core MVC

In the previous lesson, First web application in ASP.NET Core MVC, we tried the MVC architecture in practice and learned how to pass data from the model to the view. We said that we use a special collection (mostly ViewBag) to do so. But there's also a second way and that's to connect the model directly to the View. This technique is called model binding. This is very useful when working with forms and we're gonna try it in today's ASP.NET Core tutorial. We'll program a simple calculator.

Let's create a new ASP.NET Core Web Application named MVCCalculator. Even though we could start with an empty template, we'll now choose the MVC template.

Creating a new ASP.NET MVC project - ASP.NET Core MVC Basics

This way, the folders for the MVC components will be generated for us, together with the routes and configurations that we've done manually last time. A sample project including several sliders and even the famous EU cookie message will be also generated. You can try to run it. We didn't use it last time in order to better understand how the MVC works and so it didn't distract us unnecessarily.

The default project in ASP.NET Core MVC - ASP.NET Core MVC Basics

We won't need this project and therefore we'll remove the contents of the Models/, Controllers/, and Views/ folders in the Solution Explorer, but keep the _ViewImports.cshtml file, otherwise, tag helpers (see below) won't work properly. If we started with an empty project like last time, we'd have to add this file manually. Don't use only Calculator as the project name, as it'd conflict with the name of our class.

Let's show how our finished calculator will look like:

An ASP.NET Core MVC calculator - ASP.NET Core MVC Basics

Model

Let's start with the model again which will be the Calculator class. Add it to the Models/ folder. We'll add several public properties to the model, particularly, two input numbers, the selected operation, and the result. The last property will be a list of the SelectListItem type that will include possible operations for the view. It'll be rendered as the <select> HTML element later. We'll fill the list straight in the constructor. Don't forget to add using Microsoft.AspNetCore.Mvc.Rendering.

public class Calculator
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public double Result { get; set; }
    public string Operation { get; set; }
    public List<SelectListItem> PossibleOperations { get; set; }

    public Calculator()
    {
        PossibleOperations = new List<SelectListItem>();
        PossibleOperations.Add(new SelectListItem { Text = "Add", Value = "+", Selected = true });
        PossibleOperations.Add(new SelectListItem { Text = "Subtract", Value = "-" });
        PossibleOperations.Add(new SelectListItem { Text = "Multiply", Value = "*" });
        PossibleOperations.Add(new SelectListItem { Text = "Divide", Value = "/" });
    }

}

The Text property of the SelectListItem class is the label of the option the user can see. The Value is the value that is sent to the server (it shouldn't contain any non-alphanumeric characters except for dashes or underscores). We can also set the Selected property to indicate whether the item should be selected when the page is loaded.

The only thing left is a method with some logic that, according to the selected Operation and values in Number1 and Number2, calculates the Result:

public void Calculate()
{
    switch (Operation)
    {
        case "+":
            Result = Number1 + Number2;
            break;
        case "-":
            Result = Number1 - Number2;
            break;
        case "*":
            Result = Number1 * Number2;
            break;
        case "/":
            Result = Number1 / Number2;
            break;
    }
}

The result is stored to the Result property after calling the method. We could also return the result, as we did in the previous project with the random numbers. But for our further intentions with binding, this will be more useful.

We have the model ready, let's add the controller.

Controller

We'll have only one controller in our application. You surely remember that the controller wires up the model (logic) and view (HTML template). We'll add a new Empty Controller and name it HomeController. So it'll be called when we open the homepage of our application. Let's move to its code and edit the Index() method as follows:

public IActionResult Index()
{
    Calculator calculator = new Calculator();
    return View(calculator);
}

When we open the page, the Index() method is called, we already know that. At this time, we create a new model instance, which is still the same thing we did in the previous lesson. However, this time, we pass the model to the view as a parameter. Don't forget to add using MVCCalculator.Models again.

View

We'll generate the view for the Index() action. We'll do this as always by clicking anywhere in the method by the right mouse button and choosing Add View. As the Template, choose Create, and set the Model class to Calculator.

Scaffolding in ASP.NET Core MVC - ASP.NET Core MVC Basics

The template allows us to pre-generate some code right to the view, this technique is called scaffolding. The Create template generates a view with a form for the properties of the selected model, wired to this model to create a new model instance. Now when we run the app it looks like this:

https://local­host:44337
https://local­host:44337

We can see that Visual Studio generated a total of 4 inputs for the numbers, result, and operation. However, we'd like to specify the operation using the <select> element and print the result into the HTML <p> paragraph instead of a form field.

For this reason, let's move to Index.cshtml and change it to the following form:

@model MVCCalculator.Models.Calculator

@{
    ViewData["Title"] = "Calculator";
}

<head>
    <title>@ViewData["Title"]</title>
</head>

<body>
<h2>Index</h2>

<h4>Calculator</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Index">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Number1" class="control-label"></label>
                <br />
                <input asp-for="Number1" class="form-control" />
                <span asp-validation-for="Number1" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Number2" class="control-label"></label>
                <br />
                <input asp-for="Number2" class="form-control" />
                <span asp-validation-for="Number2" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Operation" class="control-label"></label>
                <br />
                @Html.DropDownListFor(model => model.Operation, new SelectList(Model.PossibleOperations, "Value", "Text"))
                <span asp-validation-for="Operation" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Calculate" class="btn btn-default" />
            </div>

            <p style="font-size: 2em;">@Model.Result</p>

        </form>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
</body>

We've made only minimum changes compared to the original template. At the very beginning of the template, we set the type of the model to which the view is bound. Next, we set the page title and the subtitle. Note that since we don't insert the template into a layout, we added the <head> and <body> elements into it. Next, there's a form generated by Visual Studio and we've only edited it.

We add individual editing fields for the model properties the following way:

<div class="form-group">
    <label asp-for="PropertyName" class="control-label"></label>
    <br />
    <input asp-for="PropertyName" class="form-control" />
    <span asp-validation-for="PropertyName" class="text-danger"></span>
</div>

The asp-for attributes are called tag helpers by which ASP.NET Core can generate an appropriate control element for our property. E.g. a DatePicker is rendered for dates and so on. The asp-validation-for attributes insert a space for the error message in the case when the user fills the field incorrectly. This is again detected from the property data type and everything is completely automatized. A minor disadvantage is that we pass properties to the helpers as strings, which you've certainly noticed. Fortunately, Visual Studio is still able to verify such code.

You can see that we combine tag helpers with the older approach of inserting controls using IHtmlHelper(@Html). Not all the controls are currently supported by tag helpers, sometimes we can't avoid this solution. However, we prefer to wire form elements to the model properties using tag helpers and asp-for rather than at-signs. We want the HTML template to look as much as HTML code as possible :)

To make the tag helpers work in your project, you need to have a file called _ViewImports.cshtml in it with the following contents. If you have followed the tutorial, the file is already included in the project. If you accidentally deleted this file or started with an empty project, you can create it now:

@using MVCCalculator
@using MVCCalculator.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

At the bottom of the page, we'll print the Result property of the model into an HTML <p> paragraph, so we can display it to the user.

Our form now looks like this:

An MVC calculator in ASP.NET Core - ASP.NET Core MVC Basics

Once the form is submitted, nothing happens yet. We'll continue next time.

In the next lesson, Data processing and validations in ASP.NET Core MVC, we'll finish the app. If you've made a mistake somewhere, you can also download the complete project code in the next lesson.


 

Previous article
First web application in ASP.NET Core MVC
All articles in this section
ASP.NET Core MVC Basics
Skip article
(not recommended)
Data processing and validations in ASP.NET Core MVC
Article has been written for you by Martin Petrovaj
Avatar
User rating:
1 votes
Activities