Asp.net core mvc ajax post 到具有多个参数的控制器 return 错误请求

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

我的控制器操作方法如下,

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();
    }
}

Assignment.cshtml 页面中的 ajax 方法

$("#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 })
    });
});

所以这构建了一个 url 喜欢;

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

这是我Startup.cs中唯一的路由配置。

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

我从未点击过作业 post 操作,服务器 returns 400,我已经搜索并还没有找到,我应该如何为这样的操作配置我的路线?

您发送到服务器的数据无效。它需要一个 JSON 数组,但您向它发送一个 JSON 对象,其中包含一个 属性 本身就是一个数组。由于 JSON.NET 无法将对象解析为数组,您会收到 400 状态代码。

为了进一步说明,这是您要发送的内容:

{
    "assignees": [
        { ... assignee1 ... },
        { ... assignee2 ... },
        ...
    ]
}

但是,这是预期的数组,因此它应该如下所示:

[
    { ... assignee1 ... },
    { ... assignee2 ... },
    ...
]

您需要做的就是将当前的 JSON.stringify 行更改为:

JSON.stringify(assignmentPage.SelectedUsers)

另一种选择是在您的 ASP.NET 核心项目中创建一个模型 class 并使用它来代替字符串列表。这是它的样子:

public class AssignmentModel
{
    public List<UserViewModel> Assignees { get; set; }
}

Assignment 操作如下所示:

public IActionResult Assignment(Guid id, [FromBody] AssignmentModel thisNameDoesNotMatter)

我的问题是我正在使用 AutoValidateAntiforgeryTokenAttribute 配置

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

所以,ajax post 本身没有任何请求验证令牌,缺少此令牌服务器 returns 错误请求。

为了克服这个问题,我遵循了这个 link,所以我的最终工作代码是,

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");
}

注意:这是我的情况,我的页面中没有任何自动生成请求验证令牌的表单。如果您的页面中有一个表单,您可以在其中提出 ajax 请求,那么您可以关注 this post