Solving the 65535 byte viewstate limit problem in OutSystems
A frequent question in the OutSystems community is what to do about the 64k object limit that both .NET and Java impose on their viewstates. In Java, the error message is “the code of method storeViewState(ObjectOutput) is exceeding the 65535 bytes limit” when you try to publish.
The short explanation to this is “you put too much stuff on your screen”. The longer explanation is that all of the screen-level objects (queries that occur in preparation, screen variables) get serialized, encrypted, and sent to the client as hidden variables, and sent back to the server on postbacks. This is how you can have a load balanced environment where the postbacks have access to those screen-level objects even though the postback is handled by a different server that originally displayed the screen. Unfortunately, both .NET and Java have a limit of 64k objects that can be put into viewstate.
Viewstate Works, It Isn’t Good
Viewstate is an answer to a thorny technical problem, but that does not mean that we can be free and loose with it. Think about this: if you hit a limit of 64k objects in the viewstate, and that data is being serialized (slow), then encrypted (slow, inflates data size), then sent to the client, it makes sense to keep it small, right? And then consider that every postback also sends the viewstate to the server, and gets a new viewstate! It should be obvious that you need to do everything you can to keep that viewstate small…
… but sadly, my customers, business users, and other “folks who tell me what the screen should look like” (and probably yours) are big fans of making “kitchen sink” screens that will hit the viewstate limit.
How to Fix This
We have a few options, which you can mix-and-match to suit your needs, to make your viewstate smaller.
- Move screen variables and preparation queries to Screen Actions when possible. Sometimes we are just sloppy, and put things at the screen level when they should be action level. Doing a quick “Find Usages” in the Preparation and screen variables will let you figure out what can be moved around.
The “Lazy Load” pattern lets you push a ton of work into Screen Actions, but the downside is that if you need to do something like refresh a query, you need to copy that query and copy its output to a screen-level variable so the screen can see it. That makes maintenance messy, because you need to make sure that if you update the query in one place that you update it everywhere.
- Reduce the number of editable fields on the screen. Each editable field on the screen contributes to viewstate. Prime offenders are TableRecord and ListRecord widgets with editable fields in them, which starts to multiply the editable field count. The easiest way to reduce the editable field count is to make the page read-only, and have an “edit” on the link going to a popup that edits that one specific record. This is not always a great UI, but it is what you need to do from time to time. It is certainly a very quick and easy solution to the problem if you already built the screen and are short on time.
- Break the screen into Web Blocks. If you need to get this done RIGHT NOW you can break the screen into Web Blocks. Unfortunately, you can forget about having a single “save” button at the bottom of the screen without jumping through some major hoops. The other issue is that while you may be working around the limitation, you still have a monster-sized viewstate that needs to be sent to the client and back to the server with every postback, making the user experience awful.
- Revamp the UI to create separate screens. Changing the UI to have a step-by-step wizard, or server-side tabs will let you split the screen into smaller ones, with a lighter viewstate. This is a great option, and usually makes the screen a lot easier to use in the process.
These are the tricks that I have found that solve this tricky issue, but I would like to know what works for you!