ASP.NET
I'm not talkin' about tennis...
Today I received a *very* cool gift (signed by Soma) consisting of a transparent (and heavy...) cube with the Visual Studio 2005 logo and a few paragraphs floating inside of it (ok, its hard to explain). Very, very cool:

It is the "Visual Studio 2005 ACE award", which recognizes the contributions done to make VS a better product, like a lot of bug reporting, suggestions, etc.
A few weeks ago I had the chance to peek at the FlexWiki source code while helping a team that was trying to integrate a Wiki into an existent website. All my suggestions to them, like “write a custom control to do this or the other” had the effect of only confuse them even more. They were worried about “how to do that in FlexWiki”. Well… it’s an ASP.Net application so you should not have much trouble adding an extra control for instance, that was my simple reasoning, until I saw FlexWiki soure code, of course.
What I saw was really some of the worst coding practices you could use for an ASP.Net application. But the real surprise came after I read the 2nd line that is in every source file:
// Copyright (c) Microsoft Corporation. All rights reserved.
This worried me a bit… -- Why is a Microsoft copyrighted ASP.Net application using some of the worst coding practices for a web application?
Inside the ugly
You probably remember ASP 3.0 common code like the following:
Response.Write (“MyMessyAndImpossibleToMantainMarkupGoesHere”)
Well… FlexWiki contains more than 400 (that is, four hundred) calls to Response.Write and some of them like the one found at WikiEdit.aspx.cs:432 output ~3Kb of html in a single call, that’s as ugly as it can get regarding usage of Response.Write. This includes hard coded CSS class selectors, hard coded markup, etc, thus making customization of “the thing” really a hard task.
But besides the common “bad-usage-of-Response.Write” syndrome that you will find in FlexWiki and some other web apps out there what is really incredible is that FlexWiki doesn’t use any of the major ASP.Net features!! No controls, no state management, etc. I guess if you rename FlexWiki pages from “.aspx” to “.asp” they may even work in ASP 3.0!! J
Getting uglier
By looking at Default.aspx you can easily tell that all its doing is spitting out chunks of hard coded markup and javascript code in a never ending method of ~200 lines in length named DoPage. This is very similar to the rest of the pages they use.
So their approach basically seems to consist in having an .aspx page with the following:
<%@ Page language="c#" Codebehind="ShowNewsletter.aspx.cs" AutoEventWireup="false" Inherits="FlexWiki.Web.ShowNewsletter" %>
<% DoPage(); %>
And a huge DoPage method with all the hard coded markup and script into a corresponding aspx.cs file.
Where are the controls taking to each other, firing events, maintaining state, etc. You won’t find that in FlexWiki, I’m afraid.
So if you ever try to extend it, for instance, adding a CAPTCHA control for validating edits, you are on your own, spending lot of time because of FlexWiki “architecture”.
It’s also hard to understand the reason why if they really wanted to use the DoPage approach (which just in case you haven’t noticed already I think it’s nasty) they did not go for a custom IHttpHandler implementation… (why having a full featured Page when all you’re doing is calling Response.Write?).
Almost five months without any blogging… bad… bad… bad...
Here is the list of the main excuses reasons that kept me from blogging:
Reason #1: ClariuS is growing, a lot!
And at a really quick rate, which has been keeping me busy with a lot of extra stuff that range from internal training, looking for new office space and things like choosing furniture color… :S
Reason #2: Work overload.
As usual I’m working on several different projects at the same time which adds for long days. Add to this the usually ignored task-switching overhead and you get the idea.
Reason #3: Lots of Community stuff.
Wrote a few articles for different magazines and online websites. One of them is about the new interesting Virtual Path Provider feature that will be appearing shortly at MSDN. I also did a few talks and I’m currently working on finishing two presentations I will be giving at VSLive! Boston June 23rd (let me know if you’re planning to attend!).
I also helped at the TechEd 2005 ASP.NET Cabanas in Orlando last week where I had the chance to answer a broad range of customer’s questions and met again with team members like AndresS, SimonCal and a brand new software architect. J
Ok, enough excuses so far. Its time now to get this blog working again!
I want IIS to finally marry ASP.NET, once and for all. I’m looking forward to much more than the current integration that exist today between ASP.NET v1.1 and IIS6 where you’ve to deal with a lot of duplicate functionality.
Take for instance authentication: you’ve got IIS authentication and ASP.NET authentication, this could be integrated in a way that setting authentication for a website could be done in one shot and without leaving room for any confusion.
Session state management, extension mappings and custom errors are just other duplicate features. Let’s take custom errors: IIS configuration offers its very own “Custom Errors” tab for mapping HTTP error codes to files while ASP.NET has a <customErrors> element that you can set in your web app config file. They both do exactly the same thus they’re different, separate features.
But what I would like the most to see unified is the HTTP pipeline, definitely. This is currently also duplicated in IIS and ASP.NET and you’re forced to make a hard choice. You may go down to the metal ISAPI route, where you can write really high-performing extensions and modules while loosing the easy access to key ASP.NET services like caching OR you can go the ASP.NET way of writing handlers and modules having easy access to all offered services but loosing on the performance side of the equation.
And finally, do we really need to have different names for IIS and ASP.NET?
I just downloaded the Community Server beta 2 with the intention of having a quick look at it. Unzipped the download and found no source code… L (there is a “no source code will be available for beta 2” legend in one of the readme files too).
So I fired up Reflector and started looking at the available classes to get an idea of how the integration of .Text, ASP.NET Forums, ect looked like. While doing this I stumped at an assembly whose naming was not following the standard “CommunityServer.blah.dll”, instead it was named “MemberRole.dll”…
“Oh, an implementation of membership & roles coming from the guys at Telligent and/or the community” was what I thought. But then, why in the world is it named with no “CommunityServer” or “Telligent” prefix?
I’m curious you know… so I had to feed this little “MemberRole.dll” through Reflector and… big surprise!
The namespaces used start with “Microsoft” and by quickly looking at the implemented classes one can easily tell that it looks like a backport of the Membership, Roles, Profile and Provider pattern found in the Whidbey bits.
I haven’t heard anything about this yet, maybe this is because I’m like 1.5 weeks behind weblogs…
About ten months ago Daniel Cazzulino and I decided to start ClariuS Consulting SA, with the aim of building a unique company that would be the greatest place to work and build a long-term career. So far, our expectations had been *greatly* surpassed (and I really mean greatly here). We've been incorporating more people to the team, but we're in need for more!
At ClariuS we do all kind of interesting and exciting work. We help customers get up to speed with .Net by providing superb training, mentoring and consulting. We also write a lot of code. We present @ several conferences (locally and worldwide) and we write articles and books. So there are really lots of things to do depending on your profile and your preferences.
If you happen to live anywhere near Argentina and you’re a smart guy that can get things done, then we definitively want to hear about you. Either ping Daniel (kzu AT clariusconsulting DOT net) or me or the more formally jobs AT clariusconsulting DOT net.
Also, if you’re not living in Argentina or anywhere near but you’re available for contract work we are also interested in hearing from you.
Quick Catchup: you may have heard about the new upcoming Cross Page Posting feature in ASP.NET Whidbey, in a nutshell: you will be able to post from page A to page B and while executing in Page B do some cool things like accessing the control tree for page A.
I was having dinner the other night with my gf and we where talking about *I don’t remember exactly what* when one sleeping thread in my head popped up and suddenly told me: “What about if the posting page uses Response.Write, that will be cause a mess!”.
Not having paid much attention to this feature before (read: not having run Reflector through it) I was pretty sure that if both pages were sharing the same HttpContext (which sounded logical to me) and the posting page called Response.Write to write its UI for example, then, when posted to another page, the target page UI will get all messed up with the posting page UI. Best of all this didn’t look like a bug at all, this was only good news, another excellent reason for people to finally start cleaning up calls to Response.Write in their code.
So, I quickly wrote the 3 lines of code required to test this scenario and hit Ctrl-F5.
I first browsed to –lets call it– Page “A” which included some garbage written out by calls to Response.Write. Then I clicked a button on Page “A” to cross post to Page “B” and expected Page “B” output to include the previous garbage… so far… no luck… Page “B” output was not including this… disappointing… :-(
At this point I started thinking that someone (read: the ASP.NET team) may have considered this before (just a year or two maybe? :-)) and included some workaround to make the life of developers using Response.Write much easier.
It was time for “the tool” to enter scene. It didn’t took me more than a minute or two to find out what was really happening, and yes, someone had thought about this before…
What is happening here is that before executing the posted page (Page “A”) from the target page (Page “B”), ASP.NET is cleverly switching the writer used by the HttpResponse instance with a dummy one, using a new internal (yes internal, sorry) method whose signature is:
internal TextWriter SwitchWriter(TextWriter writer);
After the posted page (Page “A”) has finished executing (and their controls are ready to be accessed by the target Page “B”) ASP.NET will switch again HttpResponse’s writer to the *real* writer this time thus allowing Page “B” to properly output whatever it needs to.
This is just an example of Whidbey helping the reputation of some ASP.NET developers :-)
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… :-)
No, I’m not talking about the 2004 Olympics here.
Like two years ago in a meeting for MVPs ScottGu was presenting an overview of ASP.NET Whidbey. I do remember he told us that ASP.NET support for mobile devices would be a gold key in Whidbey.
The alpha bits were a step further in that direction: the control architecture was revamped in order to allow “adaptation” natively. The days (and problems) of having two separate control architectures were counted.
So with adaptation being supported natively and with every control adaptable out-of-the-box against any of the supported markups they were going straight for the gold.
But then, one drop before beta1 eventually missed all the code for the adapters and the infamous System.Web.Mobile.dll had its comeback into scene. A few weeks after noticing it I innocently posted this. A week later I heard (just don’t ask where) that they were being cut off. A month later SusanC (blog?) confirmed it in the same thread. Then it got pretty much “official” with ShankuN announcement.
All this doesn’t lead to gold for sure. Why not silver then? Because I’m still not buying that the current adaptation architecture is here to last. Don’t take me wrong: it is way better than having no adaptation at all like the v1.x bits but it has it owns drawbacks too.
Bronze would be a better fit for now.
I highly encourage anyone playing with the Whidbey bits to take some time, register in the MSDN Product Feedback Center (a.k.a. LadyBug) and start submitting feedback. Based on my experience I can tell you that you won’t be wasting your time and you are going to get a reply to your submission, it may take a little while, but most likely you will get a response.
I have submitted a few bugs and suggestions myself (yes, I need to take some time, dig into my whidbey_bugs.txt file and start submitting those…) with different types of priorities and I was kind of surprised about how one of them turned up; I filed it as a ‘suggestion’ (‘bug’ was just too much for this one) and it is about a very low-level detail of the viewstate serializer that changed from 1.x to Whidbey in a way I didn’t like. My suggestion only received 1 (one) vote with a rating of 1/5. It was *my* own vote and I chose a rating of 1/5 because I thought “oh well, they’re in beta now, they’re surely worried by other most important stuff, so let’s be easy with them and just rate it with very-low priority”.
Sincerely, I was not hoping for this submission to get very far; luckily I was wrong!! :-)
I’m pasting a summary here (or you may want the real thing instead):
Problem Statement: Opened by vga on 5/26/2004 at 4:10 PM
=== Edited by vga on 5/26/2004 4:10:44 PM ===
There is a notoriously lack of support for the System.Web.UI.WebControls.Unit type in Whidbey.
In v1.x this type was assigned its own type code (49) which saved the serializer from having to store an –often large– string representing its assembly-qualified name.
In Whidbey, Unit is not backed up with a type code meaning that its full type name needs to be stored into viewstate, which means storing once the following additional string:
System.Web.UI.WebControls.Unit
Let’s take for example the following Unit instance:
Unit u = new Unit (“100px”);
In v1.x this instance will end up serialized into 8 bytes while in Whidbey final footprint will be of 39 bytes.
More info @ http://weblogs.asp.net/vga/archive/2004/05/26/WhidbeyWillBringsUsAShorterViewstateGuaranteed.aspx
Edited by Microsoft on 6/25/2004 at 7:05 PM
Thank you for submitting this bug report. We are currently investigating the issue and will keep you informed of the resolution.
The Web Platform & Tools Team
Edited by Microsoft on 6/30/2004 at 4:25 PM
The Microsoft Sub-status is now "Working on solution"
Resolved as Fixed by Microsoft on 7/22/2004 at 7:06 PM
Thanks for the feedback, we've now added the Unit token.
The Web Platform & Tools Team
As you can see this was “Resolved as Fixed” which means they’ve modified the current bits to add support for the Unit token, *way* cool!
Now, look at the dates and pay some attention: my initial submission was made on 5/26/04, almost a month later, on 6/25/04, they said “we’re investigating the issue”; my reaction to this was “oh sure… I can see the ‘thanks, but we’re a bit busy on other stuff’ already…”. Then, on 6/30/04, exactly 5 days later, they send a ‘we’re working on a solution’. I still didn’t buy this one and just though that sooner or later my little poor suggestion was going to die with the common “we will consider this for vNext”. Three weeks later –on 7/22/04– , when I’ve already completely forgot about this, a “Resolved as Fixed” was submitted. Yes, as I said before “it may take a little while” to get a final response, in this particular case it was “only” 56 days, but it was definitively worth the wait! (in case you haven’t noticed already, yes I’m happy!).
So, if you are not already registered in LadyBug, don’t wait any longer, register now and make yourself heard!!
And when you’re coding in ASP.NET 2.0 and store an Unit type into viewstate, remember… you’re saving 31 bytes thanks to me :-P
Microsoft is boosting MVPs visibility by launching an MVP Community site. This is cool. What is not so cool is the fact that if you’re an MVP and want to include a link to your bio on that site, for example as a signature for newsgroups posts, mailing lists, ect. you have to add around 200 extra chars because the URL produced by that site is huge; this is mine using the MS site URL:
http://www.microsoft.com/communities/mvp/mvpdetails.mspx?Params=~CMTYDataSvcParams^~arg+Name=%22guid%22+Value=%22c451d24e-5397-405f-a0d4-ae797459ccd4%22/^~sParams^~/sParams^~/CMTYDataSvcParams^
Hopefully kzu has noticed this and quickly hacked up a handler to offer shorter URLs; mine now looks like this:
http://aspnet2.com/mvp.ashx?vga
That’s about 180 chars shorter, now imagine the traffic the MVP Community site surely gets each day and try to count the saved bytes for each MVP profile link listed if they were using this format. Yes, @ ClariuS we take performance that seriously! :-)
I can see that Paul noticed this already.
Now, the “More” part of this post’s title
Dave Massy is working in the IE Team for almost a month now and already believes that he wouldn’t feel comfortable using any other browser. W-o-w. Dave, are you serious? Maybe you need to do some catching up of IE current status by downloading the latest bits and playing with them. I bet you won’t resist more than a day or two and will hurry up to download FireFox or any other updated browser.
NikhilKo is back to blogging!! His latest posts contain nothing but excellent inside stuff on the Whidbey bits. Go read them! :-) Now if we could just get ScottGu to start blogging again…
During last week I had a couple of different meetings (online and in person) with a bunch of Microsoft employees and we touched a big range of topics. One thing I’ve told them all is that if they were willing to destroy their credibility in a snap all they have to do is to try to defend the obsolete Internet Explorer or the non-working GDN Worskpaces. Any of these two positions will have the same instant effect: zero credibility for you.
As you may already know ASP.NET 2.0 will include a new control, HtmlHead, to serve all your <head> handling needs thus making all previous v1.x hacks unnecessary by providing programmatic access to that tag. So far so good. Let’s hear the bad now.
First thumb down: I received a response in LadyBug stating that viewstate support will not be added to HtmlHead. This was after I chimed about it. Sadly, they didn’t include an explanation backing up their decision (not that they have to but it would have been nice). While I agree that the most common scenario may not require viewstate handling there may be cases where it could be useful, so why not adding support for it and just set EnableViewState to false if you don’t want it?; with this approach you’re giving developers a choice at least…
Second thumb down: HtmlHead handling of meta tags is incomplete, or better said, *very* incomplete. Its RenderControl method is hardcoded to output only name and content attributes. What about support for other valid attributes like http-equiv and scheme? It’s just not there. Please, please… make this control more ‘standard-aware’, look at section 7.4.4 of the HTML401 spec and add support for it. It should be a piece of cake. I’ve filled a new bug in LadyBug (#FDBK11439), let’s see how this one turns up.
Considering the bits are in beta 1 now and that there are –for sure- more important bugs/issues/whatever to be fixed, my guess is that this poor little control will not get much more attention and will hit gold in its current status…
I just read Scott Mitchell’s article about viewstate where he’s explaining how viewstate serialization works and he’s saying:
“…The LosFormatter can serialize any type of object that can be serialized by the BinaryFormatter class…”
Watch out! That’s partially wrong. That is not complete and might lead you to believe that you need to make your type serializable by the BinaryFormatter in order to be able to store it into viewstate: that’s not true. As I explained in a previous post the LosFormatter will try using an associated type converter *before* getting to a BinaryFormatter. So, a type that is not serializable by a BinaryFormatter can still be serialized by the LosFormatter. It’s a real pity that none of the info that I’ve been detailing on some of my latest posts got mentioned into that article :-(
The reason I’ve been sharing this viewstate low-level details is because I couldn’t find them anywhere else on the web… and there is lot of misconceptions about how this really works, you can easily notice that by browsing the public newsgroups… Hey, even the Mono guys got it wrong at first but after I shout they quickly fix it.
There is a notorious difference in the logic used by the viewstate serializer when handling non-optimized types that may cause your code to break when running under Mono’s ASP.NET: they never look for an associated type converter and directly pass any non-optimized type to the BinaryFormatter (ouch!).
You may say “ok, that’s just an optimization thing; I will get a larger viewstate and will pay some extra processing cost, but why is my code going to break?”
Suppose you’ve a Customer type you want to store into viewstate and you’ve coded a CustomerConverter type converter for it:
[TypeConverter (typeof (CustomerConverter))]
public class Customer {
}
This is all you should need to store an instance of Customer into viewstate.
Under Microsoft’s implementation it will run just fine: the serializer will get the associated type converter and use that for serializing the Customer instance.
Under Mono’s implementation things will go bad because the serializer doesn’t use a type converter if one is available and directly passes the Customer instance to a BinaryFormatter. Of course the Customer type is not ready to be serialized by the BinaryFormatter (it is not marked with the Serializable attribute, it doesn’t implement the ISerializable interface) and that’s why a SerializationException exception will be thrown.
Mono team: this should be really easy to fix and by doing so Mono will be more compatible with Microsoft’s implementation, which I suppose is one of your goals :-)
I’ve already filled a bug against the serializer (#59495), let’s see how much luck I get…
UPDATE: Within hours after being submitted the bug is now fixed, cool!
In the following post I’m going to focus on the new viewstate serializer exclusively; keep in mind that there are other strategies being introduced in order to reduce viewstate size, like separation between viewstate as we know it today and a new control state.
Also, when using the term “serializer” I’m referring to the viewstate serializer unless otherwise noted.
New added support for common types
As I mentioned in a previous post, the serializer in ASP.NET v1.x was designed to handle only a few different types and it is not really a good idea to feed it with anything else.
In Whidbey, the serializer is being extended to support 10 additional types: IndexString, byte, char, DateTime, double, short, float, HybridDictionary, Enum and Color meaning that all these types now generate smaller footprints.
Aside from supporting new types, current serialization is being optimized. Let’s see some of the introduced changes.
Clever Gets Clever: type code = type + state
How is a Boolean handled? In v1.x they decided this was a very common type and added support for it into the viewstate serializer. This support means having a dedicated type code that represents a Boolean type thus avoiding the need to persist any additional extra information in order to properly identify it and de-serialize it later on.
This is how a serialized Boolean looks like in v1.x:
111 – code representing a Boolean type
60 – token representing the beginning of the stored state
116 or 102 – only one is used, depending on the instance value being true or false respectively.
62 – token representing the end of the stored state
Thanks to this type code optimization the footprint ends up being of 4 bytes which –believe it or not- is not that bad when compared for example to the footprint that would have been generated by the BinaryFormatter itself (~27 bytes).
First thing to notice in Whidbey is the reduction of token usage (char 60 and 62). In my opinion this “tokenized” approach of v1.x was largely useless so it’s a good thing to know it changed. Ok… so that’s two bytes shorter for a start.
Second thing we can see in Whidbey is that now the Boolean type code represents type plus state. Having two possible states bring us two different type codes: 104 for a Boolean with a value of false and 103 for a Boolean with a value of true. This means one less byte, which including the previous reduction, totals three less bytes, a 75% reduction, not bad. This is how a Boolean with a value of true looks like when serialized by Whidbey’s viewstate serializer:
103 – code representing a Boolean set to true
We miss you, Unit
There is a notoriously lack of support for the System.Web.UI.WebControls.Unit type in Whidbey.
In v1.x this type was assigned its own type code (49) which saved the serializer from having to store an –often large– string representing its assembly-qualified name.
In Whidbey, Unit is not backed up with a type code meaning that its full type name (yes, its full name and not its assembly-qualified one, wait till next title to learn why!) needs to be stored into viewstate, which means storing once the following additional string:
System.Web.UI.WebControls.Unit
None of the two serializers, the v1.x and the Whidbey one, do support any special serialization for this type; it’s being handled by a UnitConverter.
How this absence of a type code for Unit in Whidbey ends up reflecting in the final footprint?
Let’s take for example the following Unit instance:
Unit u = new Unit (“100px”);
In v1.x this instance will end up serialized into 8 bytes while in Whidbey final footprint will be of 39 bytes. Ugly… I know.
Types from System.Web.dll assembly are loved (and around 82 bytes cheaper now!)
In v1.x, non-optimized types were handled down to a type converter when available. When this happens the assembly-qualified name of the type needs to be stored into viewstate which is not fun at all as it usually tends to be a quite large strings, i.e.:
System.Web.UI.WebControls.Unit, System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
In Whidbey, the serializer performs an additional check and if its dealing with a type that lives in the System.Web.dll assembly then it uses a special code (42) to signal it so only the full name of the type needs to be saved, i.e.:
System.Web.UI.WebControls.Unit
This avoids the need for having to store assembly-qualified names for any non-optimized types living in System.Web.dll assembly which will usually result in saving ~82 bytes of storage caused by the following string:
System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
There are other interesting things going on about the new serializer, like the special treatment some types as Color are given in order to produce the smaller possible footprint. I guess I will save them for a later post…
The other day while I was reconstructing my OPML file I stumped across ScottGu weblog and noticed he hasn’t blogged this year yet. I already know that based on my poor average of 2,6 posts/month I’m in no position for asking anyone to blog more regularly.
But… Scott you are “ScottGu”!! I mean… you *need* to post more regularly, or better said, *we need* you to post more regularly.
From personal experience I know that writing, reviewing, giving talks, having a family *AND* having a day job makes it really difficult to find the free time to blog. But… Scott… I want to know what you’re into, no matter if it’s about Whidbey, Orcas or NextCoolCodeNameGoesHere technology.
How many people will notice if VGA has a 2,6 posts/month? Actually just a few, one of them being my friend Daniel who likes to remember me -about every day- of that poor average… But Scott… I bet there are *lots* of people waiting to read stuff from you. So let’s make all these people happy!, right?
And… I’m making a public compromise of making 3 (yes, that’s three) posts per every post made by Scott -- offer valid through May04 only, sorry! :-)
All the stuff written out there about viewstate will alert you that it was designed to handle only the following types: int, String, Boolean, Pair, Triple, Array, ArrayList, Hashtable and that trying to store anything else will incur in a performance loss. This is a well-known fact but what is not so well-known is the real why behind this.
One of the things I like to mention in my talks while addressing viewstate performance is something like “don’t let the BinaryFormatter get at your data”. I like all the “what??” this phrase causes at first :-) but after a bit of explanation everything comes back to normal again.
So, let’s see how the LosFormatter type –which happens to be the viewstate serializer- was designed for dealing with type serialization.
Its first approach is a very common one; it consists of checking if the type its dealing with it’s a simple one that it knows how to quickly serialize (the types listed at the very beginning of this post). In case it’s dealing with such a type it just needs to write out some form of header (usually a type code, which will be used to know what type follows) and then the customized (and fast) serialization happens. Note this is not really a novel ideal and it is exactly the same AltSerialization type already does.
Now, if the type LosFormatter is trying to serialize it’s not a supported one it will check if that type has an associated TypeConverter (yes, this implies some reflection code so you can start feeling the perf loss already, can you?). If a type converter is found then it will just say: “Hey you, type converter! Could you please serialize this type to a string representation for me please?”. It will then just use the output produced by the type converter.
But what happens if the type hasn’t an associated type converter. Well in this case the LosFormatter will say “Oh damn!, I don’t know how to serialize this type by myself and worse yet, it doesn’t have an associated type converter available to do the work for me; what am I gonna do now?” Its own answer is: “Let’s use the BinaryFormatter!”. Note that we’re talking here about instantiating a new BinaryFormatter and feeding it with the type in question. As you can imagine this is *lot* more work than any of the previous two steps, so you *really* want to avoid getting here in the first place.
Let’s put the above explanation into perspective; let’s say you’ve the following type:
[Serializable]
public class Customer {
private String _lastname;
private String _firstname;
private String _address;
private int _age;
private int _code;
public Customer (String lastName, String firstName, String address, int age, int code) {
this._lastname = lastName;
this._firstname = firstName;
this._address = address;
this._age = age;
this._code = code;
public String LastName {
get {return _lastname;}
set {_lastname = value;}
}
public String FirstName
{
get {return _firstname;}
set {_firstname = value;}
}
public String Address
{
get {return _address;}
set {_address = value;}
}
public int Age
{
get {return _age;}
set {_age = value;}
}
public int Code
{
get {return _code;}
set {_code = value;}
}
}
Now let’s say you need to persist an instance of this Customer type to viewstate. If you just do so, the type won’t be one of the supported ones by LosFormatter and it won’t have a type converter associated so the BinaryFormatter will kick. Let’s try it:
Customer cust = new Customer("Garcia Aprea","Victor","1802 4th Clarius Ave.",29,31987);
LosFormatter los = new LosFormatter();
StringWriter sw = new StringWriter();
los.Serialize (sw, cust);
String resultSt = sw.GetStringBuilder ().ToString();
int size = sw.GetStringBuilder ().ToString().Length;
If you read size value you will notice that you just paid 436 bytes to serialize a Customer. For three short strings and two integers that seems just too much.
Let’s now code a type converter that knows how to persist a Customer to a String and get back a Customer from a String:
public class CustomerConverter : System.ComponentModel.TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(String))
return true;
return base.CanConvertFrom (context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(String))
return true;
return base.CanConvertTo (context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
String state = value as String;
if (state == null)
return base.ConvertFrom (context, culture, value);
String []parts = state.Split ('#');
return new Customer (parts[0], parts[1], parts[2], System.Convert.ToInt32 (parts[3]), System.Convert.ToInt32 (parts[4]));
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null)
throw new ArgumentException ("destinationType");
Customer cust = value as Customer;
if (cust != null)
return cust.LastName + "#" + cust.FirstName + "#" + cust.Address + "#" + cust.Age.ToString() + "#" + cust.Code.ToString();
else
return base.ConvertTo (context, culture, value, destinationType);
}
}
And let’s attach it to the Customer type:
[TypeConverter (typeof(CustomerConverter))]
public class Customer
Run again the previous code used to feed a Customer instance to the LosFormatter and this time the footprint will be of 196 bytes! That’s quite a reduction, isn’t it?
Lastly, let’s play by LosFormatter rules and offer it a type that it knows how to handle:
Triplet t = new Triplet (cust.LastName, cust.FirstName, cust.Address);
Pair p = new Pair (cust.Age, cust.Code);
Pair custPair = new Pair (t,p);
Now feed the LosFormatter with custPair and not just an instance of Customer; this time the footprint will be of… 60 bytes! Another great improvement over the original 436 bytes.
I’m hoping that you can now see there are *real* benefits of knowing this stuff and that you could start taking advantage of it right away! :-)
On 4th May I will be doing a presentation on ASP.NET v1.1 @ Microsoft Argentina. I’ll be covering state management and an overview of custom control development.
One particular thing about it it’s the audience… it’s for a user group named “Desarrolladoras.NET” which in english should read “DevGirls.NET” or something like that.
I’m looking forward nothing but fun… :-)
Very simple questions as “How can I programmatically set my Page’s title from codebehind?” or “How can I handle my Page’s <head> element from codebehind?” were, are and will be asked about every single day in the public newsgroups, forums, etc.
This is because v1.x doesn’t include any built-in support for handling the <head> element or any of its children elements.
This leads to the common approach of adding the runat=’server’ attribute to the <head> element and then handling it as a HtmlGenericControl. Pretty simple and pretty unfriendly stuff at the same time. In addition, having VS.NET removing the attribute at will just make things more annoying.
After looking at all the feedback from newsgroups, forums, etc, it was pretty obvious that something was needed. Because of this, the HtmlHead control was born in the PDC03 bits (and others like HtmlTitle and HtmlLink did appear in the March04 bits). The Page type itself was modified to include these additions and new properties were added: Header (in the PDC03 bits) returns an instance of a type that implements IPageHeader (HtmlHead in this case) and Title (in the March04 bits) just wraps a Header.Title call.
So now, this is how you handle this very common need in the Whidbey bits:
void Page_Load (object sender, EventArgs e) {
this.Header.Title = “This is a title”;
this.Header.LinkedStyleSheets.Add (“classicblue.css”);
this.Header.Metadata.Add (“author”,”clarius”);
}
Pretty simple, ugh? No doubt, this is a good addition. Hopefully all the confusion and how-to questions that plagued the newsgroups about how to deal with this in v1.x won’t be there for v2.0 (now that’s a wish).
While playing with this new supported I discovered a few “issues” that I describe in these posts (warning: the following info may be more than you ever wanted to know about <head> and its child elements):
Whidbey Support For HtmlHead, Part I – What title will be rendered?
Whidbey support for HtmlHead, Part II – Not only VS.NET messes up your markup
Whidbey support for HtmlHead, Part III – The missing ViewState