代码之家  ›  专栏  ›  技术社区  ›  Kevin Fichter

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

  •  1
  • Kevin Fichter  · 技术社区  · 8 年前

    在ASP.NET Core 2.0&EF Core中,如何重写属性的验证属性?如果向属性添加(必需的)注释,则会发生两件事:

    1. EF将数据库列标记为NULL NULL。我想要这个。
    2. 在控制器中,跟着一根柱子, ModelState 将此属性报告为验证失败(因此) ModelState.IsValid 收益率 false )-->坏。这个属性在HTML中被排除在窗体中,因为我只是在控制器中添加了FK值。

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

    因此,我想要的结果是一些数据注释,指定属性是为了数据库目的而需要的,但是对于MODESTATE来说,是为了验证目的而选择/跳过。


    模型

    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>
    

    控制器的创建方法
    (由于作者的状态无效,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核心时代更好的途径吗?


    我想我会找到的解决方法
    在模型中…

    [Required]
    [Validation(Mode=ValidationModes.Manual)]
    public IdentityUser Author {get;set;}
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Chris Pratt    8 年前

    直接使用实体类绑定到post之类的东西有很多问题。一个需要不同验证规则的视图当然是其中之一,但是您还必须处理过多的、潜在的上下文冲突等。将实体类与一个“模型”混为一谈是ASP.NET MVC的一个原罪,而不幸的是,微软在阻止与ASP.NET核心的这种融合方面做得更好。简单地说,实体类是 模型。实体类有一个简单的用途,将数据库表行表示为对象。时期。把它用在其他任何事情上都会引起问题。

    长和短,是的,你应该利用视图模型,DTOs等等。无论你怎么称呼它们,它们本质上都是一样的。您正在创建一个类,用于视图或特定方法的返回,以便将数据库表示与该方法解耦。实体类应该只包含数据库所需的逻辑。视图模型/dto应该只包含它们提供的内容所必需的逻辑。然后,将一个映射到另一个。这不仅解决了这里的问题,也解决了其他问题,而且还有助于从代码中删除依赖项,这总是一件好事。

    推荐文章