Copy ModelState Errors to TempData & Display them In the view

假如想象 提交于 2019-12-03 17:31:15

Ok After trying a million things, I found the answer myself... :)

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

And in the view:

    <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:

Here it is inside an 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);
    }
}

I started going down this road, and then read your answer. I combined them into the following files:

TempDataDictionaryExtensions.cs

I created extension methods to do the dirty work on the TempData, because I felt it didn't belong in the Action Filter itself.

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

My original, copied the errors out of TempData back into ModelState prior to the ActionResult executing via OnResultExecuting. This is a combination of copying them into TempData and back out.

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);
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!