Ajax Error 400 (Bad Request) in Asp.net core Razor Pages

Ashkan 121 Reputation points
2024-10-31T11:11:12.99+00:00

hello,

I have a piece of code that collects the values ​​of the inputs in the html page and posts them to a handler using Ajax.

However, when sending by ajax, I get a 400 and bad request error and the handler is not called

Please guide me where I am doing wrong ?

    $("#sendButton").click(function (event) {
        event.preventDefault();
        var userId = $("#userId").val();
        var userName = $("#username").val();
        var message = $("#message").val();
        var groupId = $("#groupid").val();
        var attachFile = $("#f").get(0).files;

        var formData = new FormData();
        formData.append("FileAttach", attachFile);
        formData.append("UserId", userId);
        formData.append("UserName", userName);
        formData.append("Message", message);
        formData.append("GroupId", groupId);
     
   $.ajax({
            type: "POST",
            url: "Index?handler=SendMessage",
            data: formData,
            encyType: "multipart/form-data",
            processData: false,
            contentType: false
     });


        $("#message").val('').focus();
        const element = document.getElementById("preChat");
        element.scrollIntoView({ block: "end" });
    });


and this is handler code:

public class InsertChatViewModel
 {
     public string UserId { get; set; }
     public string GroupId { get; set; }
     public string Message { get; set; }
     public string UserName { get; set; }
     public IFormFile FileAttach { get; set; }
 }



public IActionResult OnPostSendMessage([FromForm] InsertChatViewModel model)
{
>>>>>>>>>    It is not called here   <<<<<<<<<

      return Page();
}

Error:

Screenshot 2024-10-31 143558

Developer technologies ASP.NET ASP.NET Core
0 comments No comments
{count} votes

Accepted answer
  1. Anonymous
    2024-11-01T02:11:23.4633333+00:00

    Hi @Ashkan

    However, when sending by ajax, I get a 400 and bad request error and the handler is not called Please guide me where I am doing wrong ?

    The issue might relate the Anti-Forgery Tokens.

    You can check Anti-Forgery Tokens workflow:

    To help prevent CSRF attacks, ASP.NET MVC uses anti-forgery tokens, also called request verification tokens.

    1. The client requests an HTML page that contains a form.
    2. The server includes two tokens in the response. One token is sent as a cookie. The other is placed in a hidden form field. The tokens are generated randomly so that an adversary cannot guess the values.
    3. When the client submits the form, it must send both tokens back to the server. The client sends the cookie token as a cookie, and it sends the form token inside the form data. (A browser client automatically does this when the user submits the form.)
    4. If a request does not include both tokens, the server disallows the request.

    By default, it will automatic generation of antiforgery tokens for HTML form elements happens when the <form> tag contains the method="post" attribute and either of the following are true:

    • The action attribute is empty (action="").
    • The action attribute isn't supplied (<form method="post">).

    Then, when we submit the data to the back-end handler method, it required to add the Verification Token in the request header (the browser will add the cookie token), if the token is invalid or missing, it will show the 400 error.

    So, try to modify your code as below: add the verification token to the header and select the first upload file (based on the view model to select the first upload file).

                $("#sendButton").click(function (event) {
                    event.preventDefault();
                    var userId = $("#userId").val();
                    var userName = $("#username").val();
                    var message = $("#message").val();
                    var groupId = $("#groupid").val();
                    var attachFile = $("#f").get(0).files[0]; //select the upload file.
    
                    var formData = new FormData();
                    formData.append("FileAttach", attachFile);
                    formData.append("UserId", userId);
                    formData.append("UserName", userName);
                    formData.append("Message", message);
                    formData.append("GroupId", groupId);
    
                    $.ajax({
                        type: "POST",
                        url: "Index?handler=SendMessage",
                        headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() }, //add the verification token to the header.
                        data: formData,
                        encyType: "multipart/form-data",
                        processData: false,
                        contentType: false
                    }); 
                }); 
    
    

    The whole sample code as below:

    Index.html

    @page
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div class="text-center">
        <h1 class="display-4">Welcome</h1>
        <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    </div>
    <div class="row">
        <div class="col-md-4">
            <form method="post"> 
                <div class="form-group">
                    <label for="userId" class="control-label"></label>
                    <input id="userId" name="userId" class="form-control" value="11" />
                </div>
                <div class="form-group">
                    <label for="username" class="control-label"></label>
                    <input id="username" name="username" class="form-control" value="AA" />
                </div>
                <div class="form-group">
                    <label for="message" class="control-label"></label>
                    <input id="message" name="message" class="form-control" value="default" />
                </div>
                <div class="form-group">
                    <label for="groupid" class="control-label"></label>
                    <input id="groupid" name="groupid" class="form-control" value="groupA" />
                </div>
                <div class="form-group">
                    <label for="f" class="control-label"></label>
                    <input id="f" name="f" type="file" class="form-control" />
                </div> 
                <div class="form-group"> 
                    <input type="button" value="Send" id="sendButton" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div> 
    @section Scripts{
        <script>
            $(function () {
                $("#sendButton").click(function (event) {
                    event.preventDefault();
                    var userId = $("#userId").val();
                    var userName = $("#username").val();
                    var message = $("#message").val();
                    var groupId = $("#groupid").val();
                    var attachFile = $("#f").get(0).files[0]; //select the upload file.
    
                    var formData = new FormData();
                    formData.append("FileAttach", attachFile);
                    formData.append("UserId", userId);
                    formData.append("UserName", userName);
                    formData.append("Message", message);
                    formData.append("GroupId", groupId);
    
                    $.ajax({
                        type: "POST",
                        url: "Index?handler=SendMessage",
                        headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() }, //add the verification token to the header.
                        data: formData,
                        encyType: "multipart/form-data",
                        processData: false,
                        contentType: false
                    }); 
                }); 
            });
        </script>
    }
    
    

    Index.html.cs

        public class IndexModel : PageModel
        {
            private readonly ILogger<IndexModel> _logger;
    
            public IndexModel(ILogger<IndexModel> logger)
            {
                _logger = logger;
            }
    
            public void OnGet()
            {
    
            }
    
            public IActionResult OnPostSendMessage([FromForm] InsertChatViewModel model)
            { 
                return Page();
            }
    
    

    The result as below:

    User's image

    Or you can disable the AntiforgeryToken use the IgnoreAntiforgeryToken attribute:

        [IgnoreAntiforgeryToken(Order = 1001)]
        public class IndexModel : PageModel
    
    

    More detail information, see Request Verification.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Dillion

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. SurferOnWww 4,631 Reputation points
    2024-10-31T22:19:58.51+00:00

    deletef because duplicated

    1 person found this answer helpful.
    0 comments No comments

  2. SurferOnWww 4,631 Reputation points
    2024-10-31T22:18:06.1033333+00:00

    Please try using nullable reference types for the properties of InsertChatViewModel class


  3. SurferOnWww 4,631 Reputation points
    2024-11-01T04:18:51.99+00:00

    If the issue is related to anti-forgery tokens as mentioned in the answer form @Zhi Lv - MSFT, both the anti-forgery tokens sent by cookie and hidden field have to be posted to the server as shown in the following figure. Red box includes the token sent by cookie. Blue box includes the token sent by hidden field. Please note that the values are different.

    enter image description here

    To do so, I recommend that you obtain FromData from form element which includes the hidden field for the anti-forgery token as shown below:

    <form id="form1" method="post" enctype="multipart/form-data">
        <input id="userId" name="userId" />
        <input id="username" name="username" />
        <input id="message" name="message" />
        <input id="groupid" name="groupid" />
        <input id="f" name="f" type="file" />
    </form>
    
    $("#sendButton").click(function (event) {
        event.preventDefault();
        let formData = new FormData(document.getElementById("form1"));
         
        $.ajax({
            type: "POST",
            url: "Index?handler=SendMessage",
            data: formData,
            processData: false,
            contentType: false
         });
    

    jQuery ajax will post both the tokens sent by cookie and hidden field.

    0 comments No comments

Your answer

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