Section 1 of 5

What are Razor Pages?

🎯 What You'll Learn

  • What Razor Pages are
  • Page-focused development
  • Setting up Razor Pages
  • Folder structure
  • Routing conventions
  • When to use Razor Pages

What are Razor Pages?

Razor Pages is a page-focused framework for building web UI in ASP.NET Core. It's simpler than MVC for scenarios where you don't need the full separation of concerns.

💡 Key Concept

Razor Pages combines the view and controller logic into a single file, making it easier to organize page-focused scenarios.

Razor Pages vs MVC

Aspect Razor Pages MVC
Organization Page-focused Controller-focused
Files .cshtml + .cshtml.cs Controller + View
Routing Convention-based (folder structure) Attribute or route config
Use Case Simple CRUD, forms Complex apps, APIs
Learning Curve Easier Steeper

Setting Up Razor Pages

Create Razor Pages Project

Create Project Bash
dotnet new webapp -n InvenTrack.Web
cd InvenTrack.Web
dotnet run

Configure Services

Program.cs C#
var builder = WebApplication.CreateBuilder(args);

// Add Razor Pages services
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

// Map Razor Pages
app.MapRazorPages();

app.Run();

Folder Structure

InvenTrack.Web/
├── Pages/
│   ├── Index.cshtml
│   ├── Index.cshtml.cs
│   ├── Products/
│   │   ├── Index.cshtml
│   │   ├── Index.cshtml.cs
│   │   ├── Create.cshtml
│   │   └── Create.cshtml.cs
│   ├── Shared/
│   │   ├── _Layout.cshtml
│   │   └── _ValidationScriptsPartial.cshtml
│   ├── _ViewStart.cshtml
│   └── _ViewImports.cshtml
├── wwwroot/
│   ├── css/
│   ├── js/
│   └── lib/
├── Program.cs
└── appsettings.json

Key Folders

Folder/File Purpose
Pages/ Razor Pages (.cshtml + .cshtml.cs)
.cshtml Razor view (HTML + Razor syntax)
.cshtml.cs PageModel (code-behind)
Pages/Shared/ Shared layouts and partials
wwwroot/ Static files

Creating a Razor Page

1. Create the PageModel (.cshtml.cs)

Pages/Products/Index.cshtml.cs C#
public class IndexModel : PageModel
{
    private readonly InvenTrackDbContext _context;

    public IndexModel(InvenTrackDbContext context)
    {
        _context = context;
    }

    public List<Product> Products { get; set; } = new();

    public async Task OnGetAsync()
    {
        Products = await _context.Products.ToListAsync();
    }
}

2. Create the View (.cshtml)

Pages/Products/Index.cshtml HTML
@page
@model IndexModel

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

<h1>Products</h1>

<table class="table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
            <th>Quantity</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model.Products)
        {
            <tr>
                <td>@product.Name</td>
                <td>$@product.Price</td>
                <td>@product.Quantity</td>
            </tr>
        }
    </tbody>
</table>
💡 @page Directive

The @page directive at the top makes the file a Razor Page. Without it, it's just a regular Razor view.

Routing Conventions

Razor Pages uses convention-based routing based on folder structure.

File Path URL
Pages/Index.cshtml / or /Index
Pages/Products/Index.cshtml /Products or /Products/Index
Pages/Products/Create.cshtml /Products/Create
Pages/About.cshtml /About

Custom Routes

Custom Route with @page HTML
@page "/products"
<!-- Now accessible at /products instead of default -->

@page "{id:int}"
<!-- Route parameter: /Products/5 -->

@page "{id:int?}"
<!-- Optional parameter: /Products or /Products/5 -->

Complete InvenTrack Example

Pages/Products/Index.cshtml.cs C#
public class IndexModel : PageModel
{
    private readonly InvenTrackDbContext _context;

    public IndexModel(InvenTrackDbContext context)
    {
        _context = context;
    }

    public List<Product> Products { get; set; } = new();
    public string? SearchTerm { get; set; }

    public async Task OnGetAsync(string? search)
    {
        SearchTerm = search;

        var query = _context.Products.AsQueryable();

        if (!string.IsNullOrEmpty(search))
        {
            query = query.Where(p => p.Name.Contains(search));
        }

        Products = await query.ToListAsync();
    }
}
Pages/Products/Index.cshtml HTML
@page
@model IndexModel

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

<h1>InvenTrack Products</h1>

<form method="get">
    <div class="input-group mb-3">
        <input type="text" name="search" value="@Model.SearchTerm" 
               class="form-control" placeholder="Search products...">
        <button class="btn btn-primary" type="submit">Search</button>
    </div>
</form>

<a asp-page="Create" class="btn btn-success mb-3">Add New Product</a>

<table class="table table-striped">
    <thead>
        <tr>
            <th>Name</th>
            <th>Category</th>
            <th>Price</th>
            <th>Quantity</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model.Products)
        {
            <tr>
                <td>@product.Name</td>
                <td>@product.Category</td>
                <td>$@product.Price</td>
                <td>@product.Quantity</td>
                <td>
                    <a asp-page="Edit" asp-route-id="@product.Id" class="btn btn-sm btn-warning">Edit</a>
                </td>
            </tr>
        }
    </tbody>
</table>

When to Use Razor Pages

✅ Good For:

  • Simple CRUD apps: Create, Read, Update, Delete operations
  • Forms-heavy apps: Contact forms, surveys, data entry
  • Page-focused scenarios: Each page is independent
  • Beginners: Easier learning curve than MVC
  • Small to medium apps: Less boilerplate than MVC

❌ Not Ideal For:

  • Complex routing: Custom routing patterns
  • RESTful APIs: Use Web API instead
  • Shared logic: Multiple pages with same logic
  • Large enterprise apps: MVC provides better separation

Best Practices

  • @page directive: Always include at the top
  • Async handlers: Use OnGetAsync/OnPostAsync
  • Dependency injection: Inject services in constructor
  • Folder organization: Group related pages in folders
  • PageModel properties: Use for data binding
  • Naming convention: PageModel class name matches file

Key Takeaways

  • Razor Pages: Page-focused framework for web UI
  • @page: Directive that makes a file a Razor Page
  • PageModel: Code-behind class (.cshtml.cs)
  • Convention-based routing: Based on folder structure
  • AddRazorPages(): Registers Razor Pages services
  • MapRazorPages(): Maps Razor Pages endpoints
  • Simpler than MVC: For page-focused scenarios
  • Two files: .cshtml (view) + .cshtml.cs (code-behind)
🎯 Next Steps

You now understand what Razor Pages are! In the next section, we'll explore the Page Model Pattern—how to structure your code-behind and work with properties and methods.