Model binding in ASP.NET Core Razor Views

The ASP.NET Core Application's Model Binding mechanism gathers information from an HTTP request and passes it along to the controller action method parameters.

Model binding in ASP.NET Core Razor Views
Model binding, ASP.NET Core, Programming, thetechfoyer, thetechfoyer.com

This Articles helps you to understand the concept of Model binding in ASP.NET Core Razor Views

The process of mapping client request data—such as form values, route data, query string parameters, request body, and HTTP headers—to action method parameters in ASP.NET Core MVC is known as model binding. This enables us to use strongly typed.NET objects directly in our action methods. In the ASP.NET Core MVC Application, this will remove the need to manually parse and convert the raw HTTP request data to.NET objects.



The Manual Way (Without Model Binding)
If the website contains a User form that the user can fill in and submit, we might want to use the values submitted during user registration

@{
  ViewData["Title"] = "user Home Page";
}
<form method="post" asp-controller="User" asp-action="Registration">
  <label>Name:label>
  <input type="text" name="Name" />
  <br />
  <label>Phone Number:label>
  <input type="text" name="PhoneNumber" />
  <br />
  <button type="submit">Submitbutton>
form>



Capture Post Back

public class UserController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public string Registration(IFormCollection form)
    {
        var Name = form["Name"].ToString();
        var PhoneNumber = form["PhoneNumber"].ToString();
       return View();
    }
}

We didn't use model binding here, and yet our form works fine. So, what do we need model binding for?



Model Binding in ASP.NET Core in Razore Views
The goal of model binding is to automate the process of passing information from an HTTP request into an input model.
Lets change our UserModel class, View and Controller Class

public class User
{
    [Required]
    public string Name { get; set; }
    [Required]
    public string PhoneNumber { get; set; }
}
// View ===============================================================
@model User
@{
    ViewData["Title"] = "user Home Page";
}
<form method="post" asp-controller="User" asp-action="Registration">
    <label>Name:label>
    <input type="text" asp-for="Name" />
    <br />
    <label>Phone Number:label>
    <input type="text" asp-for="PhoneNumber" />
    <br />
    <button type="submit">Submitbutton>
form>


public class UserController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public string Registration(User user)
    {      
        if (user != null)
        {
            if (ModelState.IsValid)
            {
                var Name = user.Name;
                var PhoneNumber = user.PhoneNumber;
            }
        }      
        return View();
    }
}



Importance of Model Binding in ASP.NET Core MVC?
Type Safety: By converting client data into.NET types through model binding, we can make sure that the values of our action methods are already of the correct data type. As a result, fewer manual data type conversions and related error checks will be required.
Automatic Validation: When combined with data annotations, model binding can validate the incoming data against predefined rules. By looking at the ModelState, we can quickly determine whether the data is legitimate.
Code Simplification: The repetitive code of manually extracting values from the request and converting them to.NET types is eliminated by model binding.



Different Model Binding Techniques in ASP.NET Core MVC
Normal Model Binding:

[HttpPost]
public IActionResult Registration(User user){}



Attribute Routing:
Attribute routing in model binding allows data from the URL to be bound.

// RESTful APIs:
[Route("article/{id}")]
public IActionResult ArticleDetails(Guid id) { }



FromBody:
The [FromBody] attribute designates that a parameter—typically in XML or JSON format—should be deserialized from the request body. Typically, JSON or XML is sent when data is sent in the body of an HTTP request (usually for POST, PUT, and PATCH methods).

[HttpPost]
public IActionResult Registration([FromBody] User user) { }



FromForm:
Data from form fields is bound in a form submit action via the [FromForm] attribute. The form data is sent by the browser as application/x-www-form-urlencoded MIME type when it is embedded in an HTML page. The model binder is instructed by the FromForm attribute to retrieve the data from the request's form body and attempt to bind it to the action method parameters or model properties that are specified.

[HttpPost]
[HttpPost]
public IActionResult Registration([FromForm] User user)
{
    if (user != null)
    {
        if (ModelState.IsValid)
        {
            var Name = user.Name;
            var PhoneNumber = user.PhoneNy form["PhoneNumber"].ToString();
                return View(user);
        }
    }      
    return View();
}

 public IActionResult Create([FromForm] string Name, [FromForm] string PhoneNumber) {}


// File Uploads:
// The uploaded files and any additional form fields are bound together when managing file
uploads with a form that uses enctype="multipart/form-data" and the FromForm attribute.
[HttpPost("/upload")]
public IActionResult Upload([FromForm] IFormFile uploadedFile, [FromForm] string fileinfo){}

<form method="post" action="/upload" enctype="multipart/form-data">
    <input type="file" name="uploadedFile" />
    <input type="text" name=fileinfo" />
    <input type="submit" value="Upload" />
form>



FromQuery:
Parameters from the query string are bound using the [FromQuery] attribute. For situations like filtering, where you want to retrieve data based on specific parameters passed through the URL, the FromQuery attribute is very helpful.

public IActionResult Search([FromQuery] string query) { }

public class SearchCriteria
{
    public string Name { get; set; }
    public int Age { get; set; }
}

[HttpGet("users/filter")]
public IActionResult Filter([FromQuery] SearchCriteria criteria){}
try to search via querystring: /users/filter?Name=DT&Age=40


// Instead of binding to a model, you can bind directly to method parameters.
[HttpGet("users/filter")]
public IActionResult Filter([FromQuery] string Name, [FromQuery] int? Age) {}

Real Time Example
you can use this feature for paging and sorting in any listing



FromRoute:
Parameters from the route data are bound by the [FromRoute] attribute.

[HttpGet("{id}")]
public IActionResult Get(int id) { }


// Get user details based on their ID
public class UsersController : Controller
{
    [HttpGet]
    [Route("users/{Id}/getdetails")]
    public IActionResult GetUserById([FromRoute] int Id)
    {        
        var user = _users.FirstOrDefault(x => x.Id == Id);  
        if (user == null)
        {
            return NotFound();
        }
        return Ok(user);
    }
}


FromHeader:
An HTTP header parameter can be bound using the [FromHeader] attribute. To indicate that a parameter should be bound using information from the HTTP request header, use the FromHeader attribute. An HTTP request's headers offer a mechanism to transmit extra data about the request or answer.

public IActionResult CheckAgent([FromHeader(Name = "User-Agent")] string userAgent) { }


// Authentication & Authorization:
// It is common practise to send credentials or tokens (such as JWTs) to the server via the Authorization header.
[HttpGet]
public IActionResult Get([FromHeader(Name = "Authorization")] string token) { // Validate token and proceed
}

// Content Negotiation:
// Clients can indicate the expected media type (such as application/json or text/xml) using the Accept header. The server can then decide how to format the response using this header.


// Caching Control:
// For conditional requests, headers like If-Modified-Since or If-None-Match can be utilised. After reviewing these headers, the server may choose to send a complete response or a 304 Not Modified status.


// Localization:
// The clients preferred language may be specified in the Accept-Language header. The server can return localised content based on this.
[HttpGet]
public IActionResult GetLocalizedContent([FromHeader(Name = "Accept-Language")] string language) {
    // Content will be returned based on the specified language preference.
}