2011-05-07 51 views
3

我的大多數操作方法在成功時返回PartialView,在失敗時返回RedirectToAction結果。爲此,我想將模型狀態錯誤複製到TempData中,以便將它們顯示給用戶。我在這裏閱讀了幾個關於SO和一些外部鏈接的問題,但他們都沒有爲我工作......我正在用來自MvcContrib的ModelStateToTempData屬性裝飾ActionMethod,然後在視圖中顯示如下:(這只是一個原型)將ModelState錯誤複製到TempData並顯示它們在視圖中

 @if (TempData.Count > 0) 
     { 
      foreach (var obj in TempData) 
      { 
       var errors = ((ModelStateDictionary)obj.Value).Values; 
       foreach (var error in errors) 
       { 
       <div style="position:absolute; background:Black; color:White; top:250px; left:550px;"> 
        <span style="margin-bottom:5px; display:block; height:25px;">@error.Value</span> 
       </div> 
       } 
      } 
     } 

而不是顯示錯誤本身,我不斷收到System.Web.Mvc.ValueProviderResult。我知道這是完全錯誤的,最終我想將模型狀態錯誤過濾到TempData中的字典中,但現在我只想在視圖中顯示錯誤字符串。

P.S:我試過不用MvcContrib屬性來手工完成,而且我得到了相同的結果。但我更喜歡使用自己的代碼,這樣我就可以對整個問題有更多的控制權。

有什麼建議嗎?

回答

3

好的嘗試一百萬的事情後,我發現自己的答案... :)

if (TempData["ModelErrors"] == null) 
    TempData.Add("ModelErrors", new List<string>()); 
foreach (var obj in ModelState.Values) 
{ 
    foreach (var error in obj.Errors) 
    { 
     if(!string.IsNullOrEmpty(error.ErrorMessage)) 
      ((List<string>)TempData["ModelErrors"]).Add(error.ErrorMessage); 
    } 
} 
return RedirectToAction("Index", "Home"); 

並在視圖:

<div id="validationMessages"> 
     @{ 
      var errors = (List<string>)TempData["ModelErrors"]; 
     } 
     @if (errors != null && errors.Count() > 0) 
     { 
      <div style="position:absolute; background:Black; color:White; top:250px; left:550px;"> 
       @foreach (var error in errors) 
       { 
        <span style="margin-bottom:5px; display:block; height:25px;">@error</span> 
       } 
      </div> 
     } 
    </div> 

UPDATE:

這在ActionFilter中:

public class CopyModelStateErrorsToTempData : ActionFilterAttribute 
{ 
    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)) 
      { 
       if (filterContext.Controller.TempData["ModelErrors"] == null) 
        filterContext.Controller.TempData.Add("ModelErrors", new List<string>()); 
       foreach (var obj in filterContext.Controller.ViewData.ModelState.Values) 
       { 
        foreach (var error in obj.Errors) 
        { 
         if (!string.IsNullOrEmpty(error.ErrorMessage)) 
          ((List<string>)filterContext.Controller.TempData["ModelErrors"]).Add(error.ErrorMessage); 
        } 
       } 
      } 
     } 

     base.OnActionExecuted(filterContext); 
    } 
} 
1

我開始走下這條路,然後閱讀你的答案。我將它們結合在一起爲以下文件:

TempDataDictionaryExtensions.cs

我創建擴展方法做就TempData的骯髒的工作,因爲我覺得它沒有在行動過濾器本身屬於。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Mvc; 

namespace Project.Web.UI.Domain 
{ 
    public static class TempDataDictionaryExtensions 
    { 
     private const string _ModelStateErrorsKey = "ModelStateErrors"; 

     public static IEnumerable<string> GetModelErrors(this TempDataDictionary instance) 
     { 
      return TempDataDictionaryExtensions.GetErrorsFromTempData(instance); 
     } 

     public static void AddModelError(this TempDataDictionary instance, string error) 
     { 
      TempDataDictionaryExtensions.AddModelErrors(instance, new List<string>() { error }); 
     } 

     public static void AddModelErrors(this TempDataDictionary instance, IEnumerable<string> errors) 
     { 
      TempDataDictionaryExtensions.AddErrorsToTempData(instance, errors); 
     } 

     private static List<string> GetErrorsFromTempData(TempDataDictionary instance) 
     { 
      object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey); 
      if (tempObject == null) 
      { 
       return new List<String>(); 
      } 
      List<string> tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>; 
      if (tempErrors == null) 
      { 
       return new List<String>(); 
      } 
      return tempErrors; 
     } 

     private static void AddErrorsToTempData(TempDataDictionary instance, IEnumerable<string> errors) 
     { 
      List<string> tempErrors; 

      object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey); 
      if (tempObject == null) 
      { 
       tempErrors = new List<String>(); 
      } 
      else 
      { 
       tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>; 
       if (tempErrors == null) 
       { 
        tempErrors = new List<String>(); 
       } 
      } 

      tempErrors.AddRange(errors); 

      instance[TempDataDictionaryExtensions._ModelStateErrorsKey] = tempErrors; 
     } 
    } 
} 

TempDataModelStateAttribute.cs

我的原創,複製出來的TempData錯誤回到ModelState通過OnResultExecuting執行的ActionResult之前。這是將它們複製到TempData並退出的組合。

using System.Collections.Generic; 
using System.Linq; 
using System.Web.Mvc; 

namespace Project.Web.UI.Domain 
{ 
    public class TempDataModelStateAttribute : ActionFilterAttribute 
    { 
     public override void OnResultExecuting(ResultExecutingContext filterContext) 
     { 
      IEnumerable<string> modelErrors = ((Controller)filterContext.Controller).TempData.GetModelErrors(); 
      if (modelErrors != null 
       && modelErrors.Count() > 0) 
      { 
       modelErrors.ToList() 
          .ForEach(x => ((Controller)filterContext.Controller).ModelState.AddModelError("GenericError", x)); 
      } 
      base.OnResultExecuting(filterContext); 
     } 

     public override void OnActionExecuted(ActionExecutedContext filterContext) 
     { 
      if (!filterContext.Controller.ViewData.ModelState.IsValid) 
      { 
       if (filterContext.Result is RedirectResult 
        || filterContext.Result is RedirectToRouteResult) 
       { 
        List<string> errors = new List<string>(); 
        foreach (var obj in filterContext.Controller.ViewData.ModelState.Values) 
        { 
         foreach (var error in obj.Errors) 
         { 
          errors.Add(error.ErrorMessage); 
         } 
        } 
        ((Controller)filterContext.Controller).TempData.AddModelErrors(errors); 
       } 
      } 

      base.OnActionExecuted(filterContext); 
     } 
    } 
} 
相關問題