Razor Pages - 由于多个对象共享参数,模型验证失败
Posted
技术标签:
【中文标题】Razor Pages - 由于多个对象共享参数,模型验证失败【英文标题】:Razor Pages - Model validation fails due to multiple objects sharing parameters 【发布时间】:2019-06-01 18:19:31 【问题描述】:我遇到了一个我似乎无法解决的问题。我正在使用 Razor Pages 并且有两个可以绑定的对象。
[BindProperty]
public MeetingMinuteInputDto MeetingToCreate get; set;
[BindProperty]
public MeetingMinuteUpdateDto MeetingToUpdate get; set;
以上两个是单独的 dto,用于在我的数据库中创建/更新基本实体。我有两个单独的 dto,因为我只允许更新特定项目(以防止过度发布)。这两个类都有Name
、Date
和Reminder
。 MeetingMinuteUpdateDto
只允许更改 Date
。
Name 属性是必需的,不能为空。我在同一个页面/控制器中拥有两个对象的原因是因为我使用模式来创建/更新,我宁愿不创建多个页面只是为了创建/编辑对象。
我有两种用户可以填写的表格 - 一种用于编辑,另一种用于创建。每一个都将值绑定到一个特定的对象(即创建表单会将其发布的表单值绑定到MeetingMinuteInputDto
)。
<div class="form-group">
<div class="col-md-10">
<label asp-for="MeetingToCreate.Name" class="control-label"></label>
<input asp-for="MeetingToCreate.Name" class="form-control" />
<span asp-validation-for="MeetingToCreate.Name" class="text-danger"></span>
</div>
</div>
以上是我创建新会议的表单示例。我检查了提交表单时,只绑定了MeetingMinuteInputDto
值。另一个对象 (MeetingMinuteUpdateDto
) 的所有属性都具有空值。
但是当我检查模型状态时,MVC 会在“名称”属性上抛出一个错误,指出它为空。我查看了模型状态的结果,并且有一个名为“Name”的键,它与任何未通过验证的对象无关。
如果我从页面中删除另一个对象(即我删除 MeetingMinuteUpdateDto
)并进行模型绑定,那么一切正常。如何防止模型验证尝试验证与当前操作无关的对象?我希望 Create 操作仅验证创建对象,反之亦然。
我尝试过TryValidateModel(MeetingToCreate)
,但这也为模型验证提供了错误。
注意:我不能只将对象属性放在外面,因为我有其他需要执行此操作的页面,其中更新/创建对象有 10 多个共享/不共享属性.
更新 - 我可以手动从模型状态字典中删除验证错误。但我不太喜欢这种方法,因为我不想遍历所有属性以获取不正确的键并删除它们。
更新 2:以下是有关此问题发生时间的更多详细信息:
public class MeetingMinuteInputDto: MeetingMinuteManipulationDto
public string AdditionalInfo get; set;
public class MeetingMinuteUpdateDto : MeetingMinuteManipulationDto
public class MeetingMinuteManipulationDto
[Required]
public string Name get; set;
public IFormFile FileToUpload get; set;
在我的 Razor 页面中,这两个属性都带有 bind 属性:
public class MeetingMinutesModel : PageModel
[BindProperty]
public MeetingMinuteInputDto MeetingToCreate get; set;
[BindProperty]
public MeetingMinuteUpdateDto MeetingToUpdate get; set;
//...stuff
我在创建/编辑页面上的表单如下所示:
<form asp-page="/MeetingMinute/MeetingMinutes" asp-page-handler="CreateMeeting">
<div class="form-group">
<div class="col-md-10">
<label asp-for="MeetingToCreate.Name" class="control-label"></label>
<input asp-for="MeetingToCreate.Name" class="form-control" />
<span asp-validation-for="MeetingToCreate.Name" class="text-danger"></span>
</div>
</div>
//other inputs and label for rest of the properties
<button type="submit" class="btn btn-danger">Submit</button>
</form>
表单的输入设置为专门绑定到 MeetingToCreate 属性。当我提交表单时,表单值已正确绑定。但与此同时,MeetingToUpdate
属性出现 ModelState 错误(因为它与 MeetingToCreate
共享一些字段)。
我假设在 Razor 页面中,模型状态验证正在验证 MeetingMinutesModel 而不是单个 MeetingToCreate/MeetingToUpdate
属性。在 MVC 中,我认为这可能会有所不同,因为操作需要有参数,而不是 razor 页面中页面模型上的开放式属性。
【问题讨论】:
与其将这些作为属性添加到 PageModel,不如将它们作为 Create 和 Update 操作方法的参数。 @MikeBrind 我需要将它们作为公共参数,因为我需要在我的剃刀视图中访问它们。由于 razor 视图仅接受 razor 页面模型作为模型,如果它们是操作级别参数,我将如何访问视图中的这些值? 您能否分享可以重现该问题的更相关的代码? @XueliChen 详情请看我的最新更新 @DC_AC 没有找到任何允许我使用具有共享属性名称的模型的解决方案。我选择创建一个具有共享属性名称的类,以便它可以用于两个对象,具体取决于调用的页面操作。我相信整个页面本身就是正在验证的“模型”,而不是单个属性,但我必须深入研究源代码来确认这一点。 【参考方案1】:我正在做类似的事情。搜索任何解决方案,我找到了您的问题,但没有解决方案我分享解决方案。
我实现了多个 BindProperty 和多个 Actions OnPost, 我找到的解决方案是在 Asp.Net MVC 中使用 [Bind] 属性做一些事情。
在你的情况下,它会是。
public class MeetingMinutesModel : PageModel
//[BindProperty] remove it
public MeetingMinuteInputDto MeetingToCreate get; set;
//[BindProperty] remove it
public MeetingMinuteUpdateDto MeetingToUpdate get; set;
//...stuff
public IActionResult OnPost([Bind("Name, FileToUpload, AdditionalInfo")] MeetingMinuteInputDto MeetingToCreate)
//Do somthing
【讨论】:
很好的解决方案!绝对可以解决。将相同的标识符声明为 PageModel 的属性和页面处理程序的参数并不理想。 (此外,拥有 PageModel 的属性只能“欺骗”AspNetCore)尽管如此,这是我找到的解决这个问题的最佳解决方案。完全符合我的要求 - 干得好!【参考方案2】:在 Razor pages 中,页面中的 @model 是 PageModel 并且 MeetingMinuteManipulationDto
类的 "Name" 属性是 Required
,因此模型状态验证会验证所有PageModel 中的属性。
如果你坚持原来的想法,你可以尝试使用ViewComponent在同一剃刀视图中实现创建/编辑对象。
【讨论】:
嗨雪莉,我想可能是这样。使用视图组件创建/编辑对象是什么意思?我当然可以将表单放入视图组件并显示在 razor 视图中 - 但是当我发布表单时 - 它最终会进入 razor 页面并具有相同的模型绑定问题。在这种情况下,视图组件有什么帮助?以上是关于Razor Pages - 由于多个对象共享参数,模型验证失败的主要内容,如果未能解决你的问题,请参考以下文章
使用 Razor Pages 在路由中间定义所需的路径参数?