RedirectToAction after validation errors

If I have the usual Edit actions, one for GET to retrieve the object by its identifier and display it in the edit form. The following is for POST to accept values ​​in the ViewModel and update the object in the database.

public virtual ActionResult Edit(int id)

[HttpPost]
public ActionResult Edit(VehicleVariantEditSaveViewModel viewModel)

If an error occurs during model binding in the POST action, I understand that I can return the RedirectToAction to the GET action and save the ModelState validation errors by copying it to TempData and retrieving it after the redirect in the GET action.

if (TempData["ViewData"] != null)
{
    ViewData = (ViewDataDictionary)TempData["ViewData"];
}

How can I then convert this ViewData, which includes the previous invalid ModelState, into a new model to send to the view so that the user sees their invalid input with validation warnings? Oddly enough, if I pass a new instance of my ViewModel retrieved from the database (with the original valid data) to View (), this is ignored and the (invalid) data is displayed in ViewData!

thank

+3
source share
2 answers

I had a similar problem and decided to use the following template:

public ActionResult PersonalRecord(Guid id)
{
    if (TempData["Model"] == null)
    {
        var personalRecord = _context.PersonalRecords.Single(p => p.UserId == id);
        var model = personalRecord.ToPersonalRecordModel();
        return View(model);
    }
    else
    {
        ViewData = (ViewDataDictionary) TempData["ViewData"];
        return View(TempData["Model"]);
    }
}

[HttpPost]
public ActionResult PersonalRecord(PersonalRecordModel model)
{
    try
    {
        if (ModelState.IsValid)
        {
            var personalRecord = _context.PersonalRecords.Single(u => u.UserId == model.UserId);
            personalRecord.Email = model.Email;
            personalRecord.DOB = model.DOB;
            personalRecord.PrimaryPhone = model.PrimaryPhone;
            _context.Update(personalRecord);
            _context.SaveChanges();
            return RedirectToAction("PersonalRecord");
        }
    }
    catch (DbEntityValidationException ex)
    {
        var errors = ex.EntityValidationErrors.First();
        foreach (var propertyError in errors.ValidationErrors)
        {
            ModelState.AddModelError(propertyError.PropertyName, propertyError.ErrorMessage);
        }
    }

    TempData["Model"] = model;
    TempData["ViewData"] = ViewData;

    return RedirectToAction("PersonalRecord", new { id = model.UserId });
}

Hope this helps.

+3
source

I noticed that the model is included in ViewData, so you do not need to pass it in addition to ViewData, I do not understand how you get it, and then return it to the view.

    public ViewResult Edit(int id)
    {
        // Check if we have ViewData in the session from a previous attempt which failed validation
        if (TempData["ViewData"] != null)
        {
            ViewData = (ViewDataDictionary)TempData["ViewData"];
        }

        VehicleVariantEditViewModel viewModel = new VehicleVariantControllerViewModelBuilder()
            .BuildForEdit(id);

        return View(viewModel);      
    }

, , , ( ViewData)

.

+1

All Articles