2011-10-29 34 views

回答

7

通常情況下,您只會在成功後(無模型驗證錯誤)後重定向,否則您會返回包含驗證錯誤消息的頁面。

重定向PRG圖案防止雙重張貼,所以沒有傷害發回同一頁面(+錯誤消息),因爲後沒有成功,也不會是,除非有新的變化,使驗證通過。

編輯

看起來你正在尋找通過ModelState下一個(轉移)請求。這可以通過使用TempData來存儲ModelState直到下一個請求。 FYI,TempData使用Session。

這可以用ActionFilters來實現。例如可以在MvcContrib項目代碼中找到:ModelStateToTempDataAttribute

這也與在「最佳做法」的文章等提示一起提到的weblogs.asp.net(看來作者已移動博客,但我找不到文章在新的博客上)。從文章:

此模式的問題之一是當驗證失敗或任何 異常發生時,您必須將ModelState複製到TempData中。如果您 正在做手工,請停止它,你可以用操作過濾器自動執行此 ,如下所示:

控制器

[AcceptVerbs(HttpVerbs.Get), OutputCache(CacheProfile = "Dashboard"), StoryListFilter, ImportModelStateFromTempData] 
public ActionResult Dashboard(string userName, StoryListTab tab, OrderBy orderBy, int? page) 
{ 
    //Other Codes 
    return View(); 
} 

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData] 
public ActionResult Submit(string userName, string url) 
{ 
    if (ValidateSubmit(url)) 
    { 
     try 
     { 
      _storyService.Submit(userName, url); 
     } 
     catch (Exception e) 
     { 
      ModelState.AddModelError(ModelStateException, e); 
     } 
    } 

    return Redirect(Url.Dashboard()); 
} 

措施篩選

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; 
      } 
     } 

     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); 
      } 
     } 

     base.OnActionExecuted(filterContext); 
    } 
} 
+2

這是不正確的。有很多傷害......所有POST都必須跟隨重定向。 (1)這是從瀏覽器歷史記錄中刪除POST請求的唯一方法(2)否則,用戶按下BACK或REFRESH將會令人困惑和惱人的「重新發送」確認。(3)選擇「重新發送」的用戶無法知道行動的最終結果可能是!這已經是超過15年的專業品質網絡應用程序的標誌。 (儘管在ASP或ASP.NET Web應用程序中不常見)此外,即使是嘗試不可重複的狀態更改的GET也應重定向。 – Jack

+0

我的觀點是,如果模型驗證失敗,服務器狀態不會更改,因此即使重新提交相同的POST請求,服務器狀態仍不會更改。但是,如果您強烈地感到抑制這種特殊情況下令人討厭的重新發送確認(未發生服務器狀態更改的POST失敗),爲什麼不直接重定向?您可能需要一個會話(例如TempData)來將至少驗證錯誤消息繼續發送到重定向的請求,並通知用戶POST失敗的原因。但是,再次,在GET請求中顯示會話狀態不是很RESTful ... – marapet

+0

「服務器狀態沒有改變」//這個請求不是,但你假設下一次它不會被改變/ /你不能做出這樣的假設//這也只是問題的一部分//重複捕獲必須在服務器端完成//「簡單地重定向」如何在下一個請求中訪問ModelState? – Jack

0

什麼你的意思是「強制」重定向?通常我們在控制器中使用try/catch,如果嘗試成功,您可以重定向到View(如果需要)或者也可以返回任何部分視圖或任何您需要的東西。捕獲通常會重新顯示原始頁面並顯示錯誤消息,因爲發佈請求不成功。

希望我沒有誤解你:)

+0

專業網絡應用程序的「強制性」 - 與fiddler一起檢查 - 觀察Google或IBM或PayPal或EBay如何做到這一點...... ASP或ASP.NET網絡應用程序很少正確實現此功能,因爲Microsoft從未在其中顯示該技術例子(他們不想混淆人) – Jack