如何在 ASP.NET MVC 6 中继续使用 ModelState 和 RedirectToAction?
Posted
技术标签:
【中文标题】如何在 ASP.NET MVC 6 中继续使用 ModelState 和 RedirectToAction?【英文标题】:How to keep using ModelState with RedirectToAction in ASP.NET MVC 6? 【发布时间】:2016-06-29 03:22:22 【问题描述】:我有一个删除对象的方法。删除不属于自己的视图,是“EditReport”中的“Delete”按钮。成功移除“报告”上的重定向后。
[HttpPost]
[Route("reportId:int")]
[ValidateAntiForgeryToken]
public IActionResult DeleteReport(int reportId)
var success = _reportService.DeleteReportControl(reportId);
if (success == false)
ModelState.AddModelError("Error", "Messages");
return RedirectToAction("EditReport");
ModelState.AddModelError("OK", "Messages");
return RedirectToAction("Report");
在 ASP.NET MVC 5 中,我使用以下属性在方法之间保存 ModelState。我从这里拿的:https://***.com/a/12024227/3878213
public class SetTempDataModelStateAttribute : ActionFilterAttribute
public override void OnActionExecuted(ActionExecutedContext filterContext)
base.OnActionExecuted(filterContext);
filterContext.Controller.TempData["ModelState"] =
filterContext.Controller.ViewData.ModelState;
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
base.OnActionExecuting(filterContext);
if (filterContext.Controller.TempData.ContainsKey("ModelState"))
filterContext.Controller.ViewData.ModelState.Merge(
(ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
但在 ASP.NET MVC 6 RC 1 (ASP.NET Core 1.0) 中,此代码不起作用。
filterContext.Controller 中的错误不包含 TempData 和 ViewData 的定义。
【问题讨论】:
【参考方案1】:感谢answer,我意识到需要创建自己的代码 ASP.NET Core 1.0 (Full .NET Framework 4.6.2)
public class SetTempDataModelStateAttribute : ActionFilterAttribute
public override void OnActionExecuted(ActionExecutedContext filterContext)
base.OnActionExecuted(filterContext);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
controller.TempData["ModelState"] = JsonConvert.SerializeObject(listError);
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
base.OnActionExecuting(filterContext);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
if (tempData.Contains("ModelState"))
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString);
var modelState = new ModelStateDictionary();
foreach (var item in listError)
modelState.AddModelError(item.Key, item.Value ?? "");
controller.ViewData.ModelState.Merge(modelState);
异步版代码ASP.NET Core 1.0(完整的.NET Framework 4.6.2)
public class SetTempDataModelStateAttribute : ActionFilterAttribute
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
var listErrorJson = await Task.Run(() => JsonConvert.SerializeObject(listError));
controller.TempData["ModelState"] = listErrorJson;
await next();
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
if (tempData.Contains("ModelState"))
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = await Task.Run(() =>
JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString));
var modelState = new ModelStateDictionary();
foreach (var item in listError)
modelState.AddModelError(item.Key, item.Value ?? "");
controller.ViewData.ModelState.Merge(modelState);
await next();
【讨论】:
应该有一个检查来防止非错误出现在SetTempDataModelStateAttribute
行var listError = modelState.ToDictionary(m => m.Key, m => m.Value.Errors
应该是modelState.Where(x => x.Value.Errors.Any()).ToDictionary(m...
在这里使用await next();
是不正确的,因为它会导致该方法被多次命中。【参考方案2】:
使代码编译的修复方法如下,但似乎 ASP.NET Core 不支持序列化模型状态(由于 ModelStateEntry
包含永远无法序列化的异常)。
因此,您无法序列化 TempData
中的模型状态。正如this GitHub issue 中所述,似乎没有计划改变这种行为。
ActionExecutingContext
中的Controller
属性属于object
类型。这是因为 ASP.NET Core 中的控制器不需要继承自 Controller
,因此它们没有通用的基类型。
要访问TempData
属性,您必须先将其转换为Controller
。您的属性可能如下所示:
public class SetTempDataModelStateAttribute : ActionFilterAttribute
public override void OnActionExecuted(ActionExecutedContext filterContext)
base.OnActionExecuted(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null)
controller.TempData["ModelState"] = controller.ViewData.ModelState;
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
base.OnActionExecuting(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null & controller.TempData.ContainsKey("ModelState"))
controller.ViewData.ModelState.Merge(
(ModelStateDictionary)controller.TempData["ModelState"]);
【讨论】:
添加到 Sessions 项目。虽然我无法解决错误的问题:InvalidOperationException: The 'Microsoft.AspNet.Mvc.ViewFeatures.SessionStateTempDataProvider' cannot serialize an object of type 'Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary' to session state
.
似乎 ASP.NET Core 不支持序列化模型状态,并且没有计划改变它。我已经更新了我的答案以反映这一点。
正确地将 ModelState 转换为字符串 (json) 并存储在 TempData 中?
您不能序列化模型状态,包括将其序列化为 JSON。如果您仍想这样做,则必须手动对其进行序列化。
感谢您的信息。这是我的解决方案***.com/a/35987804/3878213以上是关于如何在 ASP.NET MVC 6 中继续使用 ModelState 和 RedirectToAction?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Asp.Net 5 (MVC 6) 中使用实体框架 6.x
是否可以在 Visual Studio 2013 中使用 asp.net mvc 6?
如何继续等待 API 请求响应值完成 ASP .Net Core MVC
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)