Compsoft Flexible Specialists

Compsoft plc

Compsoft Weblog Compsoft Website News Archive Privacy Policy Contact Us  

Thursday, May 21, 2009

Size of data in the ViewState

I love the ViewState.

I know it's a much-maligned technology. I know it can bloat out of all control. I know it can be an effort to tame it, but spend an afternoon reading up on it and it can really be your friend.

It can be a handy place to store all sorts of state data that you don't want to (or can't) track on the server. It's dead easy to add values to it programmatically and retrieve them after a postback.

You can serialize pretty much anything into the ViewState. Though putting an instance of your Customer class in there would blatantly be a bad idea - it would be vast once serialized - storing smaller constructs is feasible, and usually holding a few flags is sufficient to maintain the state of your page.

What can be a little surprising, though, is how big some data items are compared with others when they're serialised to the ViewState.

I spent an afternoon putting all sorts of items into the ViewState and seeing how much it made the ViewState grow. The results are in the graph below. (Click to see a legible-sized version.)

ViewState Graph

Note that all the figures are multiples of four - this is because the ViewState is base 64 encoded. Unfortunately it means the figures aren't quite spot-on to the byte, but they're good enough for our purposes.

The most important thing to notice is the long bar at the bottom. A List<string> containing only two three-letter strings took a whopping 312 bytes! Compare this with the array of strings holding the same values, which took only 24 bytes. An easy lesson: if you're putting a set of objects into the ViewState, turn that list into an array first.

In fact, arrays perform pretty well. Arrays of arrays carry a bit of overhead but aren't too bad, all things considered.

Surprisingly, int.MaxValue takes more space than the integer 1. Storing int.MaxValue.ToString() took more again, but these figures are still pretty small so it doesn't make much difference.

Converting a DateTime to a string took rather more space than the raw DateTime itself.

On the other hand, decimals take a vast amount of space for what they are (and decimal.MinValue took significantly more than decimal.One); but converting them to strings dropped the space right back down again.

I'm surprised that storing a Guid takes three times as much space as its string representation - I can't imagine what extra information is being serialized there.

Similarly, types take quite a bit of space; storing their full names is sufficient to regain the class object later and takes only about a third of the space. (Though to be fair I can't imagine what circumstances would lead you to putting a Type into the ViewState.)

Labels: ,

Monday, May 18, 2009

Combatting "Unspecified error"

In one of our Windows Mobile applications we've been noticing some bizarre exceptions where we're logging a rare exception of "Unspecified Error".

It's always a pain getting this kind of error, you really have no clue where to turn. Pin pointing the general area and finding the point at which the application fails tends to be the only route and led us to find it was database related.

Further research into the error implies that the issue lies in SQL CE (we're using SQL CE 3.5 SP1). It's at the point we're touching the database but ONLY after the device has come out of stand by mode and ONLY if the database file is located on the storage / memory card. Database files stored on the internal memory are fine.

It turns out that the SQL Server Mobile engine has a bug when the database file is accessed before the block device driver (that allows you to access the database file) has started up after the device is restored from suspend mode.

There's a hotfix available for previous versions but not the latest and it only seems to give a more intelligible error message of "The disk is not ready" or "The OS storage system (RAM, CF, SD, or IPSM) is not responding. Retry the operation".

Which leaves us with the choice of what to do in this instance.

1. Handle database access exceptions until the device is ready again.

2. Wire up to the device's power events and handle the Power up event.

3. Move the database file to the Internal memory.

I decided to go with option 2. A significant amount of work would have been required for option 1. The devices we're working against have a 2GB storage card versus a 64mb internal memory so I felt this wouldn't work for us without impacting performance so I didn't go for option 3.

The easiest way to go with option 2 is by using the opennetcf smart device framework framework which in the OpenNETCF.WindowsCE.PowerManagement namespace allows you to wire up to all the Power related states and their changes.

Here's one possible solution:

   1: static void Main()
   2: {
   3:     OpenNETCF.WindowsCE.PowerManagement.PowerUp += new 
OpenNETCF.WindowsCE.DeviceNotification(PowerManagement_PowerUp);
   4:     //Run the app
   5: }
   6:  
   7: private static void PowerManagement_PowerUp()
   8: {
   9:     System.Windows.Forms.Application.Exit();
  10: }

OpenNetCF has some great products, their download count is at 3/4 million at the time of writing. They have good customer service too.

Labels: , ,

Tuesday, May 05, 2009

Making sure your application is not left in debug="true"

You will find loads of articles around the web reminding us all that running your production ASP.NET website in complication debug=true mode is a BAD THING!
To make sure we avoid this problem we have added a start up check in our application that will make sure that the build mode (debug or release) of our binaries match that of the web.config. As all releases are done via our build server all our binaries will be in release mode. However we tend to make major changes to the web.config on the live servers so deploying the web.config is usually not an option.

To check if the web.config has debug enabled you can use HttpContext.Current.IsDebuggingEnabled.

To check what mode a binary is in, we use the #DEBUG Preprocessor Directive:

   1: // codesnippet:ADB0358E-3BD1-11DE-B2D2-764056D89593
   2: public static BuildModeEnum BuildMode
   3: {    
   4:     get    
   5:     {        
   6:         #if (DEBUG)
   7:             return BuildModeEnum.Debug;
   8:         #else
   9:             return BuildModeEnum.Release;
  10:         #endif
  11:     }
  12: }




Labels: , , ,