Unit-4 Creating ASPdotnet Core MVC Application2
Unit-4 Creating ASPdotnet Core MVC Application2
The model classes represents domain-specific data and business logic in the
MVC application. It represents the shape of the data as public properties and
business logic as methods.
A very important aspect of the MVC pattern is the Separation of Concerns.
SoC is achieved by encapsulating information inside a section of code,
making each section modular, and then having strict control over how each
module communicates. For the MVC pattern, this means that both the View
and the Controller can depend on the Model, but the Model doesn't depend
on neither the View nor the Controller. This turns your Models into a module
that can exist even outside of the MVC framework, e.g. for use in a desktop
application, and then it has the added benefit of allowing your Models to be
tested without the visual representation, e.g. through the use of unit tests.
As mentioned, the Model can be a class already defined in your project, or it
can be a new class you add specifically to act as a Model. Therefore, Models
in the ASP.NET MVC framework usually exists in a folder called "Models", or
they come from outside of the project, e.g. from a class library.
Adding a Model
In the ASP.NET Core MVC Application, all the Model classes must be created in
the Models folder.
To create the model class that should have the required properties for
the Employee entity.
In the MVC application in Visual Studio, and right-click on the Models folder,
select Add -> and click on Class... It will open the Add New Item dialog box.
In the Add New Item dialog box, enter the class name Employee and click
Add.
This will add a new Employee class in model folder.
http://localhost:5000/home/details/101
Our application default route template ({controller=Home}/{action=Index}/{Id?}) routes the above GET
request to the Details(int Id) action method of the HomeController. The following image shows
the Details action method of the Home Controller.
http://localhost:5000/home/details?id=101&name=dotnet
The above GET request will handle by the Details action method and it will map the value
101 to the Id parameter and the value dotnet will be mapped to the name parameter of the
Details action method.
HTTP Request Data Sources:
ASP.NET Core MVC uses three primary data sources to map the HTTP requests
data to the action method parameter in the following order:
The Model Binding in ASP.NET Core Application also works with complex user defined
types like Customer, Student, Order, Product, etc. Let us understand this with a
Create Student form example
Add the following Create method to the Student Controller. When the above form is
posted, this is the method which is going to handle the request. Decorate the
method with HttpPost attribute.
[HttpPost]
public ActionResult Create(Student student)
{
student.StudentId = listStudents.Max(x => x.StudentId) + 1;
listStudents.Add(student);
return View("Details", student);
}
When the form is submitted, the values in the form are mapped to the Student object
parameter to the Post Create action method. The Model binder in asp.net core application
binds the posted form values to the properties of the Student object that is passed as a
parameter to the Create() action method.
The value in the input element that has the name attribute set to “Name” is mapped to the
Name property of the Studnet object. Similarly, the value in the Address input element will
be mapped to the Address property of the Student object. This is going to be same for the
rest of the properties like Email and Gender.
Using Model Binding
Create a simple Model class for handling information about a student
<div>
@Html.LabelFor(m => m.City)
@Html.TextBoxFor(m => m.City)
</div>
Note: The ASP.NET Core MVC framework automatically converts request values into a
primitive or complex type object. Model binding is a two-step process. First, it collects
values from the incoming HTTP request, and second, it populates primitive type or a
complex type with these values.
Data Annotations
DataAnnotations is used to configure model classes, which will highlight the most
commonly needed configurations. Sometimes, it can be relevant for a View to know
more about a property on a Model than just its name and type. For these situations,
ASP.NET Core MVC comes with the concept of DataAnnotations (sometimes referred
to as Model Attributes), which basically allows to add meta data to a property.
As an example, we might want to change the display version of the First Name
property to “First Name”
A lot of the available DataAnnotations are actually directly related to the validation
mechanisms found in the ASP.NET Core MVC framework. They will allow you to
enforce various kinds of rules for your properties, which will be used in your Views
and in your Controllers, where you will be able to check whether a certain Model is valid
in its current state or not (e.g. after a FORM submission).
public class Employee
{
[Required]
[StringLength(25)]
public string FirstName { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string LastName { get; set; }
[Required]
[EmailAddress]
public string EmailAddress { get; set; }
}
The three properties have all been decorated with
DataAnnotations, giving the framework useful information for
validating the data. First of all, all properties have been
marked with the [Required] attribute, meaning that a value is
required - it can't be NULL. We have also used the
[StringLength] attribute to make requirements about the
maximum, and in one case minimum, length of the strings.
These are of course particularly relevant if your Model
corresponds to a database table, where strings are often
defined with a maximum length. For the last property, we
have used the [EmailAddress] attribute to ensure that the
value provided looks like an e-mail adress.
@model WebApplication1.Models.Employee
@using(var form = Html.BeginForm())
{
<div>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
</div>
<div>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)
</div>
<div>
@Html.LabelFor(m => m.EmailAddress)
@Html.TextBoxFor(m => m.EmailAddress)
</div>
Depending on the data you submitted in the FORM, IsValid property of the
ModelState object will be either true or false, based on the validation rules we
defined for the Model (Employee). With this in place, you can now prevent a Model
from being saved, e.g. to a database, unless it's completely valid.
Displaying validation errors
First of all, we need to extend our FORM so that it can display error messages to the user. We can use another
helper method found on the Html object: The ValidationMessageFor() method. It will simply output the error
message related to the field, if there is one - otherwise, nothing will be outputted. Here's the extended
version of the FORM
@model WebApplication1.Models.Employee
@using(var form = Html.BeginForm())
{
<div>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
@Html.ValidationMessageFor(m => m.FirstName)
</div>
<div>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)
@Html.ValidationMessageFor(m => m.LastName)
</div>
<div>
@Html.LabelFor(m => m.EmailAddress)
@Html.TextBoxFor(m => m.EmailAddress)
@Html.ValidationMessageFor(m => m.EmailAddress)
</div>
<input type="submit" value="Submit" />
}
We also need to make sure that once the FORM is submitted, and if there are
validation errors, we return the FORM to the user, so that they can see and fix these
errors. We do that in our Controller, simply by returning the View and the current
Model state, if there are any validation errors.
[HttpPost]
public IActionResult Create(Employee employee)
{
if (ModelState.IsValid)
return Content(“Validation Successful");
else
return View(employee);
}
If you try submitting the FORM with a value that doesn't meet the StringLength
requirements, you will notice that there are even automatically generated error
messages for these as well. For instance, if you submit the FORM with a LastName
that's either too long or too short, you will get this message:
An individual error message for each input field can be really useful, especially if you
have a large FORM. However, for smaller forms, it might be more useful to simply
display a summary of the validation errors, either above or below all the fields.
Syntax:
@Html.ValidationSummary()
[Required]
[StringLength]
[Range]
[Compare]
[EmailAddress]
[RegularExpression]
ViewModels
A ViewModel in ASP.NET Core MVC is a model that is passed to a View, and it is
considered as a ViewModel because it's used by that particular View. In other words,
there doesn't have to be a difference - you can use your Models as ViewModels
interchangeably. however, a lot of situations where you may want to create a specific
ViewModel for a specific View. This can be to extend or simplify an existing Model, or
because you want to represent something in a View that's not already covered by one
of your models.
ViewModels are often placed in their own directory in your project, called
"ViewModels". Again, this is just a convention and since ViewModels are just regular
.NET classes.
To simplify an existing Model: only expose the parts of model that actually needed for a view.
To extend an existing Model with data only relevant to the View
URL Routing and Features
The Route is similar to a roadmap. We use a roadmap to go to our destination. Similarly, the
ASP.NET Core Apps uses the Route to go to the controller action. The Each Route contains a
Name, URL Pattern (Template), Defaults and Constraints. The URL Pattern is compared to the
incoming URLs for a match. An example of URL Pattern is {controller=Home}/{action=Index}/{id?}
The Routing in ASP.NET Core MVC is a mechanism which inspects the incoming http request
and maps them to Controller Actions. It also used to generate the outgoing URLs. This
process is handled by the Routing Middleware. The Routing Middleware is available in
Microsoft.AspNetCore.Routing Namespace.
The Routing has two main responsibilities:
1) It maps the incoming requests to the Controller Action
2) Generate an outgoing URLs that correspond to Controller Action
How Routing Works
When the Request arrives at the Routing Middleware it does the following.
• It Parses the URL.
• Searches for the Matching Route in the RouteCollection.
• If the Route found then it passes the control to RouteHandler.
• If Route not found, it gives up and invokes the next Middleware.
What are the different types of Routing supported by ASP.NET Core MVC?
In ASP.NET Core MVC application, you can define routes in two ways. They are as
follows:
1) Convention Based Routing
2) Attribute-Based Routing.
In ASP.NET Core MVC application, it is the controller action method that is going to handle the
incoming Requests i.e. URLs. For example, if we issue a request to the “/Home/Index” URL,
then it is the Index action method of Home Controller class which is going to handle the
request as shown in the below image.
Similarly, if you issue a request to the “/Home/Details/2” URL, then it is the Details action method
of the Home Controller class which is going to process that request as shown in the above image.
Where the parameter value 2 is automatically mapped to the id parameter of the Details action
method.
The request mapping is done by the MVC Middleware which we registered in the application’s
request processing pipeline.
Set up conventional route
Startup.Configure typically has code similar to the following when using conventional
routing:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
REST APIs should use attribute routing to model the app's functionality as a set of
resources where operations are represented by HTTP verbs.
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase