[英]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.