我的大多数操作方法都会在成功时返回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属性的情况下手动完成,我得到了相同的结果。但我更喜欢使用我自己的代码,这样我就可以更好地控制整个问题。
有什么建议吗?
答案 0 :(得分: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>
<强>更新
这里面是一个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 :(得分:1)
我开始走这条路,然后读你的答案。我将它们合并到以下文件中:
<强> 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
我的原创,在通过TempData
执行ActionResult之前,将错误从ModelState
复制回OnResultExecuting
。这是将它们复制到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);
}
}
}
答案 2 :(得分:0)