【发布时间】:2017-02-26 12:46:38
【问题描述】:
问题
我有一个带有一些必需属性和非必需属性的客户端视图模型。视图包含用于更新不同视图模型属性的不同部分。如果我使用所需的客户端详细信息(例如 FirstName、LastName、DOB 等)更新视图的一部分,那么我可以将输入类型包装到 ajax 表单中,控制器将从视图模型中获取这些属性并使用 ModelState 进行相应的验证.IsValid 和验证将成功。但是,如果我在同一个视图上有另一个部分需要更新视图模型(即注释)上的非必需属性并从 ajax 表单发布传递,那么 ModelState 验证失败,因为其他必需属性为空,因为它们从未提交过作为 ajax 表单的一部分。请注意,必填字段应始终在加载客户端详细信息页面之前填充数据,因此不应为空。
代码
视图模型
public class ClientDetailViewModel
{
public int ID { get; set; }
[Required]
[StringLength(50, MinimumLength = 2)]
public string FirstName { get; set; }
[Required]
[StringLength(50, MinimumLength = 2)]
public string LastName { get; set; }
[Required]
[Display(Name = "Date of Birth")]
[DataType(DataType.Date)]
public DateTime DOB { get; set; }
[Required]
public string Gender { get; set; }
public string Notes { get; set; }
}
查看
@model MSIC.Models.ClientViewModels.ClientDetailViewModel
@inject MSIC.Services.Custom.IGenderService GenderService;
<!-- tab-pane for updating core client details -->
<div class="tab-pane active" id="tab_1">
<form asp-controller="Client" asp-action="Edit" class="form-horizontal">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FirstName" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="LastName" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="DOB" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<input asp-for="DOB" class="form-control" />
<span asp-validation-for="DOB" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Gender" class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<select asp-for="Gender" asp-items="@(new SelectList(GenderService.GetAll(),"Code","Name"))" class="form-control">
</select>
<span asp-validation-for="Gender" class="text-danger" />
</div>
</div>
</form>
</div>
<!-- different section for updating client notes -->
<div id="divNotes" class="center-block">@Model.Notes</div>
<a href="#" class="btn btn-danger btn-block" data-toggle="modal" data-target="#notesModal" role="button"><b>Edit Notes</b></a>
<form asp-controller="Client" asp-action="EditNotes" class="form-horizontal" data-ajax="true" data-ajax-method="POST" data-ajax-update="#divNotes" data-ajax-mode="replace" data-ajax-success="CloseModal('#notesModal')" data-ajax-failure="AjaxOnFailure(xhr, status, error)">
<div class="modal fade" id="notesModal" tabindex="-1" role="dialog" aria-labelledby="notesModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="notesModalLabel">edit Reason</h4>
</div>
<div class="modal-body">
<input type="hidden" asp-for="ID" />
<div class="form-group">
<div class="col-sm-10">
<textarea asp-for="Notes" class="form-control" autofocus></textarea>
<span asp-validation-for="Notes" class="text-danger" />
</div>
</div>
</div>
<div class="modal-footer">
<div class="text-danger pull-left">
<i id="modalErrorIcon" class=""></i>
<span id="modalErrorText"></span>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
</form>
控制器
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult EditNotes(ClientDetailViewModel model)
{
//validation fails because required fields in model are null since they were not submitted with this ajax form
if (ModelState.IsValid)
{
//update database with client notes and return notes to screen
return Content(model.Notes);
}
return Content("i haven't coded this yet");
}
问题
如何在不重复代码的情况下有效地在控制器内仅对某些字段执行 ModelState 验证?我搜索了这个问题并知道诸如 ModelState[].Errors.Clear(); 之类的选项。但由于这将是一个大视图,有许多不同的部分可供更新,我想避免在我需要执行的所有小型 ajax 帖子的不同 Action 方法中重复这些语句。基本上我想使用 ModelState 验证,所以我可以将我的验证逻辑存储在 ViewModel 中,而不是分离和/或复制控制器内部的任何验证逻辑。
我可以看到的另一个选项是将所有必需的属性作为隐藏输入类型包含在我拥有的每个 ajax 表单中,但这似乎非常不必要,并且肯定会成为维护的噩梦。有没有更好的方法来传递 ajax 帖子的所有 ViewModel 属性,如果是这样,发送除了利用 ModelState.IsValid 检查之外未使用的 ViewModel 属性是否会很昂贵?
-
我是 asp.net 的新手,从 asp.net core mvc 开始(我非常喜欢),并且一直在通过所有教程、SO 问题等进行学习。但是有可能我正在以错误的方式处理这个问题,如果是这样,使用 asp.net 核心和 Microsoft.jQuery.Unobtrusive.Ajax 或其他一些 ajax 工具解决这个问题的正确方法是什么?请注意,我只发布了这个问题,因为发布的其他类似问题似乎都没有涉及在 View 上共享 ViewModel 属性,但只提交了一些属性,但利用了开箱即用的验证。
提前致谢。
【问题讨论】:
标签: c# ajax validation asp.net-core-mvc