Razor Page Handlers

  • 3 minutes to read

This topic describes how to bind DevExtreme-based controls to Razor page handlers.


It is recommended that you bind the controls to API controllers because:

Implement Razor Page Handlers

Razor page handlers are similar to API controller actions, but have several specific differences:

  • A handler name

    Handler methods are executed as a result of a HTTP request. They are named according to the scheme: On[HttpMethod][HandlerName]Async. The Async suffix is optional, and is used for asynchronous functions.

    Examples: OnGetMyHandler() is used to process the GET request, OnPostMyHandler() - to process the POST request, etc.

    Refer to Microsoft documentation for more information about handlers.

  • A handler body

    Page handlers contain the same operations that you use in controller actions. There may be instances when you may need to use other methods to perform these operations (for instance, you may utilize new JsonResult() (in Razor page handlers) instead of Json() (in controller actions)).

  • Antiforgery validation

    Razor pages are automatically protected from XSRF/CSRF. When you bind a control to page handlers, you need to pass an antiforgery token to the DataSource.OnBeforeSend method (see Configure Access to Page Handlers).

The following code illustrates a typical page model for the DataGrid control. The model has two handler methods:

  • OnGetGridData() - runs on the GET request, provides data for the DataGrid.

  • OnPutGridRow() - runs on the PUT request, updates a DataGrid’s row.

CRUD operations are performed on the Northwind database’s Categories collection.

using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Linq;

namespace MyApp.Pages {
    public class MyPageModel : PageModel {
        readonly NorthwindContext _context;

        public MyPageModel(NorthwindContext context) {
            _context = context;

        // runs on the GET request
        public IActionResult OnGetGridData(DataSourceLoadOptions loadOptions) {
            var categories = _context.Categories.Select(i => new {
            return new JsonResult(DataSourceLoader.Load(categories, loadOptions));

        // runs on the PUT request
        public IActionResult OnPutGridRow(int key, string values) {
            var model = _context.Categories.FirstOrDefault(item => item.CategoryId == key);

            var _values = JsonConvert.DeserializeObject<IDictionary>(values);
            PopulateModel(model, _values);

                return BadRequest("Validation failed");

            return new OkResult();

        // a handler for the POST request

        // a handler for the DELETE request

        void PopulateModel(Category model, IDictionary values) {
            if(values.Contains("CategoryName")) {
                model.CategoryName = Convert.ToString(values["CategoryName"]);


Configure Access to Page Handlers

Use the DataSourceFactory.RemoteController method to configure access to data.

This method opens a chain of methods, including methods for CRUD operations: InsertUrl(), LoadUrl(), UpdateUrl(), DeleteUrl(). These CRUD methods take a URL for a Razor page handler. You can obtain this URL using Url.Page(), where you specify a page name and a page handler name defined in a page model.

The following example shows how to bind the DataGrid to page handlers. The LoadUrl() and UpdateUrl() methods provide access to the OnGetGridData() and OnPutGridRow() handler methods.

@model MyApp.Pages.MyPageModel
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf

    function grid_dataSource_beforeSend(op, ajax) {
        ajax.headers = {
            RequestVerificationToken: "@Xsrf.GetAndStoreTokens(Model.HttpContext).RequestToken"

    .DataSource(ds => ds.RemoteController()
        .LoadUrl(Url.Page(null, "GridData")) // access to the GridData handler defined in the OnGetGridData method in the page model
        .UpdateUrl(Url.Page(null, "GridRow")) // access to the GridRow handler defined in the OnPutGridRow method in the page model
        .OnBeforeSend("grid_dataSource_beforeSend") // passes an antiforgery token
    .Columns(columns => {
        columns.AddFor(m => m.CategoryName);
    .Editing(e => e