Reputation: 11725
My problem with the following is how do I send the ModelStateErrors to the action Employee, when I go through the catch part in DeleteEmployee
public ActionResult Employee(int ID, string Name)
{
EmployeeListModel model = new EmployeeListModel (ID, projectName);
return View(model);
}
public ActionResult DeleteEmployee(Employee emp)
{
try
{
emp.Delete();
return RedirectToAction("Employee", new { ID = emp.ID, Name = emp.Name });
}
catch (Exception e)
{
EmployeeListModel model = new EmployeeListModel (emp.ID, emp.Name);
ModelState.AddModelError("Error", e.Message);
return RedirectToAction("Employee", model);
}
}
With return View("Employee", model); I a still not able to send the ID and Name as parameter.
Upvotes: 2
Views: 5840
Reputation: 42246
Use TempData
to persist the ModelState
across multiple controller actions.
MvcContrib has an action filter that does this. Jeremy Skinner wrote the code and a blog post about it at http://www.jeremyskinner.co.uk/2008/10/18/storing-modelstate-in-tempdata-with-aspnet-mvc/. The link there for the source is broken, so I posted the code below.
/// <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>
public class ModelStateToTempDataAttribute : ActionFilterAttribute
{
public const string TempDataKey = "__MvcContrib_ValidationFailures__";
/// <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 modelState = filterContext.Controller.ViewData.ModelState;
var controller = filterContext.Controller;
if(filterContext.Result is ViewResultBase)
{
//If there are failures in tempdata, copy them to the modelstate
CopyTempDataToModelState(controller.ViewData.ModelState, controller.TempData);
return;
}
//If we're redirecting and there are errors, put them in tempdata instead (so they can later be copied back to modelstate)
if((filterContext.Result is RedirectToRouteResult || filterContext.Result is RedirectResult) && !modelState.IsValid)
{
CopyModelStateToTempData(controller.ViewData.ModelState, controller.TempData);
}
}
private void CopyTempDataToModelState(ModelStateDictionary modelState, TempDataDictionary tempData)
{
if(!tempData.ContainsKey(TempDataKey)) return;
var fromTempData = tempData[TempDataKey] as ModelStateDictionary;
if(fromTempData == null) return;
foreach(var pair in fromTempData)
{
if (modelState.ContainsKey(pair.Key))
{
modelState[pair.Key].Value = pair.Value.Value;
foreach(var error in pair.Value.Errors)
{
modelState[pair.Key].Errors.Add(error);
}
}
else
{
modelState.Add(pair.Key, pair.Value);
}
}
}
private static void CopyModelStateToTempData(ModelStateDictionary modelState, TempDataDictionary tempData)
{
tempData[TempDataKey] = modelState;
}
}
Upvotes: 5
Reputation: 3061
Try below code //as a best practise always use Viewmodel e.g. employeeViewMode and strongly type your view to viewmodel public class EmployeviewModel { public int id; public string name; public string errormessage; } public ActionResult Employee(int ID) { EmployeeListModel model = new EmployeeListModel(ID, projectName); EmployeviewModel vm = new EmployeviewModel(); vm.id = model.id; vm.name = model.name; if (TempData.Keys.Count() > 0) { vm.errormessage = TempData["errormessage"]; } return View(vm); }
public ActionResult DeleteEmployee(Employee emp)
{
try
{
emp.Delete();
return RedirectToAction("Employee", new { ID = emp.ID, Name = emp.Name });
}
catch (Exception e)
{
//use TempData to store error message
TempData["ErrorMessage"] = e.message;
return RedirectToAction("Employee", emp.ID);
}
}
Upvotes: 1
Reputation: 1947
Store the ModelState in TempData:
TempData["ModelState"] = ModelState;
Then merge the ModelState using an action filter for example:
protected override void OnActionExecuted(ActionExecutedContext context)
{
filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
}
Hope this helps.
Upvotes: 1
Reputation: 4931
The values for ID and Name are being sent wrapped up in the EmployeeListModel you pass to the "View" ActionResult:
Note, @Brian is correct in that you'll need to use the "View" ActionResult rather than "RedirectToAction" ActionResult otherwise the modelstate errors would be lost. The alternative is to store your modelstate in TempData which is really a special wrapper around the session object. You would need to use something like the "RedirectToAction" ActionResult if you need to ensure your url's are updated properly ...
Upvotes: 1
Reputation: 50728
From the view, the model state dictionary is a part of the ViewDataDictionary, so try accessing it through viewdata, at least in MVC 3 (believe that way in older versions as well). You don't need to pass it through the model, but instead access it this way.
However, i don't know if model state errors are retained if you do a redirect; you may want to return the response directly instead:
return View("Employee", model);
HTH.
Upvotes: 1