Home > Software engineering >  Ajax Call using Razor Page Handler Returns 400
Ajax Call using Razor Page Handler Returns 400

Time:10-11

Using asp.net core 3.1 and I'm trying to make a Post method call using ajax when dropdown is changed, the id value from the selected dropdown will be stored in a session, but upon changing the dropdown I encounter 400

Pages/Index.cshtml.cs

[Authorize]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    return _studentService.GetStudents();
    }

    public void OnPostUpdateStudent(string id)
    {
         HttpContext.Session.SetString("SelectedStudent", id);
    }
}

Pages/Shared/_Layout.cshtml

@{
    var studentList = HttpContextAccessor.HttpContext.Session.GetObject<List<SelectListItem>>("StudentList");
}
<select onchange="UpdateAll(this)" asp-items="studentList" >
<option value="all">All Students</option>
</select>

site.js

function updateAll(element){
    updateStudent(element.value);
}

function updateStudent(id) {
    if (id != null && id != '') {
        $.ajax({
            type: "POST",
            url: "/Index?Handler=UpdateStudent",
            data: { id: id },
            success: function (result) {
            },
            failure: function (response) {
                console.log(response);
            }
        });
    }
}

Response:

Request URL: https://localhost:44383/Index?Handler=UpdateStudent
Request Method: POST
Status Code: 400 
Remote Address: 127.0.0.1:44383
Referrer Policy: strict-origin-when-cross-origin
date: Mon, 10 Oct 2022 08:11:42 GMT
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
:authority: localhost:44383
:method: POST
:path: /Index?Handler=UpdateStudent
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
content-length: 0

CodePudding user response:

  1. In cshtml, add

@Html.AntiForgeryToken()

2.The Ajax request should send the anti-forgery token in request header to the server. So, the modified Ajax request looks like:

   function updateStudent(id) {
    if (id != null && id != '') {
        $.ajax({
            type: "POST",          
             url: "/Index?Handler=UpdateStudent",
            beforeSend: function (xhr) {
        xhr.setRequestHeader("XSRF-TOKEN",
            $('input:hidden[name="__RequestVerificationToken"]').val());
    },
            data: { id: id },
   
            success: function (result) {
            },
            failure: function (response) {
                console.log(response);
            }
        });
    }
}

3.In startup, since the script sends the token in a header called X-CSRF-TOKEN, configure the antiforgery service to look for the X-CSRF-TOKEN header:

services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

result:

enter image description here

CodePudding user response:

The simplest solution (in my opinion) is to add a form element for the dropdown, which will automatically generate the anti forgery token as a hidden field (so long as the method is set to post):

@{
    var studentList = HttpContextAccessor.HttpContext.Session.GetObject<List<SelectListItem>>("StudentList");
}
<form method="post">
<select onchange="UpdateAll(this)" asp-items="studentList" >
<option value="all">All Students</option>
</select>
</form>

Then serialise the form in the AJAX call:

function updateAll(element){
    updateStudent(element);
}

function updateStudent(element) {
    if (element.value != null && element.value != '') {
        $.ajax({
            type: "POST",
            url: "/Index?Handler=UpdateStudent",
            data: $(element).closest('form').serialize(),
            success: function (result) {
            },
            failure: function (response) {
                console.log(response);
            }
        });
    }
}
  • Related