Nonsense Viewstate Usage (and a Lot of Microsoft Sincerity)

Note: this entry has moved.

A few days ago I stumped at the following sample (Whidbey docs required):

 

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/cpref/html/T_System_Web_Handlers_AssemblyResourceLoader.htm

 

In the code for that sample a custom control is built; you will find that a constructor taking two arguments is provided but not used; why is it provided at all is beyond me.

 

        public TextWithImage(string text, string imageName) {

            ViewState["Text"] = text;

            ViewState["ImageName"] = imageName;

        }

 

But what is really bad about the previous constructor? It’s the lack of sense of storing values into viewstate in a constructor when viewstate tracking has not been started yet; anything you put in there will not be persisted into viewstate.

 

As these samples are and will be followed by thousands and thousands of people I believed it was really necessary to not show such a thing. People actually learn from samples and this one will not help any in that matter.

 

So I filed this bug using LadyBug and telling:

 

Description:  Opened by vga on 2004-10-31 at 00:27:49 

                                     

In the sample used here:

 

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/cpref/html/T_System_Web_Handlers_AssemblyResourceLoader.htm#codeExampleToggle

 

A ctor taking two arguments is provided although not used by the sample. This ctor actually stores into viewstate the two arguments passed.

 

Storing values into viewstate in a ctor is nonsense as viewstate tracking hasn't started yet thus these values won't be persisted.

 

Please consider deleting the mentioned ctor from the sample as:

 

1) its not used at all

2) its showing a nonsense usage of viewstate

 

And less than two days later I got the following (the highlighting is mine):

 

Resolution: Fixed

Closed by Microsoft on 2004-11-02 at 11:15:43 

   

Thanks for your comments,

you are right that manipulating view state in the constructor in that way is silly. I've changed the sample to have a default constructor; the control is still usable in this way and still demonstrates the important thing, which is how to use the AssemblyResourceLoader to get at some type of resource compiled with the assembly.

 

Regards, Alex 

 

 

Don’t you just love that much sincerity? :-) I know I do!

 

BTW, Alex if you happen to read this, please while you’re at it modifying the sample make sure to also change the referenced filename map6.gif to something like… map.gif? Or if you really want to get funny with filenames then you could try map872-b-northEast.gif… :-)

9 Comments

  • While I agree that the use in the example is probably silly, I think it's going too far to call it nonsense. The two examples below are equivalent, and while I'd normally use the second style, I don't think the first one is "wrong". Setting a value in ViewState before tracking starts establishes a default which can subsequently be overridden. If the constructor in your example was ever used it could be a valid design.



    ==== Example 1 ====

    public MyControl : Control

    {

    public MyControl()

    {

    ViewState["Text"] = "this is the default text";

    }



    public string Text

    {

    get { return (string) ViewState["Text"]; }

    set

    {

    if (value == null) throw new ArgumentNullException();

    ViewState["Text"] = value;

    }

    }

    }



    ==== Example 2 ====

    public MyControl : Control

    {

    public string Text

    {

    get

    {

    object o = ViewState["Text"];

    return (o == null) ? "this is the default text" : (string) o;

    }

    set

    {

    if (value == null) throw new ArgumentNullException();

    ViewState["Text"] = value;

    }

    }

    }

  • Hi Joe,



    I disagree with you. If I'm given a ctor like the one in the sample, where I can provide two properties values, I will expect them to be properly persisted. If you accept the sample approach then you will need to remember to store the values one more time after viewstate tracking has started just so you get what you would have expected in the first time: proper persistence of property values.



    Now, note that your sample is a actually different than the MS one as you're *not* taking input from the user. What you're doing in your sample is to have a default value for one of your properties. You can achieve this by using the following ultra-common viewstate pattern that doesn't include touching viewstate:



    public ImageName {

    get {

    String img = (String)ViewState["ImageName"];

    if (img != null)

    return img;

    else

    return YOURDEFAULTVALUEHERE;

    }

    }

  • Victor,



    I haven't looked at the sample you referenced, nor have I ever seen or designed a control with a constructor that takes arguments. However if this is ever needed, then the calling Page (or parent control) would obviously be instantiating the control in code. In which case it would probably have already persisted the initial values itself if necessary (i.e. if constructing the control after its own ViewState tracking has started). Without a concrete example of how you would use such a control I can't make my mind up whether this could be a valid use.



    The ultra-common ViewState pattern you mention is the same as my Example 2 above, and I agree it's more natural. The only point I was making is that writing to ViewState before tracking has started is not completely redundant, it is a valid (if slightly inefficient) way to establish an initial default.

  • VGA,



    Actually, I think that will cause an exception if ImageName is not defined in the viewstate, since you can't cast null to an object. What I think you want is:



    public ImageName {

    get {

    String img = ViewState["ImageName"] as String;

    if (img != null)

    return img;

    else

    return YOURDEFAULTVALUEHERE;

    }

    }



    the "As String" should properly handle the null (I also think it looks better/more readable that way, but that's just me)

  • test:



    | public ImageName {

    | get {

    | String img = ViewState["ImageName"] as String;

    | if (img != null)

    | return img;

    | else

    | return YOURDEFAULTVALUEHERE;

    | }

    | }

  • Hi Joe,



    Thats the point I was trying to note; the Whidbey sample I referenced and the one you posted aren't equivalent. The Whidbey samples can really confuse developers. Your sample is different as you're just using the early and non-trackeable storage just to have a default value. I understand this, but still like more the approach of having the default value in the property get accessor (IMO, better readability, perf, etc).



    Thanks for your feedback!

  • Hi James,



    No, you won't get any exceptions; my posted code should run ok even when there is no such data into viewstate.



    Thanks for your feedback!

  • However, if ViewState["ImageName"] happened to contain something other than a String object, then an exception would be thrown.



    Whether this is a problem or not is dependent on the specific requirements of the project; however, personally I'm a fan of using the 'as' operator when pulling stuff out of a non-strongly-typed collection.

  • Sure, but as you're in total control of what gets into viewstate for your property as you're the one writing the set accessor for it, then if something else than a String object gets there it is because:



    a) your set accessor is buggy

    b) something really bad happened to viewstate and in this case odds are that you're going to see *another* type of exception before trying to access your property.



    I do agree that 'as' looks like a more "elegant" solution.

Comments have been disabled for this content.