ASP.NET显示ModelState.AddModelError [英] ASP.NET display ModelState.AddModelError
问题描述
我这里此方法,这是一个登录方法,如果用户名和密码不正确被添加一个ModelError
[HttpPost]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{ 如果(ModelState.IsValid)
{
如果(Membership.ValidateUser(model.UserName,model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName,model.RememberMe);
如果(Url.IsLocalUrl(RETURNURL)及&放大器; ReturnUrl.Length→1&放大器;&放大器; ReturnUrl.StartsWith(/)
&功放;&安培; !ReturnUrl.StartsWith(//)及与放大器; !ReturnUrl.StartsWith(/ \\\\))
{
返回重定向(RETURNURL);
}
其他
{
返回RedirectToAction(指数,家);
}
}
其他
{
ModelState.AddModelError(,提供的用户名或密码不正确);
}
} 返回RedirectToAction(指数,家);
}
我的问题是如何显示ModelError我的看法Index.cshtml?
...我将如何显示ModelError我的看法Index.cshtml?
块引用>显示错误消息
我最初做,你想重定向到主页的假设(
的HomeController
行动首页
)的基础上您的来电返回RedirectToAction(指数,家);
在登录
动作的底部。现在我想,也许这是你流了一个错误,你实际上是试图展示错误信息给用户,无需重定向,并且您只希望如果一切成功重定向。 如果是这样的话,然后只阅读这部分,并跳过有关如何在RedirectToAction
通话持续模型状态休息。所有你需要做的就是调用查看
而不是RedirectToAction
中是否有故障。[HttpPost]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
如果(ModelState.IsValid)
{
如果(Membership.ValidateUser(model.UserName,model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName,model.RememberMe);
如果(Url.IsLocalUrl(RETURNURL)及&放大器; ReturnUrl.Length→1&放大器;&放大器; ReturnUrl.StartsWith(/)
&功放;&安培; !ReturnUrl.StartsWith(//)及与放大器; !ReturnUrl.StartsWith(/ \\\\))
{
返回重定向(RETURNURL);
}
其他
{
返回RedirectToAction(指数,家);
}
}
其他
{
ModelState.AddModelError(,提供的用户名或密码不正确);
}
} 返回查看(模型); //追溯到与现有的模型和验证错误登录视图
//返回RedirectToAction(指数,家);
}Login.cshtml 某处包括以下的
@ Html.ValidationSummary()
与RedirectToAction工作
它不工作的原因是
的ViewData code>,其中包括验证消息,当您执行丢失的
RedirectToAction
。有几个选项的解决方案。
- 保留要么保持在
的ViewData code>横跨
RedirectToAction
,然后还原它。- 仅坚持了
的ModelState
,然后合并到的ModelState
曾经在<$ C指定的新动作$ C> RedirectToAction 已经执行。坚持的ViewData H1>
在大多数情况下,这工作得很好,但如果你重定向到行动(的在这种情况下,指数上的
的HomeController
的),有可能会导致问题的自己的的ViewData code>它所依赖的。
LoginController.cs
//简化code只显示相关部分重现该问题/解决方案
[HttpPost]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
// ...一些其他的code
ModelState.AddModelError(,提供的用户名或密码不正确);
// ...一些其他的code 如果(!ModelState.IsValid)
TempData的[的ViewData] = ViewData的; 返回RedirectToAction(指数,家);
}HomeController.cs
公众的ActionResult指数()
{
如果(TempData的[的ViewData]!= NULL)
{
//恢复的ViewData
ViewData的=(的ViewDataDictionary)的TempData [的ViewData];
} 返回查看();
}首页\\ Index.cshtml
@ Html.ValidationSummary()
合并的ModelState
这是因为你定义将是我推荐的方法你怎么想这是一个自定义
ActionFilter
属性发生一次,然后应用,你想让它发生。你也可以直接把这个code到您的控制器,但将只要你需要做到这一点在多台控制器违反了DRY原则。下面的方法是编写模型状态到
的TempData code>如果
的TempData code>不包含任何
的ModelState
键。如果已经有一个关键的present这意味着当前请求刚写完它,我们可以从中读取和合并,以我们现有的模型状态。这将prevent无意中覆盖的ViewState或ModelState中作为的ModelState现在合并了code。的我只能看到这个走错了,如果有多个RedirectToActions
所有选择要写入的ModelState,但我不认为这是一个可能的情况。ModelStateMergeFilterAttribute.cs
公共类ModelStateMergeFilterAttribute:ActionFilterAttribute
{
公共覆盖无效OnActionExecuted(ActionExecutedContext filterContext)
{
//写入临时数据,如果有ModelState中,但没有TempData的关键
//这将允许它稍后重定向被合并
如果(filterContext.Controller.TempData [的ModelState] == NULL和放大器;&安培;!filterContext.Controller.ViewData.ModelState = NULL)
{
filterContext.Controller.TempData [的ModelState] = filterContext.Controller.ViewData.ModelState;
}
//如果有TempData的(从previous行动)和它不一样的实例作为当前模型状态,则与现款车型进行合并
否则,如果(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
//简化了code只显示相关零件
[HttpPost]
[ModelStateMergeFilter]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
ModelState.AddModelError(,提供的用户名或密码不正确);
返回RedirectToAction(指数,家);
}HomeController.cs
[ModelStateMergeFilter]
公众的ActionResult指数()
{
返回查看();
}首页\\ Index.cshtml
@ Html.ValidationSummary()
参考
下面是一些参考资料也详细一些办法。我也依赖于一些从上面我的回答这些previous答案的投入。
I have this method here, which is a login method and if the username and password is incorrect a ModelError gets added.
[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 RedirectToAction("Index", "Home"); }
My question is how would I display the ModelError to my View Index.cshtml?
解决方案... how would I display the ModelError to my View Index.cshtml?
Showing Error message
I initially made the assumption that you wanted to redirect to the home page (
HomeController
actionIndex
) based on your call toreturn RedirectToAction("Index", "Home");
at the bottom of theLogin
action. Now I am thinking maybe this is a mistake in your flow and you are actually trying to show the error message to the user without redirecting and that you only want to redirect if everything succeeds. IF this is the case then just read this part and skip the rest about how to persist model state acrossRedirectToAction
calls. All you need to do is callView
instead ofRedirectToAction
if there is a failure.[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 include the following somewhere
@Html.ValidationSummary()
Working with RedirectToAction
The reason it is not working is the
ViewData
, which includes the validation messages, is lost when you execute theRedirectToAction
. There are a couple of options for a solution.
- Keep either persist the
ViewData
across theRedirectToAction
and then restore it.- Only persist the
ModelState
and then merge it with theModelState
once the new action specified in theRedirectToAction
has executed.
Persist ViewData
In most scenarios this works just fine but could cause problems if your redirected to action (in this case Index on the
HomeController
) has its ownViewData
that it depends on.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()
Merge the ModelState
This is would be my recommended approach because you define how you want this to happen once on a custom
ActionFilter
attribute and then apply where you want it to occur. You could also put this code directly into your controller but that would violate the DRY principle as soon as you need to do this on multiple controllers.The approach here is to write the model state to the
TempData
if theTempData
does not already contain a"ModelState"
key. If there is already a key present that means that the current request has just written to it and we can read from it and merge that with our existing model state. This will prevent the code from unintentionally overwriting the ViewState or the ModelState as the ModelState is now merged. I can only see this going wrong if there are multipleRedirectToActions
that all choose to write to the ModelState but I do not think this is a likely scenario.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()
References
Here are some references that also detail some of these approaches. I also relied on some of the input from these previous answers for my answer above.
- How do I maintain ModelState errors when using RedirectToAction?
- How can I maintain ModelState with RedirectToAction?
这篇关于ASP.NET显示ModelState.AddModelError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!