ASP.NET 使用 EF Core 3 进行 Core 3 远程验证

ASP.NET Core 3 remote validation with EF Core 3

确实有点像 EF 初学者的问题,但我运行正在使用 ASP.NET MVC Core 3 和 EF Core 3 进行[远程] 验证时遇到问题。

在微软的一篇帖子之后,它建议保留所有内容 "DRY"(不要重复自己)。因此,按照指示,我将用于验证的数据注释添加到我的 'entity' class(我上下文中的 DbSet)。这感觉有点奇怪,将 Presentation 逻辑与我的 DB 逻辑混合在一起,但我也喜欢只写一次,所以我想试一试。

关于我的实体。它与另一个实体具有多对多关系。假设我的实体是 "Person",那么,有一个此人可以拥有的汽车列表。

我的创建方法

过去使用 MVC,我总是编写 'view model' 来包含视图中数据绑定所需的内容。但是,为了保持干燥,我显然需要使用我的 Person 实体 class 在 View 中进行绑定,因为那是我的 DataAnnotations 所在的位置。它有我不需要用户填写的各种其他属性,所以我想我只是不必在 UI 上公开它们(尽管我知道这不会阻止黑客向我提供该信息...但这是另一个话题。)

对于创建简单的输入框,这非常有效,但我需要向用户显示可供选择的汽车列表。那么,我从哪里获得可用汽车列表,因为它不在我的实体上?我通过创建一个类似于此的包装 ViewModel class 来解决这个问题:

public class MyViewModel
{
    public Person Entity {get; set;}
    public List<Car> Cars {get;set;}
}

现在我必须将数据绑定到我调用的 "Entity" 的 属性 并且我可以从另一个 属性.[=15= 中提取额外的汽车数据]

这也很好用。但是,我在进行验证时 运行 遇到了问题。

所以我的人 class 有以下(假装)属性

public class Person
{
    [Remote("CheckIdIsAvailable","Persons")]
    public string Id { get; set; }
}

因此,回顾一下我的 Person 实例是我的 ViewModel 的实体 属性,因此 View 具有以下形式:

<tr>
    <td>ID</td>
    <td><input asp-for="Entity.Id" /></td>
    <td><span asp-validation-for="Entity.Id" class="text-danger"></span></td>
</tr>

在我的控制器中,我有验证方法:

[HttpGet]
public async Task<IActionResult> CheckIdIsAvailable(string Id)
{
    ....
}

但是,该值是 "null",因为通过网络发送的参数是“...?Entity.Id=ABCD”和我的字符串被称为 'Id' 而不是 'Entity.Id'.

所以,我要么在这里遗漏了一些明显的东西,要么是以错误的方式进行的。

您可以在远程验证操作的对象中接收 Entity.Id

[HttpGet]
 public async Task<IActionResult> CheckIdIsAvailable(Person entity)
{
  string Id = entity.Id;
  //other logic
}

对于模型绑定,参数的名称是 entity

正如 Chris Pratt 所说,您是正确的,您应该使用 ViewModel 对象来绑定到视图和从视图绑定。

值得查看标签助手为您生成的 HTML,并注意输入将具有 name 属性以及您在其中链接到的任何 属性对象(asp-for="" 部分)。名称 属性 是从视图到控制器的 model binding 知道如何映射从视图返回的对象的方式。

但理想情况下,您会在填充视图后向视图发送一个 ViewModel 对象,并期望一个返回并映射到您的实体和从任何一侧映射,而不 sending/exposing 您的实体到外部世界.

public async Task<IActionResult> CheckIdIsAvailable(PersonViewModel model)
{

}

然后您将验证添加到 ViewModel 属性而不是您的实体。

您的实体 类 中您真正应该拥有的唯一属性是您是否使用代码优先并且您正在定义数据库中的字段 - 例如字符串字段的 [MaxLength()] 属性(这是一个很好的做法,因为默认情况下我认为 EF 会生成字符串字段 NVARCHAR(MAX) 如果你不定义它们,这对以后的查找来说不是很好。但这不是重点。

除了属性之外,还有其他方法可以定义字段属性,这会导致 'cleaner' 实体定义,但这也不是这里的真正问题。