Suggested Videos
Part 14 - Editing data in asp.net core razor pages | Text | Slides
Part 15 - Updating data in asp.net core razor pages | Text | Slides
Part 16 - File upload in asp.net core razor pages | Text | Slides
In this video we will discuss how to handle multiple forms in asp.net core razor pages.
Handler Method Selection in Razor Pages
ASP.NET core razor pages framework uses naming conventions to select a handler method. Consider the following Edit razor page.
To load this Edit razor page, browser issues a GET request. To handle this GET request, asp.net core razor pages framework looks for a method that is named OnGet() in the corresponding PageModel class.
When the Update button is clicked, browser issues a POST request. To handle this POST request, asp.net core razor pages framework looks for a method that is named OnPost() in the corresponding PageModel class.
So, the following is the naming convention used by the razor pages framework to find the handler method. The word "On" is prefixed to the request verb. So for the GET request, it looks for OnGet and for POST request, it is OnPost.
Multiple forms on a Razor Page
What if we have 2 or more forms on a given razor page. We have 2 forms on the following razor page.
On Form 1, when Update Notification Preferences button is clicked we want OnPostUpdateNotificationPreferences() method to handle the request. We specify this using asp-page-handler tag helper on the <form> element as shown below. OnPost prefix is not required, but you can specify it if you want to.
On Form 2, when Update button is clicked we want OnPost() method to handle the request. We specify this using asp-page-handler tag helper on the <form> element as shown below.
When Update Notification Preferences button is clicked, the handler name is passed in the URL as a query string parameter.
If you prefer to pass the handler name as a route parameter instead of as a query string parameter, include a route parameter in the display template.
With this change, the handler name is now passed in the URL as a route parameter.
Edit.cshtml
Edit.cshtml.cs
Part 14 - Editing data in asp.net core razor pages | Text | Slides
Part 15 - Updating data in asp.net core razor pages | Text | Slides
Part 16 - File upload in asp.net core razor pages | Text | Slides
In this video we will discuss how to handle multiple forms in asp.net core razor pages.
Handler Method Selection in Razor Pages
ASP.NET core razor pages framework uses naming conventions to select a handler method. Consider the following Edit razor page.
To load this Edit razor page, browser issues a GET request. To handle this GET request, asp.net core razor pages framework looks for a method that is named OnGet() in the corresponding PageModel class.
When the Update button is clicked, browser issues a POST request. To handle this POST request, asp.net core razor pages framework looks for a method that is named OnPost() in the corresponding PageModel class.
So, the following is the naming convention used by the razor pages framework to find the handler method. The word "On" is prefixed to the request verb. So for the GET request, it looks for OnGet and for POST request, it is OnPost.
Multiple forms on a Razor Page
What if we have 2 or more forms on a given razor page. We have 2 forms on the following razor page.
- Form 1 - Used for updating notification preferences
- Form 2 - Used for updating employee data
- On Form 1 - We have Update Notification Preferences button
- On Form 2 - We have Update button
public void OnPostUpdateNotificationPreferences()
{
// Code to Update Notification Preferences Data
}
public IActionResult OnPost(Employee employee)
{
// Code to Update Employee Data
}
{
// Code to Update Notification Preferences Data
}
public IActionResult OnPost(Employee employee)
{
// Code to Update Employee Data
}
On Form 1, when Update Notification Preferences button is clicked we want OnPostUpdateNotificationPreferences() method to handle the request. We specify this using asp-page-handler tag helper on the <form> element as shown below. OnPost prefix is not required, but you can specify it if you want to.
<form method="post" asp-page-handler="UpdateNotificationPreferences">
@*Form 1 - Notification
Preferences*@
</form>
On Form 2, when Update button is clicked we want OnPost() method to handle the request. We specify this using asp-page-handler tag helper on the <form> element as shown below.
<form method="post" asp-page-handler="OnPost">
@*Form 2 - Employee Data*@
</form>
When Update Notification Preferences button is clicked, the handler name is passed in the URL as a query string parameter.
https://localhost:12345/employees/edit/2/?handler=updatenotificationpreferences
If you prefer to pass the handler name as a route parameter instead of as a query string parameter, include a route parameter in the display template.
@page "{id:min(1)}/{handler?}"
With this change, the handler name is now passed in the URL as a route parameter.
https://localhost:44383/employees/edit/2/updatenotificationpreferences/
Edit.cshtml
@page "{id:min(1)}/{handler?}"
@model
RazorPagesTutorial.Pages.Employees.EditModel
@{
ViewData["Title"] = "Edit";
var photoPath = "~/images/" + (Model.Employee.PhotoPath ?? "noimage.jpg");
}
<h1>Notification
Preferences</h1>
<form method="post" asp-page-handler="UpdateNotificationPreferences">
<div class="form-check">
<input asp-for="Notify" class="form-check-input" />
<label asp-for="Notify" class="form-check-label">
Receive email notification when my
details change
</label>
</div>
<button type="submit" class="btn btn-primary">
Update Notification Preferences
</button>
@if (!string.IsNullOrEmpty(Model.Message))
{
<div class="alert alert-primary">
@Model.Message
</div>
}
</form>
<hr />
<h1>Edit</h1>
<form method="post" class="mt-3" enctype="multipart/form-data"
asp-page-handler="OnPost">
<input hidden asp-for="Employee.Id" />
<input hidden asp-for="Employee.PhotoPath" />
<div class="form-group row">
<label asp-for="Employee.Name" class="col-sm-2 col-form-label">
</label>
<div class="col-sm-10">
<input asp-for="Employee.Name" class="form-control" placeholder="Name">
</div>
</div>
<div class="form-group row">
<label asp-for="Employee.Email" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Employee.Email" class="form-control" placeholder="Email">
</div>
</div>
<div class="form-group row">
<label asp-for="Employee.Department" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<select asp-for="Employee.Department" class="custom-select mr-sm-2"
asp-items="Html.GetEnumSelectList<Dept>()">
<option value="">Please Select</option>
</select>
</div>
</div>
<div class="form-group row">
<label asp-for="Photo" class="col-sm-2
col-form-label"></label>
<div class="col-sm-10">
<div class="custom-file">
<input asp-for="Photo" class="custom-file-input
form-control">
<label class="custom-file-label">Click
here to change photo</label>
</div>
</div>
</div>
<div class="form-group row col-sm-4 offset-4">
<img class="imageThumbnail" src="@photoPath" asp-append-version="true" />
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Update</button>
<a asp-page="/Employees/Index" class="btn btn-primary">Cancel</a>
</div>
</div>
@section Scripts {
<script>
$(document).ready(function () {
$('.custom-file-input').on("change", function () {
var fileName = $(this).val().split("\\").pop();
$(this).next('.custom-file-label').html(fileName);
});
});
</script>
}
</form>
Edit.cshtml.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesTutorial.Models;
using RazorPagesTutorial.Services;
using System;
using System.IO;
namespace RazorPagesTutorial.Pages.Employees
{
public class EditModel : PageModel
{
private readonly IEmployeeRepository employeeRepository;
private readonly IWebHostEnvironment webHostEnvironment;
public EditModel(IEmployeeRepository employeeRepository,
IWebHostEnvironment
webHostEnvironment)
{
this.employeeRepository = employeeRepository;
this.webHostEnvironment = webHostEnvironment;
}
public Employee Employee { get; set; }
[BindProperty]
public IFormFile Photo { get; set; }
[BindProperty]
public bool Notify {
get; set; }
public string Message
{ get; set; }
public IActionResult OnGet(int id)
{
Employee =
employeeRepository.GetEmployee(id);
if (Employee == null)
{
return RedirectToPage("/NotFound");
}
return Page();
}
public IActionResult OnPost(Employee employee)
{
if (Photo != null)
{
if (employee.PhotoPath != null)
{
string filePath =
Path.Combine(webHostEnvironment.WebRootPath,
"images",
employee.PhotoPath);
System.IO.File.Delete(filePath);
}
employee.PhotoPath =
ProcessUploadedFile();
}
Employee =
employeeRepository.Update(employee);
return RedirectToPage("Index");
}
public void
OnPostUpdateNotificationPreferences(int id)
{
if (Notify)
{
Message = "Thank you for turning on notifications";
}
else
{
Message = "You have turned off email notifications";
}
Employee =
employeeRepository.GetEmployee(id);
}
private string
ProcessUploadedFile()
{
string uniqueFileName = null;
if (Photo != null)
{
string uploadsFolder = Path.Combine(webHostEnvironment.WebRootPath, "images");
uniqueFileName =
Guid.NewGuid().ToString() + "_" + Photo.FileName;
string filePath = Path.Combine(uploadsFolder, uniqueFileName);
using (var
fileStream = new
FileStream(filePath, FileMode.Create))
{
Photo.CopyTo(fileStream);
}
}
return uniqueFileName;
}
}
}
Handling multiple forms was very helpful in understanding how to use more
ReplyDeletethan one OnPost handler.
For cascading dropdowns, I have thought of using cookies and session.
Examples that I am tring to implement are selecting Campus, building, room,
or Continent, country, state and have them on the same page. All data is from database.
When using .NET webforms, the solution is straight forward, because of viewstate and postback
on dropdown.
Do we have to use cookies and Session to maintain state for cascading dropdowns?
This comment has been removed by the author.
ReplyDeleteJust to let you guys know, (in 3.1 at least) you can't skip 'OnPost' in '.cs' file and you can't include 'OnPost' in 'asp-page-handler', otherwise in won't bind properly.
ReplyDelete