Search code examples
jqueryajaxasp.net-corerazor-pagesajax-upload

400 Bad Request on POST in ASP.NET Core Web API via Ajax ( Not to a controller but, to same page event handler)


I am using ASP.NET Core Razor pages in .NET 8 and VS2022.

I am trying to keep my controllers hidden from the public, so all my POST requests first call the same page. Eg www.mywebsite.com/index will call the ASP.NET Core event handler for the index page.

SCENARIO 1

When I try to upload via Ajax post (if I call a controller with the anti forgery token, it works), it hits the controller action. But fails with the Razor page, event handler of the same page

SCENARIO 2

When I try to upload to the same index page, I get bad request. Here is my code. I have tried using IActionResult and adding an ImageUpload class (which is commented out below), both of which produce the same result: BAD REQUEST

//public async Task<IActionResult> OnPostAsync(ImageUpload imageUpload)
public async Task OnPostAsync()
{
    var file = Request.Form.Files[0];
    var fileName = Path.GetFileName(file.FileName);
    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads", fileName);

    using (var fileStream = new FileStream(filePath, FileMode.Create))
    {
        await file.CopyToAsync(fileStream);
    }

    //return Content($"File '{fileName}' uploaded successfully.");
}

Here is my frontend code. I have tried using examples I seen online, by JSON.Stringfy, which also does not work:

$('#fileInput').change(function () {
    var token = $('#__RequestVerificationToken').val();
        
    var file = this.files[0];

    if (file) {
        var reader = new FileReader();
        var formData = new FormData();
        formData.append('file', file);
        reader.onload = function (e) {
            $('#previewImage').attr('src', e.target.result).show();

            var formData = new FormData();
            formData.append('file', file);
            var formData2 = JSON.stringify(formData);
            $.ajax({
                type: "POST",
                url: "",//this enables it to post to the root
                contentType: "application/json",
                processData: false,
                data: formData2,
                headers: {
                            RequestVerificationToken: token
                        },
                success: function (response) {
                    console.log('File uploaded successfully');
                },
                error: function (xhr, status, error) {
                    console.error('Error uploading file:', error);
                }
            });
        };
    }
});

And finally, this is my HTML:

<form>
 @Html.AntiForgeryToken()
<p>
    <input type="file" id="fileInput" accept="image/*">

    <br><br>
    <img src="" id="previewImage" style="max-width: 300px; max-height: 300px; display: none;">
</p>
</form>

Solution

  • The most common cause for a 400 Bad Request status code in Razor Pages is a missing Request Verification token. You can use F12 to see the token value in the source tab, set a breakpoint at var token = $('#__RequestVerificationToken').val(); it show :

    enter image description here

    change it to:

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

    result: enter image description here

    Try the code like:

    $('#fileInput').change(function () { 
        var token = $('input:hidden[name="__RequestVerificationToken"]').val();
        var file = this.files[0];
    
        if (file) {
            var reader = new FileReader();
            var formData = new FormData();
            formData.append('file', file);
            reader.onload = function (e) {
                $('#previewImage').attr('src', e.target.result).show();
    
                var formData = new FormData();
                formData.append('file', file);
            }
        }            
                $.ajax({
                    type: "POST",
                    url: "/Index",//this enables it to post to the root                
                    processData: false,
                    contentType: false,
                    data: formData,
                    headers: {
                        RequestVerificationToken: token
                    },
                    success: function (response) {
                        console.log('File uploaded successfully');
                    },
                    error: function (xhr, status, error) {
                        console.error('Error uploading file:', error);
                    }
                });
         
    });
    

    result:

    enter image description here