如果我的ModelState中存在错误而不丢失我的ModelState信息,如何返回不同操作的结果或将用户移动到其他操作?
情景是; 删除操作接受由我的索引操作/视图呈现的DELETE表单中的POST.如果删除中出现错误,我想将用户移回索引操作/视图,并显示删除操作存储的错误ViewData.ModelState
.如何在ASP.NET MVC中完成?
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Delete)] public ActionResult Delete([ModelBinder(typeof(RdfUriBinder))] RdfUri graphUri) { if (!ModelState.IsValid) return Index(); //this needs to be replaced with something that works :) return RedirectToAction("Index"); }
tvanfosson.. 96
将您的视图数据存储在TempData中,并在Index操作中从那里检索它(如果存在).
... if (!ModelState.IsValid) TempData["ViewData"] = ViewData; RedirectToAction( "Index" ); } public ActionResult Index() { if (TempData["ViewData"] != null) { ViewData = (ViewDataDictionary)TempData["ViewData"]; } ... }
[编辑]我查了上线来源MVC和它看来,ViewData的在控制器中设定的,所以它可能是最简单的办法来传输所有的ViewData的,包括的ModelState,对指数作用.
将您的视图数据存储在TempData中,并在Index操作中从那里检索它(如果存在).
... if (!ModelState.IsValid) TempData["ViewData"] = ViewData; RedirectToAction( "Index" ); } public ActionResult Index() { if (TempData["ViewData"] != null) { ViewData = (ViewDataDictionary)TempData["ViewData"]; } ... }
[编辑]我查了上线来源MVC和它看来,ViewData的在控制器中设定的,所以它可能是最简单的办法来传输所有的ViewData的,包括的ModelState,对指数作用.
使用动作过滤器(PRG模式)(就像使用属性一样简单)
在这里和这里提到.
请注意,tvanfosson的解决方案并不总是有效,但在大多数情况下应该没问题.
该特定解决方案的问题在于,如果您已经拥有任何ViewData或ModelState,则最终会使用先前请求的状态覆盖所有ViewData或ModelState.例如,新请求可能会有一些与传递给操作的无效参数相关的模型状态错误,但这些错误最终会被覆盖,因为它们会被覆盖.
另一种可能无法按预期工作的情况是,如果您有一个Action Filter,它初始化了一些ViewData或ModelState错误.同样,它们将被该代码覆盖.
我们正在研究ASP.NET MVC的一些解决方案,它们可以让您更轻松地合并两个请求的状态,敬请期待.
谢谢,艾伦
如果这对任何使用PRB的@bob推荐解决方案的人都有用:
见第13项 - > 链接.
在执行操作时,我在VeiwBag中传递了另外一个消息,即在控制器操作中从TempData手动编写和检查/加载View RedirectToAction("Action")
.为了简化(并使其可维护),我稍微扩展了这种方法来检查和存储/加载其他数据.我的行动方法看起来像:
[AcceptVerbs(HttpVerbs.Post)] [ExportModelStateToTempData] public ActionResult ChangePassword(ProfileViewModel pVM) { bool result = MyChangePasswordCode(pVM.ChangePasswordViewModel); if (result) { ViewBag.Message = "Password change success"; else { ModelState.AddModelError("ChangePassword", "Some password error"); } return RedirectToAction("Index"); }
我的索引动作:
[ImportModelStateFromTempData] public ActionResult Index() { ProfileViewModel pVM = new ProfileViewModel { //setup } return View(pVM); }
动作过滤器中的代码:
// Following best practices as listed here for storing / restoring model data: // http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg public abstract class ModelStateTempDataTransfer : ActionFilterAttribute { protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName; }
:
public class ExportModelStateToTempData : ModelStateTempDataTransfer { public override void OnActionExecuted(ActionExecutedContext filterContext) { //Only export when ModelState is not valid if (!filterContext.Controller.ViewData.ModelState.IsValid) { //Export if we are redirecting if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) { filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState; } } // Added to pull message from ViewBag if (!string.IsNullOrEmpty(filterContext.Controller.ViewBag.Message)) { filterContext.Controller.TempData["Message"] = filterContext.Controller.ViewBag.Message; } base.OnActionExecuted(filterContext); } }
:
public class ImportModelStateFromTempData : ModelStateTempDataTransfer { public override void OnActionExecuted(ActionExecutedContext filterContext) { ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary; if (modelState != null) { //Only Import if we are viewing if (filterContext.Result is ViewResult) { filterContext.Controller.ViewData.ModelState.Merge(modelState); } else { //Otherwise remove it. filterContext.Controller.TempData.Remove(Key); } } // Restore Viewbag message if (!string.IsNullOrEmpty((string)filterContext.Controller.TempData["Message"])) { filterContext.Controller.ViewBag.Message = filterContext.Controller.TempData["Message"]; } base.OnActionExecuted(filterContext); } }
我意识到我的更改是对@Bob提供的代码@链接已经完成的ModelState的一个非常明显的扩展 - 但是在我想到以这种方式处理它之前我不得不偶然发现这个线程.