views:

1365

answers:

4

I have some code that saves a ticket in our system. If there is an error it does a RedirectToAction. The problem is that I don't seem to have my errors in the new action. How can I fix this?

 ModelState.AddModelError("_FORM", "Unable to save ticket");
 ModelState.AddModelError("_FORM", "Phone number was invalid.");
 ModelState.AddModelError("_FORM", "Lane number is required.");
 return RedirectToAction("CreateStep", "Ticket");

I know some have suggested using TempData, but how would I get each error out of the ModelState?

Thanks.

A: 

I believe you lose your model state when you do a redirect. Maybe you could rewrite your logic to something like:

public ActionResult Save()
{
  // your code...
  if(saveSucceeded)
  {
    return View("Saved");
  }
  else
  {
    return View("Create");
  }
}

And the usual way to get your error message:

<%= Html.ValidationMessage("property_name") %>
Thomas Eyde
+2  A: 

Use the TempData[] Collection

The tempdata is stored from one request to the next, then its gone.

AndreasN
+2  A: 

this blog post describes how you could implement the PRG-Pattern in MVC http://blog.simonlovely.com/archive/2008/11/26/post-redirect-get-pattern-in-mvc.aspx

hth

marc.d
+7  A: 

The PRG pattern is ok, but I did this:

Base controller:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    if (TempData["ModelState"] != null && !ModelState.Equals(TempData["ModelState"]))
     ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);

    base.OnActionExecuted(filterContext);
}

Action (I'm using xVal):

try
{
    user.Login();
    AuthenticationManager.SignIn(user);
}
catch (RulesException rex)
{
    // on bad login
    rex.AddModelStateErrors(ModelState, "user");
    TempData["ModelState"] = ModelState;
    return Redirect(Request.UrlReferrer.ToString());
}

The action throws an exception, adds the ModelState to TempData and redirects back to the referrer. Since the action is caught, OnActionExecuted is still executed, but the first time around the ModelState is the same as TempData["ModelState"], so you don't want to merge with yourself. When the redirect action is executed, OnActionExecuted fires again. This time, if there's anything in TempData["ModelState"], it merges with this action's ModelState.

You could expand it to multiple models by using TempData["ModelState.user"] = ModelState and then merging every TempData object that starts with ModelState.

I like this... Seems a handy way to make this work. Thank you!
Andrew Flanagan
@Bill. I love it. I have extended your code for my usage. Instead of your RulesException.AddModelStateErrors(), I did it the other way, I extended ModelState to have two extension methods; UpdateModel and RestoreModel. +1 for you.
Syd