Search code examples
c#asp.net-corerazor-pageskendo-ui-gridkendo-ui-mvc

Setting Kendo UI Grid DataSource Read property with Handler in ASP.NET Core MVC with Razor Pages


I am using the Kendo UI for ASP.NET Core MVC suite with a Razor Pages web application so I am trying to use the handler technique for the grid's server operations.

@(Html.Kendo().Grid<CustomerViewModel>()
        .Name("CustomersGrid")
        .Columns(columns =>
        {
            columns.Bound(x => x.CustomerId).Title("Student ID");
            columns.Bound(x => x.CustomerName).Title("Name");
        })
        .Pageable()
        .Sortable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(20)
            .ServerOperation(true)
            .Read(read => read.Url("/Customers?handler=Read")))
         )

I looked in the network tab and it is making the correct POST to http://localhost:5000/Customers?handler=Read however I am not ending up at my breakpoint and I get a status code 400.

In the razor page's code behind the Action method is named OnPostReadAsync

Any idea why this is not working? In addition to .Url also tried using read.Action and read.Route in the .Read property of the DataSource.

Here is the class with the action method:

public class IndexModel : PageModel
{
    private readonly ICustomerRepository _customerRepository;
    private readonly IMapper _mapper;

    public IndexModel(ICustomerRepository customerRepository, IMapper mapper)
    {
        _customerRepository = customerRepository;
        _mapper = mapper;
    }

    public IList<CustomerViewModel> Customers { get; set; }

    public async Task<IActionResult> OnPostReadAsync([DataSourceRequest] DataSourceRequest request)
    {
        // THIS IS WHERE I WANT IT TO GO FOR READ

        var customersFromDb = await _customerRepository.FilterAsync();
        return new JsonResult(_mapper.Map<IList<Customer>, IList<CustomerViewModel>>(customersFromDb).ToDataSourceResult(request));
    }
}

Solution

  • You may be doing this already, but I didn't see it in your code. Remember the Razor Pages require the anti-forgery token. You can inject it into your markup like this:

    @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
    

    And I added this function to set it on the grid's dataSource requests:

    $(function () {
        const requestVerificationToken = '@Xsrf.GetAndStoreTokens(HttpContext).RequestToken';
        const beforeSend = req => req.setRequestHeader('RequestVerificationToken', requestVerificationToken);
        const grid = $("#grid").getKendoGrid();
        grid.dataSource.transport.options.create.beforeSend = beforeSend;
        grid.dataSource.transport.options.update.beforeSend = beforeSend;
        grid.dataSource.transport.options.destroy.beforeSend = beforeSend;
    });
    

    Without that token all the PageModel custom handlers will return 400 errors.

    Reference: Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core