![](/img/trans.png)
[英]How do I maintain ModelState errors when using RedirectToAction?
[英]How can I maintain ModelState with RedirectToAction?
如果我的ModelState
存在错误,如何在不丢失我的ModelState
信息的情况下返回不同操作的结果或将用户移动到不同的操作?
场景是; Delete
操作接受来自我的Index
操作/视图呈现的 DELETE 表单的 POST。 如果Delete
有错误,我想将用户移回Index
Action/View 并显示由Delete
操作存储在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");
}
将您的视图数据存储在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
传输到 Index 操作可能是最简单的。
请注意,tvanfosson 的解决方案并不总是有效,但在大多数情况下应该没问题。
该特定解决方案的问题在于,如果您已经拥有任何 ViewData 或 ModelState,您最终会用先前请求的状态覆盖它们。 例如,新请求可能有一些与传递给操作的无效参数相关的模型状态错误,但这些错误最终会被隐藏,因为它们被覆盖了。
它可能无法按预期工作的另一种情况是,如果您有一个 Action Filter 初始化了一些 ViewData 或 ModelState 错误。 同样,它们将被该代码覆盖。
我们正在研究 ASP.NET MVC 的一些解决方案,它们可以让您更轻松地合并来自两个请求的状态,因此请继续关注。
谢谢,伊隆
如果这对我使用 PRG 使用 @bob 推荐的解决方案的任何人有用:
参见第 13 项 -> 链接。
在执行RedirectToAction("Action")
时,我在控制器操作中从 TempData 手动写入和检查/加载了消息在 VeiwBag 中传递到视图的附加问题。 为了简化(并使其可维护),我稍微扩展了这种方法来检查和存储/加载其他数据。 我的操作方法看起来像:
[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);
}
}
我意识到我在这里的更改是对 ModelState 已经通过代码@@bob 提供的链接所做的事情的一个非常明显的扩展 - 但在我什至想到以这种方式处理它之前,我不得不偶然发现这个线程。
请不要因为这个答案而质疑我。 这是一个合理的建议。
使用 AJAX
用于管理 ModelState 的代码很复杂,并且(可能?)表明您的代码中存在其他问题。
你可以很容易地推出你自己的 AJAX javascript 代码。 这是我使用的脚本:
https://gist.github.com/jesslilly/5f646ef29367ad2b0228e1fa76d6bdcc#file-ajaxform
(function ($) {
$(function () {
// For forms marked with data-ajax="#container",
// on submit,
// post the form data via AJAX
// and if #container is specified, replace the #container with the response.
var postAjaxForm = function (event) {
event.preventDefault(); // Prevent the actual submit of the form.
var $this = $(this);
var containerId = $this.attr("data-ajax");
var $container = $(containerId);
var url = $this.attr('action');
console.log("Post ajax form to " + url + " and replace html in " + containerId);
$.ajax({
type: "POST",
url: url,
data: $this.serialize()
})
.done(function (result) {
if ($container) {
$container.html(result);
// re-apply this event since it would have been lost by the form getting recreated above.
var $newForm = $container.find("[data-ajax]");
$newForm.submit(postAjaxForm);
$newForm.trigger("data-ajax-done");
}
})
.fail(function (error) {
alert(error);
});
};
$("[data-ajax]").submit(postAjaxForm);
});
})(jQuery);
也许试试
return View("Index");
代替
return Index();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.