ModelState.AddModelError 用于 Ajax 加载的部分
ModelState.AddModelError for Ajax loaded partials
我在加载表单的主页上有一个局部视图,模型如下:
public class CreateRequestViewModel
{
[Required]
public short ClientId { get; set; }
[Required]
public Guid SystemId { get; set; }
[Required]
public string RequestedUsername { get; set; }
public string TicketReference { get; set; }
public string Notes { get; set; }
public List<SelectListItem> Clients { get; set; }
public List<SelectListItem> Systems { get; set; }
}
这是局部视图:
@model Models.CreateRequestViewModel
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-12">
<h1>Create a Request</h1>
</div>
<div class="col-lg-8 col-md-8 col-sm-12 right">
<div class="form-group">
@Html.DropDownListFor(m => m.ClientId, Model.Clients, htmlAttributes: new { @class = "form-control form-control-lg", @id = "ClientSelect" })
@Html.ValidationMessageFor(m => m.ClientId, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.DropDownListFor(m => m.SystemId, Model.Systems, htmlAttributes: new { @class = "form-control form-control-lg", @id = "ClientSystemSelect" })
@Html.ValidationMessageFor(m => m.SystemId, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.TextBoxFor(m => m.RequestedUsername, htmlAttributes: new { @class = "form-control form-control-lg", @placeholder = "Username" })
@Html.ValidationMessageFor(m => m.RequestedUsername, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.TextBoxFor(m => m.TicketReference, htmlAttributes: new { @class = "form-control form-control-lg", @placeholder = "Ticket reference" })
</div>
<div class="form-group">
@Html.TextAreaFor(m => m.Notes, htmlAttributes: new { @class = "form-control form-control-lg", @rows = 3, @placeholder = "Notes..." })
</div>
<input type="Submit" class="btn btn-secondary btn-block send-request" value="Submit" name="">
</div>
</div>
这是我加载页面的方式:
<div class="container">
<div class="row">
<div class="col-lg-6">
<form asp-action="CreateRequest" asp-controller="Access"
data-ajax="true"
data-ajax-method="POST"
data-ajax-mode="replace"
data-ajax-update="#createRequest">
<div id="createRequest">
@await Html.PartialAsync("_CreateRequest", Model.CreateRequestModel)
</div>
</form>
</div>
</div>
</div>
使用模型原样并使用不显眼的 javascript,例如将 RequestedUsername 留空将导致不提交表单并显示一条验证消息。这太棒了。
但是,我需要先根据数据库中的条目检查表单数据,如果存在现有记录则抛出错误。我认为,在所有客户端验证都通过后,我会在控制器中使用 ModelState.AddModelError,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateRequest(CreateRequestViewModel model)
{
if(model.RequestedUsername == "someincorrectvalue"){ //actual logic removed for brevity
ModelState.AddModelError("RequestedUsername", "Already in use");
}
if(!ModelState.IsValid)
{
//reset lists on model, removed
return PartialView("_CreateRequest", model);
}
_logger.LogInformation("CreateRequest successful");
return RedirectToAction(nameof(Index));
}
但是,如果我使用 ModelState.AddModelError,return PartialView("_CreateRequest", model)
调用最终会重新加载整个页面,就像返回完整视图一样。
我不知道为什么会这样。我可以看到的区别是我在控制器中添加了一个 ModelState 错误,而验证是在客户端发生的。
有人有想法吗?
所以,这是一个问题的组合。首先,我的解决方案中不显眼的 Ajax 脚本没有执行。我不知道为什么,但我用 CDN 中的一个替换了它们:https://ajax.aspnetcdn.com/ajax/jquery.unobtrusive-ajax/3.2.5/jquery.unobtrusive-ajax.min.js
这解决了整个页面重新加载的问题,而不是通过不显眼的方式返回部分页面 ajax。
第二个问题是,成功后,我重定向到 Index 控制器操作,而不是再次返回 Partial。这导致整个索引页面呈现在我选择的 div 作为我的 ajax 目标。我的控制器操作现在看起来像这样:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateRequest(CreateRequestViewModel model)
{
if(model.RequestedUsername == "someincorrectvalue"){ //actual logic removed for brevity
ModelState.AddModelError("RequestedUsername", "Already in use");
}
if(!ModelState.IsValid)
{
//reset lists on model, removed
return PartialView("_CreateRequest", model);
}
_logger.LogInformation("CreateRequest successful");
// reset lists on model, removed
ModelState.Clear(); // get rid ofany model details to make way for a new request
return PartialView("_CreateRequest", model);
}
我在加载表单的主页上有一个局部视图,模型如下:
public class CreateRequestViewModel
{
[Required]
public short ClientId { get; set; }
[Required]
public Guid SystemId { get; set; }
[Required]
public string RequestedUsername { get; set; }
public string TicketReference { get; set; }
public string Notes { get; set; }
public List<SelectListItem> Clients { get; set; }
public List<SelectListItem> Systems { get; set; }
}
这是局部视图:
@model Models.CreateRequestViewModel
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-12">
<h1>Create a Request</h1>
</div>
<div class="col-lg-8 col-md-8 col-sm-12 right">
<div class="form-group">
@Html.DropDownListFor(m => m.ClientId, Model.Clients, htmlAttributes: new { @class = "form-control form-control-lg", @id = "ClientSelect" })
@Html.ValidationMessageFor(m => m.ClientId, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.DropDownListFor(m => m.SystemId, Model.Systems, htmlAttributes: new { @class = "form-control form-control-lg", @id = "ClientSystemSelect" })
@Html.ValidationMessageFor(m => m.SystemId, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.TextBoxFor(m => m.RequestedUsername, htmlAttributes: new { @class = "form-control form-control-lg", @placeholder = "Username" })
@Html.ValidationMessageFor(m => m.RequestedUsername, "", htmlAttributes: new { @class = "text-danger" })
</div>
<div class="form-group">
@Html.TextBoxFor(m => m.TicketReference, htmlAttributes: new { @class = "form-control form-control-lg", @placeholder = "Ticket reference" })
</div>
<div class="form-group">
@Html.TextAreaFor(m => m.Notes, htmlAttributes: new { @class = "form-control form-control-lg", @rows = 3, @placeholder = "Notes..." })
</div>
<input type="Submit" class="btn btn-secondary btn-block send-request" value="Submit" name="">
</div>
</div>
这是我加载页面的方式:
<div class="container">
<div class="row">
<div class="col-lg-6">
<form asp-action="CreateRequest" asp-controller="Access"
data-ajax="true"
data-ajax-method="POST"
data-ajax-mode="replace"
data-ajax-update="#createRequest">
<div id="createRequest">
@await Html.PartialAsync("_CreateRequest", Model.CreateRequestModel)
</div>
</form>
</div>
</div>
</div>
使用模型原样并使用不显眼的 javascript,例如将 RequestedUsername 留空将导致不提交表单并显示一条验证消息。这太棒了。
但是,我需要先根据数据库中的条目检查表单数据,如果存在现有记录则抛出错误。我认为,在所有客户端验证都通过后,我会在控制器中使用 ModelState.AddModelError,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateRequest(CreateRequestViewModel model)
{
if(model.RequestedUsername == "someincorrectvalue"){ //actual logic removed for brevity
ModelState.AddModelError("RequestedUsername", "Already in use");
}
if(!ModelState.IsValid)
{
//reset lists on model, removed
return PartialView("_CreateRequest", model);
}
_logger.LogInformation("CreateRequest successful");
return RedirectToAction(nameof(Index));
}
但是,如果我使用 ModelState.AddModelError,return PartialView("_CreateRequest", model)
调用最终会重新加载整个页面,就像返回完整视图一样。
我不知道为什么会这样。我可以看到的区别是我在控制器中添加了一个 ModelState 错误,而验证是在客户端发生的。
有人有想法吗?
所以,这是一个问题的组合。首先,我的解决方案中不显眼的 Ajax 脚本没有执行。我不知道为什么,但我用 CDN 中的一个替换了它们:https://ajax.aspnetcdn.com/ajax/jquery.unobtrusive-ajax/3.2.5/jquery.unobtrusive-ajax.min.js
这解决了整个页面重新加载的问题,而不是通过不显眼的方式返回部分页面 ajax。
第二个问题是,成功后,我重定向到 Index 控制器操作,而不是再次返回 Partial。这导致整个索引页面呈现在我选择的 div 作为我的 ajax 目标。我的控制器操作现在看起来像这样:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult CreateRequest(CreateRequestViewModel model)
{
if(model.RequestedUsername == "someincorrectvalue"){ //actual logic removed for brevity
ModelState.AddModelError("RequestedUsername", "Already in use");
}
if(!ModelState.IsValid)
{
//reset lists on model, removed
return PartialView("_CreateRequest", model);
}
_logger.LogInformation("CreateRequest successful");
// reset lists on model, removed
ModelState.Clear(); // get rid ofany model details to make way for a new request
return PartialView("_CreateRequest", model);
}