Ajax post with C# Handler and XSRF-TOKEN

Joseph Kashishian 85 Reputation points
2025-11-21T15:34:44.2166667+00:00

This question is for Web pages with .NET, C#, and Ajax.

I'm having an issue with a ajax calling working with the XSRF-TOKEN" and it's not calling the handler in the .CS. I think I need to do something with my ajax call to validate the token.

In my startup I have

        var antiforgery = app.ApplicationServices.GetRequiredService<IAntiforgery>();

        app.Use((context, next) =>

        {

            var requestPath = context.Request.Path.Value;

            if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)

                || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))

            {

                var tokenSet = antiforgery.GetAndStoreTokens(context);

                context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,

                    new CookieOptions { HttpOnly = false });

            }

            return next(context);

        });

index cs

using System.IO;

using System.Data.SqlClient;

using System.Collections.Generic;

using Microsoft.AspNetCore.Http;

using Microsoft.Extensions.Configuration;

using Microsoft.AspNetCore.Mvc.RazorPages;

using Microsoft.AspNetCore.Mvc;

using System;

namespace RecoveryHouse.Pages.ReferralRequest

{

public class IndexModel : PageModel

{

    public void OnGet()

    {

    }

    [HttpPost]

    [ValidateAntiForgeryToken]

    public IActionResult OnPostGetTime(string name)

    {

        PersonModel person = new PersonModel

        {

            Name = name,

            DateTime = DateTime.Now.ToString()

        };

        return new JsonResult(person);

    }

}

}

public class PersonModel

{

/// <summary>

/// Gets or sets Name.

/// </summary>

public string Name { get; set; }

/// <summary>

/// Gets or sets DateTime.

/// </summary>

public string DateTime { get; set; }

}

Index CSHTML

@page

@model RecoveryHouse.Pages.ReferralRequest.IndexModel

@addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>Index</title>

</head>

<body>

@Html.AntiForgeryToken()

<input type="text" id="txtName" />

<input type="button" id="btnGet" value="Get Current Time" />

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> 

<script type="text/javascript">

    $(function () {

        $("#btnGet").click(function () {

            $.ajax({

                type: "POST",

                url: "/Index?handler=GetTime",

                beforeSend: function (xhr) {

                    xhr.setRequestHeader("XSRF-TOKEN",

                        $('input:hidden[name="__RequestVerificationToken"]').val());

                },

                data: {"name": $("#txtName").val() },

                success: function (response) {

                    alert("Hello: " + response.Name + ".\nCurrent Date and Time: " + response.DateTime);

                },

                error: function (response) {

                    alert(response.responseText);

                }

            });

        });

    });

</script>

</body>

</html>

Developer technologies | ASP.NET Core | Other

Answer accepted by question author
Anonymous
2025-12-03T10:09:39.4566667+00:00

Hello Joseph Kashishian,
Thanks for trying my solution. I see you tried adding AddAntiforgery from my answer, but you're mixing it with old .NET Core 2.1 syntax that doesn't exist in .NET 7. Here's the corrected version:

What's wrong with your code:


// ? This is .NET Core 2.1 syntax - doesn't exist in .NET 7

services.AddMvc()

    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) // ? REMOVED in .NET 5+

    .AddJsonOptions(...); // ? Wrong syntax for .NET 7

 

// ? This part is correct, but needs proper .NET 7 context

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

Correct .NET 7 version:

Program.cs:


var builder = WebApplication.CreateBuilder(args);

 

// Add Razor Pages

builder.Services.AddRazorPages();

 

// ? Configure antiforgery - this is what you tried to add

builder.Services.AddAntiforgery(options =>

{

    options.HeaderName = "RequestVerificationToken";

});

 

var app = builder.Build();

 

app.UseRouting();

app.MapRazorPages();

app.Run();

Razor Page (.cshtml):


@page

@model YourNamespace.Pages.AjaxPostModel

@{

    ViewData["Title"] = "AjaxPost";

}

 

<h1>AjaxPost</h1>

<hr />

 

<form method="post">

<input type="text" id="name" placeholder="Enter name" />

<br />

<input type="text" id="datetime" placeholder="Enter datetime" />

<br />

</form>

 

<input type="button" id="ajaxPost" value="POST" />

<div id="result"></div>

 

@section Scripts {

<script>

        document.getElementById("ajaxPost").addEventListener('click', async () => {

            const token = document.querySelector('input[name="__RequestVerificationToken"]').value;

            const result = document.getElementById("result");

 

            const response = await fetch("/ajaxpost", {

                method: "POST",

                headers: {

                    'Content-Type': 'application/json',

                    'RequestVerificationToken': token,

                    'X-Requested-With': 'XMLHttpRequest'

                },

                body: JSON.stringify({

                    name: document.getElementById("name").value,

                    datetime: document.getElementById("datetime").value

                })

            });

 

            if (response.ok) {

                const data = await response.text();

                result.innerText = data;

            } else {

                result.innerText = `Error: ${response.status}`;

            }

        });

</script>

}

PageModel (.cshtml.cs):


using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.RazorPages;

 

namespace YourNamespace.Pages

{

    public class AjaxPostModel : PageModel

    {

        public void OnGet()

        {

        }

 

        [HttpPost]

        [ValidateAntiForgeryToken]

        public IActionResult OnPost([FromBody] PersonModel model)

        {

            if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")

            {

                return Content($"Name: {model.Name}, DateTime: {model.DateTime}");

            }

            return BadRequest();

        }

    }

    public class PersonModel

    {

        public string Name { get; set; }

        public string DateTime { get; set; }

    }

}

Key changes from .NET Core 2.1 to .NET 7:

  1. No more Startup.cs - everything in Program.cs
  2. Use builder.Services.AddRazorPages() instead of services.AddMvc()
  3. No more SetCompatibilityVersion() - removed in .NET 5+
  4. Use var builder = WebApplication.CreateBuilder(args) minimal hosting pattern

The AddAntiforgery you tried is correct, just needs to be in the right place with .NET 7 syntax. The key is reading the token from the hidden field and sending it in the RequestVerificationToken header with your JSON payload.
Hope this helps!

Was this answer helpful?


Answer accepted by question author
SurferOnWww 6,106 Reputation points
2025-11-22T01:13:43.0666667+00:00

Please try the followings:

(1) Add form tag to .cshtml.

(2) Create the FormData object form the form tag.

(3) Send the FormData using jQuery ajax or fetch API.

Shown below are the samples:

Model

namespace RazorPages.Models
{
    public class PersonModel
    {
        public string Name { get; set; } = string.Empty;
        public string DateTime { get; set; } = string.Empty;
    }
}

.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPages.Models;

namespace RazorPages.Pages
{
    public class AjaxPostModel : PageModel
    {
        public void OnGet()
        {
        }

        [BindProperty]
        public PersonModel Model { get; set; } = default!;

        public IActionResult OnPost()
        {
            if (Request.Headers.XRequestedWith == "XMLHttpRequest")
            {
                string name = Model.Name;
                string dateTime = Model.DateTime;
                return Content($"Name: {name}, DateTime: {dateTime}");
            }
            else
            {
                return BadRequest();
            }
        }
    }
}

.cshtml

@page

@model RazorPages.Pages.AjaxPostModel
@{
    ViewData["Title"] = "AjaxPost";
}

<h1>AjaxPost</h1>

<hr />

<form method="post">
    <input type="text" name="name" />
    <br />
    <input type="text" name="datetime" />
    <br />
</form>

<input type="button" id="ajaxPost" value="POST" />

<div id="result"></div>

@section Scripts {
    <script type="text/javascript">
        //<![CDATA[
        document.getElementById("ajaxPost")
            .addEventListener('click', async () => {
                const fd = new FormData(document.querySelector("form"));
                const result = document.getElementById("result");                

                const param = {
                    method: "POST",
                    body: fd,
                    // set X-Requested-With in request header
                    headers: { 'X-Requested-With': 'XMLHttpRequest' }
                }

                const response = await fetch("/ajaxpost", param);

                if (response.ok) {
                    const data = await response.text();
                    result.innerText = data;
                } else {
                    result.innerText = "response.ok is false";
                }
            });
        //]]>
    </script>
}

CSRF token in cookie sent to the server:

enter image description here

CSRF token in hidden field sent to the server:

enter image description here

Result

enter image description here

To see if the validation of CSRF-token is working, delete cookie of browser after the browser has received the response of OnGet() method and send the FormData by clicking the [POST] button. The ASP.NET will return 400 Bad request without invoking the OnPost() method.

Was this answer helpful?

0 comments No comments

5 additional answers

Sort by: Most helpful
  1. Joseph Kashishian 85 Reputation points
    2026-01-06T15:29:11.7733333+00:00

    I added this to the Startup.CS and it worked!!!!

    services.AddRazorPages()

     .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
    

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

    Was this answer helpful?

    1 person found this answer helpful.

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.

    5 deleted comments

    Comments have been turned off. Learn more

  3. Joseph Kashishian 85 Reputation points
    2025-11-25T14:41:46.5366667+00:00

    Use answers to provide solutions to the user's question.this does not work in .net 7

    services.AddMvc()

           .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
    
           .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
    

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

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.