Skip to content

Instantly share code, notes, and snippets.

@danielgreen
Created May 29, 2013 15:42
Show Gist options
  • Save danielgreen/5671294 to your computer and use it in GitHub Desktop.
Save danielgreen/5671294 to your computer and use it in GitHub Desktop.
If an MVC action has detected validation errors in the model, the errors are held in ModelState. If the action returns a view containing the model, and the jQuery Validate plugin is present on the page, the validation errors are displayed. If the MVC action performs a redirect, however, the model validation errors are lost. Use the PreserveModel…
using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Mvc;
/* Based on the ModelStateToTempDataAttribute class from MVCContrib */
namespace Web.Filters
{
/// <summary>
/// When a RedirectResult or RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
/// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
/// </summary>
public class PreserveModelStateOnRedirectAttribute : ActionFilterAttribute
{
public const string TempDataKey = "ModelState";
/// <summary>
/// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
/// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var controller = filterContext.Controller;
var modelState = controller.ViewData.ModelState;
var tempData = controller.TempData;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var actionName = filterContext.ActionDescriptor.ActionName;
var result = filterContext.Result;
if (result is ViewResultBase)
{
//If there are failures in tempdata, copy them to the modelstate
CopyTempDataToModelState(modelState, tempData, controllerName, actionName);
return;
}
//If we're redirecting and there are errors, put them in tempdata instead (so they can later be copied back to modelstate)
if ((result is RedirectToRouteResult || result is RedirectResult) && !modelState.IsValid)
{
CopyModelStateToTempData(modelState, tempData, controllerName, actionName);
}
}
private void CopyTempDataToModelState(ModelStateDictionary modelState, TempDataDictionary tempData, string controllerName, string actionName)
{
string key = GetKey(controllerName, actionName);
if (!tempData.ContainsKey(key)) return;
var fromTempData = tempData[key] as ModelStateDictionary;
if(fromTempData == null) return; // No ModelStateDictionary found against the key, so nothing to merge
modelState.Merge(fromTempData);
}
private static void CopyModelStateToTempData(ModelStateDictionary modelState, TempDataDictionary tempData, string controllerName, string actionName)
{
string key = GetKey(controllerName, actionName);
tempData[key] = modelState;
}
private static string GetKey(string controllerName, string actionName)
{
return controllerName + actionName + TempDataKey;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment