...如何将 ModelError 显示到我的 View Index.cshtml 中?
显示错误信息
根据您在Login 操作底部对return RedirectToAction("Index", "Home"); 的调用,我最初假设您希望重定向到主页(HomeController 操作Index)。现在我在想,这可能是您的流程中的一个错误,您实际上是在尝试向用户显示错误消息而不进行重定向,并且您只想在一切成功时进行重定向。 如果是这种情况,那么只需阅读本部分并跳过有关如何在 RedirectToAction 调用中保持模型状态的其余部分。如果出现故障,您只需拨打View 而不是RedirectToAction。
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
}
}
return View(model); // goes back to the login view with the existing model and validation error
// return RedirectToAction("Index", "Home");
}
Login.cshtml 在某处包含以下内容
@Html.ValidationSummary()
使用 RedirectToAction
它不起作用的原因是当您执行RedirectToAction 时,包含验证消息的ViewData 丢失了。解决方案有多种选择。
- 在
RedirectToAction 中保留ViewData,然后恢复它。
- 只保留
ModelState,然后在RedirectToAction 中指定的新操作执行后将其与ModelState 合并。
保留视图数据
在大多数情况下,这可以正常工作,但如果您重定向到操作(在这种情况下,HomeController 上的索引)有它自己依赖的 ViewData,则可能会导致问题。 p>
LoginController.cs
// simplified code to just show the relevant parts to reproduce the problem/solution
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
// ... some other code
ModelState.AddModelError("", "The user name or password provided is incorrect");
// ... some other code
if (!ModelState.IsValid)
TempData["ViewData"] = ViewData;
return RedirectToAction("Index", "Home");
}
HomeController.cs
public ActionResult Index()
{
if (TempData["ViewData"] != null)
{
// restore the ViewData
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
return View();
}
Home\Index.cshtml
@Html.ValidationSummary()
合并模型状态
这将是我推荐的方法,因为您在自定义 ActionFilter 属性上定义了希望这种情况发生一次的方式,然后应用到您希望发生的位置。您也可以将此代码直接放入您的控制器中,但是一旦您需要在多个控制器上执行此操作,这将违反 DRY 原则。
如果TempData 尚未包含"ModelState" 键,则此处的方法是将模型状态写入TempData。如果已经存在密钥,则意味着当前请求刚刚写入它,我们可以从中读取并将其与我们现有的模型状态合并。这将防止代码无意中覆盖 ViewState 或 ModelState,因为 ModelState 现在已合并。 只有当有多个RedirectToActions 都选择写入 ModelState 时,我才能看到这会出错,但我认为这不太可能发生。
ModelStateMergeFilterAttribute.cs
public class ModelStateMergeFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// write to the temp data if there is modelstate BUT there is no tempdata key
// this will allow it to be merged later on redirect
if (filterContext.Controller.TempData["ModelState"] == null && filterContext.Controller.ViewData.ModelState != null)
{
filterContext.Controller.TempData["ModelState"] = filterContext.Controller.ViewData.ModelState;
}
// if there is tempdata (from the previous action) AND its not the same instance as the current model state THEN merge it with the current model
else if (filterContext.Controller.TempData["ModelState"] != null && !filterContext.Controller.ViewData.ModelState.Equals(filterContext.Controller.TempData["ModelState"]))
{
filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
}
base.OnActionExecuted(filterContext);
}
}
LoginController.cs
// simplified the code to just show the relevant parts
[HttpPost]
[ModelStateMergeFilter]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
return RedirectToAction("Index", "Home");
}
HomeController.cs
[ModelStateMergeFilter]
public ActionResult Index()
{
return View();
}
Home\Index.cshtml
@Html.ValidationSummary()
参考文献
这里有一些参考资料也详细说明了其中一些方法。我还依赖这些先前答案中的一些输入来回答上面的问题。