在模型的属性上使用EF [必需]批注,但跳过验证-是否重写ModelValidationState?

时间:2018-06-22 04:04:42

标签: c# asp.net-core entity-framework-core asp.net-core-2.0

在Asp.Net Core 2.0和EF Core中,如何覆盖属性的验证属性?如果我在属性中添加[Required]注释,则会发生两件事:

  1. EF将数据库列标记为非空->很好。我想要这个。
  2. 在控制器中,在POST之后,ModelState将此属性报告为验证失败(因此ModelState.IsValid返回false)->错误。此属性从HTML表单中排除,因为我仅在控制器中添加了FK值。

我有一个带有“作者”必填属性的模型,该模型映射到IdentityUser。在数据库中,该列不应为空,但我不想在客户端和服务器之间传递用户ID。相反,当收到POST时,我只是从上下文中获取用户ID并在模型上设置FK属性。

因此,我想要的结果是一些数据注释,该注释指定该属性对于数据库目的是必需的,而对于ModelState而言,对于验证目的是可选的/跳过的。


模型

public class ArticleModel
{
    [Required]
    public string Title {get;set}
    [Required]
    public string Body {get;set;}

    [Required]
    public IdentityUser Author { get; set; }

    [ForeignKey("Author")]
    public string AuthorId { get; set; }
}

视图 (视图不了解或不在乎作者)

<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Body" class="control-label"></label>
                <input asp-for="Body" class="form-control" />
                <span asp-validation-for="Body" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>

控制器的创建方法
(由于Author的无效状态,ModelState.IsValid始终为false)

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public IActionResult Create([Bind("Body,Title")] ArticleModel articleModel)
    {
        articleModel.AuthorId = User.FindFirstValue(ClaimTypes.NameIdentifier);

        if (ModelState.IsValid)
        {
            DoStuff();
            return RedirectToAction(nameof(Index));
        }
        return View(articleModel);
    }

一个修正(丑陋,脆弱,并在多个处理程序上重复出现)
检查所有所需的字段均有效,然后忽略其余字段... 将
if (ModelState.IsValid)
替换为
if (ModelState.Where(k => k.Key != "Author").All(v => v.Value.ValidationState == ModelValidationState.Valid))


更好的(?)修复程序(正确-使用DTO)
我在这里尝试使用MS的默认脚手架,该脚手架采用模型并将其仅馈送到视图。过去,我通常使用DTO手动完成此操作,而这一切都是没有问题的。在Asp.Net Core时代,这仍然是更好的方法吗?


我认为可以找到的解决方法
在模型中。...

[Required]
[Validation(Mode=ValidationModes.Manual)]
public IdentityUser Author {get;set;}

1 个答案:

答案 0 :(得分:1)

直接使用实体类绑定到POST等存在很多问题。需要不同验证规则的视图当然是其中之一,但是您还必须处理过分张贴,潜在的上下文冲突等问题。将实体类与“模型”相结合是ASP.NET MVC的原始缺点,不幸的是, Microsoft在阻止这种与ASP.NET Core的合并方面做得更好。简而言之,实体类不是模型。实体类有一个简单的用途,将数据库表行表示为一个对象。期。除此之外,将其用于其他任何事情都将导致问题。

简短的说,是的,您应该使用视图模型,DTO等。无论您怎么说,它们本质上都是同一件事。您正在创建一个类,以用于查看或从特定方法返回的目的,以使数据库表示与之分离。您的实体类应仅包含数据库所需的逻辑。您的视图模型/ DTO应该只包含它们所要馈送的逻辑。然后,将一个映射到另一个。这不仅可以解决您的问题,也可以解决其他问题,而且还可以消除代码中的依赖关系,这总是一件好事。