如何修复 .Net Core POST 操作中的 400 Bad Request 错误?

2024-03-31

我有一个 .Net Core 2.1 API,它使用 EF core 发布数据。当我从 Postman 向 http://localhost:3642/task/create 发出 POST 请求时,收到 400 Bad Request 错误(由于语法错误,该请求无法完成)。在深入研究后,我得到了注释掉的建议验证来自控制器的AntiForgery 令牌。当我通过邮递员发送带有此更改的请求时,我收到 200 Ok 状态消息,但没有数据被提交到 Sql Server 中的表。我是否应该在 API 中配置一些东西,或者我还缺少什么东西?

我的控制器如下所示:

 [HttpPost]
 // [ValidateAntiForgeryToken]
 public async Task<IActionResult> 
Create([Bind("Assignee,Summary,Description")] TaskViewModel taskViewModel)
    {
if (ModelState.IsValid)
            {
                _context.Add(taskViewModel);
 await _context.SaveChangesAsync();
                return RedirectToAction("Index");
            }
            return View();
        }

在 TaskViewModel.cs 中我有:

 public class TaskViewModel 
{
    [Required]
    public long Id { get; set; }

    [Required(ErrorMessage = "Please provide Task Summary")]
    [Display(Name = "Summary")]
    public string Summary { get; set; }

    [Required(ErrorMessage = "Please enter task description")]
    [Display(Name = "Description")]
    public string Description { get; set; }

    [Required(ErrorMessage = "Please select Assignee")]
    [Display(Name = "Assign To")]
    public string Assignee { get; set; }
}

这是我在 Postman 中的负载:

{
    "Assignee": "Ed tshuma",
    "Summary": "Finish reconciliations",
    "Description": "collate all the pending data"
}

这里有很多问题。首先也是最重要的,为什么要将视图模型保存到数据库中。这实际上是一个entity在这种情况下,不是视图模型。您绝对应该使用视图模型,但您还应该有一个单独的实体类。然后,您的视图模型应该只包含您希望实际允许用户编辑的属性,从而完全不需要Bind属性,无论如何都应该避免。 (看:束缚是邪恶的 https://cpratt.co/bind-is-evil/).

// added "Entity" to the name to prevent conflicts with `System.Threading.Task`
[Table("Tasks")]
public class TaskEntity
{
    [Key]
    public long Id { get; set; }

    [Required]
    public string Summary { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    public string Assignee { get; set; }
}

public class TaskViewModel
{
    [Required(ErrorMessage = "Please provide Task Summary")]
    [Display(Name = "Summary")]
    public string Summary { get; set; }

    [Required(ErrorMessage = "Please enter task description")]
    [Display(Name = "Description")]
    public string Description { get; set; }

    [Required(ErrorMessage = "Please select Assignee")]
    [Display(Name = "Assign To")]
    public string Assignee { get; set; }
}

另外,还要注意职责分工。该实体仅包含对数据库重要的内容([Required]这里指示该列应该是不可为空的)。而视图模型只关心视图。没有Id属性,因为它不是必需的或不需要的,并且要呈现给用户的显示名称和错误消息仅放置在此处。

然后,您需要从视图模型映射到实体类:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(TaskViewModel model)
{
    if (!ModelState.IsValid)
        return View(model);

    var task = new TaskEntity
    {
        Assignee = model.Assignee,
        Summary = model.Summary,
        Description = model.Description
    };

    _context.Add(task);
    await _context.SaveChangesAsync();
    return RedirectToAction("Index");
}

这里的映射相当简单,但您可能更喜欢使用像 AutoMapper 这样的库来为您处理这个问题:_mapper.Map<TaskEntity>(model).

虽然这是专门针对创建操作的,但值得指出更新的细微差别。您需要首先从数据库中检索现有任务,然后将发布的值映射到该任务上。其余部分保持相对相同:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Update(long id, TaskViewModel model)
{
    if (!ModelState.IsValid)
        return View(model);

    var task = await _context.Tasks.FindAsync(id);
    if (task == null)
        return NotFound();

    task.Assignee = model.Assignee;
    task.Summary = model.Summary;
    task.Description = model.Description;

    await _context.SaveChangesAsync();
    return RedirectToAction("Index");
}

最后,关于你的问题的主要问题,有两个问题。首先,此操作是为传统的 HTML 表单帖子而设计的(x-www-form-urlencoded)。因此,向其发送 JSON 是没有意义的,并且向其发送 JSON 也不起作用。要在 Postman 中测试它,您应该将请求发送为x-www-form-urlencoded。如果您不这样做,那么您的模型本质上将始终无效,因为帖子主体中的任何内容都不会绑定到您的模型。

为了接收 JSON,您的参数需要具有FromBody应用于它的属性([FromBody]TaskViewModel model)。但是,如果您这样做,您将无法再接收传统的表单帖子,在这种情况下,这就是将要发送的内容。如果您通过 AJAX 发送(您可以想象使用 JSON),那么您也应该返回JSON 或者也许PartialView, 但不是View或重定向。

最后,您需要包含请求验证令牌,它应该是帖子正文名称中的另一个键__RequestVerificationToken。要获取要发送的值,您需要首先加载视图的 GET 版本,然后检查源。将会有一个带有该值的隐藏输入。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何修复 .Net Core POST 操作中的 400 Bad Request 错误? 的相关文章

随机推荐