Kolya_Net Kolya_Net - 3 months ago 126
C# Question

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

I have a method to remove the object. Removal does not own view, and is a "Delete" button in the "EditReport". Upon successful removal of a redirect on "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 ModelState between methods. I took from here: http://stackoverflow.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"]);
}
}
}


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

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

Answer

Thanks to answer, I realized that the need to create your own code ASP.NET Core 1.0 (Full .NET Framework)

public class SetTempDataModelStateAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);

            var controller = filterContext.Controller as Controller;
            if (controller != null)
            {
                var modelState = controller.ViewData.ModelState;
                if (modelState != null)
                {
                    var dictionary = new KeyValuePair<string, ModelStateEntry>[modelState.Count];
                    modelState.CopyTo(dictionary, 0);
                    var listError = dictionary.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 version of the code ASP.NET Core 1.0 (Full .NET Framework)

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.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();
        }
    }