aspnetcore: ModelState cannot be added to TempData (cannot be serialized)
I found this when dealing with ModelState and transfering using TempData to follow PRG pattern.
TempData.Add("ModelStateTransfer", ModelState);
InvalidOperationException:
The 'Microsoft.AspNet.Mvc.ViewFeatures.SessionStateTempDataProvider' cannot serialize an object
of type 'Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary' to session state.
Shouldn’t be ModelState serializable?
I was pointed out to this tests: https://github.com/aspnet/Mvc/blob/25eb50120eceb62fd24ab5404210428fcdf0c400/test/Microsoft.AspNetCore.Mvc.Core.Test/SerializableErrorTests.cs
so I tried using SerializableError with no success
TempData.Add("ModelStateTransfer", new SerializableError(ModelState));
InvalidOperationException:
The 'Microsoft.AspNet.Mvc.ViewFeatures.SessionStateTempDataProvider' cannot serialize an object
of type 'Microsoft.AspNet.Mvc.SerializableError' to session state.
Help? Ideas?
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 34 (17 by maintainers)
Laravel (PHP) has redirect function in controller action which can be fluently chained to include errors and form inputs.
https://laravel.com/docs/5.1/validation#other-validation-approaches
Related to issue topic, it’d be nice if we can do this, instead of manually playing with
TempData/ manually serializingModelStateThat’s similar of what I ended up doing. But that isn’t a supported scenario on 1.1. That’s just read the data serialize and create the model again in a very manual fashion. While it works, I still think it should be baked in the framework and not responsibility for the developer or external Nuget.
@sipi41 - the problem with this though is that static variables is that they remain in memory past the current request - they retain value for the lifetime of the application. It may work in test with a single user, but with multiple users, this is very dangerous. Every user will see the same value for that static variable. Not to mention potential concurrency issues.
The problem I describe doesn’t happen with the Post-Redirect-Get (PRG) pattern because error cases are still a POST, so if you refresh, first of all the browser warns you, and even if you do post, you just re-post the same (bad) data, in which case you see the same errors again. If you do an initial redirect w/ TempData then the browser might not warn you, and if you proceed, you lose your data.
Is the problem I’m describing not a concern? We can certainly implement what’s described here, it just doesn’t seem to me like it would promote a good UI for end-users.
I’m reactivating this for consideration. We might not do exactly this but we should do something for this scenario
I still don’t believe that TempData is a solution for this. One hit of <kbd>F5</kbd> and your TempData goes away.
I’m going to chime in here as well with a 👍 - this is one of those death by a thousand cuts that makes MVC painful to use. IMO, it’s fine when you can post to the same URL that you’re currently on, it falls apart when you need to start posting to different URL’s and handling error conditions.
@Bartmax That’s true. PRG by far seems the best way of dealing with this kinda scenarios.
Recently I came across this article that demonstrates how to push the new
ModelStateintoTempData(as we used to do in previous versions of asp.net).One thing that got me thinking is that a guy in the comment section alleges that this functionality is supported on aspnet core 1.1 through cookie tempdata provider. Would love someone providing any thoughts on that matter.
@dougbu For simple types like
intandstringyes, I’m aware. But if I have a list of an complex type, when post happens, it will always be null (pretty obvious). In those cases we have to rebuild the view model to display the correct data again.That’s when PRG shines, because only the GET action needs to know how to build your views. If I’m always checking model state on POST, I’ll have to duplicate the code that builds the view every single time (both on GET and POST).
All that beeing said, what are your thoughts on reusing that code? I know that a view model builder or something like that is an option, but I’m wondering what other approaches could fit that case instead of PRG.
Update: Beware though that are some complex cases/approaches where view data is populated through TempData/ViewBag. In those specific cases we must have access to either of them to re-insert the values, and this kinda breaks the use of an out-of-controller builder abstraction.
Andrew Lock provides a workaround for this problem in MVC: https://andrewlock.net/post-redirect-get-using-tempdata-in-asp-net-core/ Unfortunately his method doesn’t work in Razor Pages, so I’ve created a
IPageFilterfor this, maybe it’ll be helpful for someone: https://gist.github.com/Yaevh/e87f682a3c3ac35d1504c068c9f5e8abI however agree that it should be supported by the framework itself and not require additional work by the developer.
@Eilon I don’t think I quite understood your explanation. The reason to preserve ModelState here is to provide form usability. Imagine a huge form, if you treat failed requests just as a normal POST, then the user will have to fill every single form field again.
The way I see it, we have two options when
ModelState.IsValid = false:Of course the second options is preferable because of DRY. What is your approach right now? Anyone else could bring some thoughts on this matter?
Basically, I want to save ModelState on a POST action so I can redirect and have the ModelState on next (get) request. Basic PRG pattern.
Since this is the source thread, I figured I would post what helped me and it works great on any kind of model you create.
https://stackoverflow.com/questions/34638823/store-complex-object-in-tempdata-in-mvc-6