A PageModel is the C# backing class for a Razor Page. It usually lives in a code-behind file beside the .cshtml view: Privacy.cshtml pairs with Privacy.cshtml.cs. The view’s @model directive identifies the class; the matching filenames are a convention, not what links them. A PageModel derives from the PageModel base class and contains page handlers that respond to requests. section 17.2.1 section 13.1.4
For a GET request to /Privacy, routing selects the page and its OnGet handler runs. If that handler returns void, the associated Razor template renders the HTML. A handler can instead return an IActionResult to give other response instructions, such as a redirect. The .cshtml file needs @page on its first line to be recognized as a Razor Page. section 13.1.4 section 13.1.3
A PageModel has two closely related jobs:
- Handle the request. Handler names follow conventions such as OnGet for GET. Parameters or properties marked [BindProperty] can receive values from the request. Check ModelState.IsValid when acting on validated input; validation does not prevent the handler from running. section 13.1.4 section 16.1 section 16.5
- Supply data for the view. Set public properties before rendering so the Razor template can read what it needs to generate HTML. The view should generally read those properties rather than call PageModel methods. section 13.4.3 section 17.1
- Coordinate business work. Use an injected service for application logic rather than putting that logic directly in the handler. This keeps request handling, business logic, and HTML generation separate. section 13.5 section 13.2
A category page
A request to /category/Simple supplies “Simple” to CategoryModel.OnGet(string category). The handler asks an injected ToDoService for matching items, puts them in its Items property, and returns Page() to render the view. A void handler could also render the associated view. section 13.4.1 section 13.2
Listing 13.5 A Razor Page for viewing all to-do items in a given category
public class CategoryModel : PageModel
{
private readonly ToDoService _service; #1
public CategoryModel(ToDoService service) #1
{
_service = service;
}
public ActionResult OnGet(string category) #2
{
Items = _service.GetItemsForCategory(category); #3
return Page(); #4
}
public List<ToDoListModel> Items { get; set; } #5
}
See the handler, injected service, Items property, and Page() result together in a small PageModel. section 13.2
Do not confuse the PageModel with every “model” in MVC. Request data forms a binding model; application services perform business actions; and the PageModel acts as both the page’s controller, through its handlers, and the view model, through its properties. A separate PageModel is optional: without one, the framework can use an implicit handler and render the view directly. section 16.1 section 17.2.1

