-1

I have a Concurrency check at my data layer that will threw a custom exception (ConcurrencyValidationException) when the condition occurs. I'm trying to display this as a friendly error message in my ValidationSummary object, like the other validation errors.

The problem is that I lose that invalid state when using RedirectToAction. I've tried passing through the ViewData state as TempData but it doesn't seem to work.

Here are the two actions in my controller:

    public ActionResult Details(int? id)
    {
        StudentRepository studentRepository = StudentRepository();
        Student student = new Student();
        ActionResult result;

        if (TempData["Student"] != null)
        {
            student = TempData["Student"] as Student;
            TempData["Student"] = student; // needed to survive a browser refresh
        }            
        else if (id != null)
            student = studentRepository.GetById((int)id);

        if (student != null)
            result = View(student);
        else
            result = RedirectToAction("Index");

        return result;
    }

    [HttpPut]
    public ActionResult Upsert(Student model)
    {
        StudentRepository studentRepository = StudentRepository();
        int studentId= 0;

        try
        {
            if (model.IsValid() && model.Id == null)
            {
                studentId = studentRepository.Add(model);
            }
            else if (model.IsValid() && model.Id != null)
            {
                studentRepository.Update(model);
                studentId = (int)model.Id;
            }
        }
        catch (ConcurrencyValidationException exception)
        {
            ModelState.AddModelError("ConcurrencyUniqueID", exception);
            TempData["Student"] = model;

            if (model.Id != null)
                studentId = (int)model.Id;
        }

        return RedirectToAction("Details", new { id = studentId });
    }

When the Details View is loaded, no error is displayed, the error is lost. BTW, the reason I'm using RedirectToAction and not displaying calling View in Upsert() is that I don't want the URL to be /Upsert, I want it to be /Details/[id].

Updated: I can see that the student is properly preserved, but the added model validation isn't.

Josh
  • 8,219
  • 13
  • 76
  • 123
  • possible duplicate of [ASP.NET MVC - How to Preserve ModelState Errors Across RedirectToAction?](http://stackoverflow.com/questions/4642845/asp-net-mvc-how-to-preserve-modelstate-errors-across-redirecttoaction) – GSerg Jan 30 '15 at 20:57
  • I updated it to the example in that post the error still doesn't appear on the page. I'll update my example in this question so it is inline with that example in case I'm missing something. – Josh Jan 30 '15 at 21:59
  • @GSerg, I better luck with the second (unaccepted question). So I need to figure out how to get it to display in Validation Summary, currently I have to tie it to a property that is displayed on the form. – Josh Jan 30 '15 at 22:30

1 Answers1

1

TempData only works for one access, and deletes its contents afterwards. So this code is your major problem:

if (TempData["Student"] != null)  // data is accessed and deleted
{
    // oopss.. nothing in TempData now
    student = TempData["Student"] as Student;
    TempData["Student"] = student; // needed to survive a browser refresh
} 

So you need to get the TempData first and assign it to something, then check that variable:

var student = TempData["Student"] as Student;
if (student != null)  // we're ok now
{
    //....
}
Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • Interesting observation, I ended up going with the second answer that moves the logic for populating TempData it to an attribute. One thing that I'm not getting, it seems that even if you populate Student based on ID after you get it from TempData, it still works. So appears I don't need my if/else. I'm not sure why populating Student the second time doesn't overwrite what was set by grabbing it from TempData. – Josh Jan 30 '15 at 22:35