Search code examples
c#asp.net-coreasp.net-core-2.1

Asp.net core mvc ajax post to controller with multiple parameters return bad request


I have my controller action methods as follows,

public class UserController : BaseController<UserController>
{
    [HttpGet]
    public IActionResult Assignment(Guid id)
    {
        return View();
    }

    [HttpPost]
    public IActionResult Assignment(Guid id, [FromBody] List<UserViewModel> assignees)
    {
        return View();
    }
}

The ajax method in Assignment.cshtml page

$("#btn-save").click(function () {
    var url = "/User/Assignment/@Model.SelectedUser.Id";
    $.ajax({
        type: "POST",
        url: url,
        contentType: "application/json",
        data: JSON.stringify({ assignees: assignmentPage.SelectedUsers })
    });
});

So this builds a url like;

http://localhost:8800/User/Assignment/f474fd0c-69cf-47eb-7281-08d6536da99f

This is the only route configuration in my Startup.cs.

app.UseMvc(routes =>
{
    routes.MapRoute(name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

I never hit to Assignment post action, server returns 400, I've searched and couldn't find yet, how am I supposed to configure my route for an action like this?


Solution

  • The problem for my case is I am using AutoValidateAntiforgeryTokenAttribute configuration

    services.AddMvc(options =>{
        // Automatically add antiforgery token valdaiton to all post actions.
        options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
    }
    

    So, ajax post has not any request verification token with itself, lack of this token server returns bad request.

    To overcome this, I followed this link, so my final working code as,

    Assignment.cshtml

    @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
    @functions
    {
        public string GetAntiXsrfRequestToken() => Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
    <input type="hidden" id="RequestVerificationToken" name="RequestVerificationToken" 
           value="@GetAntiXsrfRequestToken()">
    
    <script type="text/javascript">
        $("#btn-saveinspectors").click(function () {
            var url = "/Audit/Assignment/@Model.SelectedUser.Id";
            var assignees = JSON.stringify(assignmentPage.SelectedUsers);
    
            $.ajax({
                type: "POST",
                url: url,
                beforeSend: function (xhr) {
                    xhr.setRequestHeader("XSRF-TOKEN", $('#RequestVerificationToken').val());
                },
                contentType: "application/json",
                data: assignees,
            });
        });
    </script>
    

    Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
    }
    

    Note: This is my case that there is not any form inside my page where a request verification token is generated automatically. If you have a form in your page where you make an ajax request then you can follow this post