How to continue using ModelState with RedirectToAction in ASP.NET MVC 6?

I have a way to delete an object. Deletion does not have its own representation and is the "Delete" button in "EditReport". After successfully removing the redirect to "Report".

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

In ASP.NET MVC 5, I use the following attributes to save a ModelState between methods. I took from here: stack overflow

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

But in ASP.NET MVC 6 RC 1 (ASP.NET Core 1.0) this code does not work.

The error in filterContext.Controller does not contain definitions for TempData and ViewData.

+6
source share
2 answers

Thanks to the answer , I realized that I needed to create my own ASP.NET Core 1.0 code (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); } } } } 

Asynchronous ASP.NET Core 1.0 Code Version (Full .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(); } } 
+4
source

A fix for compiling the code is below, but ASP.NET Core does not seem to support model state serialization (due to ModelStateEntry containing exceptions that can never be serialized).

Therefore, you cannot serialize the model state in TempData . And as explained in this issue, GitHub does not seem to plan to change this behavior.


The Controller property in ActionExecutingContext is of type object . This is because the controllers in the ASP.NET kernel do not need to inherit from the Controller , so there is no common base type for them.

To access the TempData property, you must first transfer it to the Controller . Your attributes may look like this:

 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"]); } } } 
+3
source

All Articles