0

I have a view model containing data from a user form and other data. After submitting the form, the server-side validation is performed and if the form is not valid, my code returns the view with the updated model.

// If we got this far, something failed, redisplay form
return View(model);

The problem is that properties not used in the form are lost. What is the proper way to not lose this data after submitting the form?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
D.L.
  • 201
  • 6
  • 14
  • 1
    There's too little context here to give proper advice. Is everything on the form tied to this viewmodel? Can you use hidden properties (i.e. can you trust user input)? Or can you reload the model from the database (or service, or ...) and repopulate it from the data that _was_ posted ([`TryUpdateModel()`](https://stackoverflow.com/questions/1087279/how-does-the-asp-net-mvc-updatemodel-method-work))? And so on. There are plenty of suggestions, but their feasibility depends on what the rest of your code does. – CodeCaster Jan 22 '20 at 09:40
  • @CodeCaster using hidden properties does not work with Lists and similar data structures. I was wondering if there's a standard pattern to address the problem, but I think you just answered my question – D.L. Jan 22 '20 at 09:48
  • 1
    @DavideLeonardi hidden properties **can** be used with lists: https://stackoverflow.com/a/37238682/8126362 – Johnathan Barclay Jan 22 '20 at 09:53
  • looks like your submitted viewmodel doesn't pass completely to controller or it is different viewmodel. Please update your question to contain more info. – Kira Hao Jan 22 '20 at 10:18

1 Answers1

1

There isn't a "proper" way as such, just different options that you can select from based on your use case.

The first is that you post all your data back to the controller i.e. add inputs for every property.

The second is to retrieve missing data again before resurfacing your form e.g.

[HttpPost]
public IActionResult SomeMethod([FromForm] SomeModel model)
{
    if (!ModelState.IsValid)
    {
        model.Property = _repo.GetValue();
        return View(model);
    }
}

The third is to use TempData or Session, which work in a similar way.

TempData might be better in this scenario, as the value is only persisted for a single HTTP request:

[HttpGet]
public IActionResult SomeMethod()
{
    var value = _repo.GetValue();
    TempData["value"] = value; // Store value in temp data
    model.Property = value;
    return View(model);
}

[HttpPost]
public IActionResult SomeMethod([FromForm] SomeModel model)
{
    if (!ModelState.IsValid)
    {
        model.Property = TempData.Peek("value"); // Retrieve from temp data (may need casting)
        return View(model);
    }
}

Notice the use of TempData.Peek rather than accessing by key; this will ensure if another submit is invalid, the data will be retained, then will be cleared once a valid submission is made.

Be aware that when using the TempData / Session approach that multiple windows / tabs may overwrite the data, which will then resurface in another tab.

Also a session may timeout, which would cause values to be lost.

Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • 1
    But each approach you suggest has its problems which your answer doesn't mention. Using hidden fields may not be viable as the not-posted properties might not be supposed to be user-editable. Reloading the model from the database loses information the user has entered or changed (but not always, see https://stackoverflow.com/questions/41775756/). Using the session or tempdata breaks loading the same page in two tabs for different entities; the latest overwrites the values for the previous. Also, sessions can time out; making a POST after the time out ends up with empty values. – CodeCaster Jan 22 '20 at 09:51
  • @CodeCaster 1) Clearly yes; if the user tries to circumvent that that's their prerogative. Hidden fields shouldn't be blindly written back to the database anyway. 2) Again yes, isn't that obvious that database values may be updated? That's a concern for all software not just MVC. 3) Fair point; I'll update my answer. – Johnathan Barclay Jan 22 '20 at 10:10