【问题标题】:Copy ModelState Errors to TempData & Display them In the view将 ModelState 错误复制到 TempData 并在视图中显示它们
【发布时间】:2011-05-07 08:27:47
【问题描述】:

我的大多数操作方法在成功时返回 PartialViews,在失败时返回 RedirectToAction 结果。为此,我想将模型状态错误复制到 TempData 中,以便将它们显示给用户。我在这里阅读了关于 SO 和一些外部链接的几个问题,但没有一个对我有用......我正在用 MvcContrib 的 ModelStateToTempData 属性装饰 ActionMethod,然后在视图中显示如下:(这只是原型)

        @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 属性的情况下手动执行此操作,并且得到了相同的结果。但我更喜欢使用自己的代码,这样我可以更好地控制整个问题。

有什么建议吗?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 modelstate tempdata


    【解决方案1】:

    好吧,在尝试了一百万件事之后,我自己找到了答案……:)

    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>
    

    更新:

    这是在 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);
        }
    }
    

    【讨论】:

      【解决方案2】:

      我开始走这条路,然后读了你的答案。我将它们组合成以下文件:

      TempDataDictionaryExtensions.cs

      我创建了扩展方法来处理 TempData 的脏活,因为我觉得它不属于 Action Filter 本身。

      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

      在通过OnResultExecuting 执行ActionResult 之前,我的原件将错误从TempData 复制回ModelState。这是将它们复制到 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);
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        【讨论】:

        • 什么概念?能不能说的具体点?
        • 看起来您正在尝试实现名为 PRG(Post/Redirect/Get)的概念/模式。以下链接我提供或检查 CodePlex 上的 MvcContrib 项目应该会给你一个很好的解释 Pattern 本身加上实现示例
        猜你喜欢
        • 1970-01-01
        • 2020-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-14
        • 2018-04-05
        相关资源
        最近更新 更多