Author : MD TAREQ HASSAN | Updated : 2020/07/03
What is razor pages?
- A page-focused framework for building dynamic, data-driven web sites
 - Razor Pages framework is lightweight and very flexible
 - Razor Pages can be considered as “MVVM for web” (M = Model, V = View, VM = ViewModel)
    
- Clean separation of concerns
 - MVVM Data binding
 
 - Razor Pages based on a page-centric development model, offering a familiarity to web developers with experience of other page-centric frameworks (PHP, Classic ASP, Java Server Pages, ASP.NET Web Forms etc.)
 - Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views
 - Links:
 
Notes:
- Razor pages are built on top of AspNetCore MVC
 - AspNetCore Identity is implemented as Razor Pages. Scaffold Identity & take a look to better understand razor pages (see how Microsoft implemented it)
 
MVC vs Razor Pages
- Razor Pages: much like am MVVM (simple, clean, easy to maintain). Razor Pages for
    
- simple pages (read-only)
 - basic data input
 - also suitable for big/complex applications
 - ASP.Net core Identity is provided as Razor Pages (razor library)
 
 - MVC: seperation of concern (fit for big/complex application). MVC for
    
- dynamic server views
 - single page apps
 - REST APIs
 - AJAX calls
 
 - Links:
 
Overview
- Similarity to MVC view
    
- same razor view engine & razor systax
 - same Tag Helpers
 - Same model binding, validation, and action results
 - same 
.cshtmlextension 
 @pagedirective: to indicate that it’s a Razor Page@pagemakes the file into an MVC action - which means that it handles requests directly, without going through a controller@pagemust be the first Razor directive on a page
@modeldirective: to bind ViewModel- Conventions:
    
- All pages will be under “Pages” folder (i.e. 
Pages/Foo/xxx.cshtml) - URL routing are based on location in Pages folder (the path to the file on disk is used to calculate the URL)
        
Pages/Foo/Index.cshtml=> ‘/foo’Pages/Foo/Bar.cshtml=> ‘/foo/bar’
 - Each razor page 
.cshtmlfile has a corresponding.cshtml.csfile containing the PageModel- Page: 
Bar.cshtml - PageModel: 
Bar.cshtml.cs - Visual Studio will hide the PageModel behind the page and we have expand to see PageModel
 
 - Page: 
 - PageModel class name is 
<PageName>Modeland is in the same namespace as the page 
 - All pages will be under “Pages” folder (i.e. 
 
Pages/Foo/Bar.cshtml
@page
@using Hover.Foo // the namespace where BarModel belongs
@model BarModel
<h2>Hovermind</h2>
<p>
    @Model.Message
</p>
Pages/Foo/Bar.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
namespace Hover.Foo
{
    public class BarModel : PageModel
    {
        public string Message { get; private set; } = "Hover Now ->";
        public void OnGet()
        {
            Message += $" { DateTime.Now }";
        }
    }
}
Configuration
configurations-in-startup#razor-pages
Layout
Same as MVC: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/layout
Page model
- Page model acts as both a mini-controller and the view model for the view
 
Anatomy of PageModel
public class XxxModel : PageModel
{
	// bindable properties (property type => POCO i.e. public Baz baz)
	
	// DI injection properties
	
	// constructor for DI injection
	// handler methods for corresponding http verbs
}
Example: Bar.cshtml.cs
public class BarModel : PageModel
{
    [BindProperty]
    public Customer Customer { get; set; }
	
    private readonly CustomerDbContext _context;
    public BarModel(CustomerDbContext context)
    {
        _context = context;
    }
    public IActionResult OnGet()
    {
        return Page();
    }
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
        return RedirectToPage("./Index");
    }
}
Handler methods
- Handler method is the cllback function for corresponding HTTP verb
 - Handler methods for any HTTP verb can be added
    
OnPost[handler]Asynci.e.OnPostDeleteAsync<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
 - The most common handlers are:
    
OnGet/OnGetAsyncto initialize state needed for the pageOnPost/OnPostAsyncto handle form submissions
 
Multiple handlers
asp-page=> target page to submit formasp-page-handler=> target handler in target page (defined byasp-page)- In PageModel: 
GetXxxAsync()/PostXxxAsync()whenasp-page-handler="Xxx" - https://docs.microsoft.com/en-us/aspnet/core/razor-pages/#multiple-handlers-per-page
 
Property binding and model expression
[BindProperty]annotation is used to bind PageModel properties to Page- By default binding for GET (url parameters) is not supported, to allow use: 
[BindProperty(SupportsGet = true)] 
Routing
By conmvention, path in “Pages” forlder & page file name becomes route url
Pages/Foo.cshtml=> “/foo”Pages/Foo/Index.cshtml=> “/foo”Pages/Foo/Bar.cshtml=> “/foo/bar”- Use route template after 
@pagedirective if you want more URL segments after page name in the url (See: route-template-and-constraint) 
To overrive default routing convention, provide absolute URL after @page directive  
Example: Pages/Foo/Bar.cshtml
@page "/xxx"
<!-- ... ... ... -->
- hardcoded absolute URL “
/xxx” is being used - Page url would be “
/foo/xxx” instead of “/foo/bar” 
Details: https://docs.microsoft.com/en-us/aspnet/core/razor-pages/razor-pages-conventions
Route template and constraint
- Same MVC route template can be used: “
{controller}/{action}/{param}” - Same MVC route constraint can be used: “
{id:int}” - If you already know MVC routing template then imagine:
    
@page=> is like “{controller=<page-file-name>}/{action=<OnGet>}”@page "/absolute-url"=> overrides default routing@page "{route-template}"=> “foo/<path-segments-according-to-template>”@page "{id}"=> “foo/5”@page "{year}/{month}/{day}"=> “foo/2020/7/4”
@page "{y}/{z}":@page= “/foo” +"{y}/{z}"= “/y/z” (URL: “foo/y/z”)
 
Pages/Foo/Bar.cshtml
@page "{id:int}"
<!-- ... ... ... -->
URL would be: “foo/bar/5”
Accessing route url segments
Pages/Bar.cshtml
@page "{id:int}"
<!-- ... ... ... -->
URL: “/bar/5”
Pages/Bar.cshtml.cs
public class BarModel : PageModel
{
    // ... ... ...
    public IActionResult OnGet(int id) // id = 5
    {
        // ... ... ...
    }
	
	// ... ... ...
}
ViewData
- Same as MVC ViewData/ViewBag but 
[ViewData]annotation is in case of Razor Pages - Used to:
    
- Pass data from PageModel to Page
 - Set title in Layout
 
 - Acceessed in page
    
@Model.Xxx@ViewData["Xxx"]
 
PageModel
public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";
    public void OnGet()
    {
    }
}
Page
<h1>@Model.Title</h1>
<!-- ... ... ... -->
Layout
<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
	
    <!-- ... ... ... -->
TempData
- Same as MVC TempData but 
[TempData]annotation is in case of Razor Pages - Stores data until it’s read
 - Useful for redirection
 - https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state#tempdata
 
PageModel
[TempData]
public string Message { get; set; }
Page
<h3>Message: @Model.Message</h3>