I recently I had a job interview w/ Costco Wholesale in the e-Commerce group. I thought the most interesting question they asked was "If you could change one thing about ASP.net, what would it be". It was a hard question, because on the whole, I'm pretty happy with it. Furthermore, on the whole, I'm pretty happy with the direction that Microsoft is going. However, it got me thinking about what I don't like about Microsoft's internet platform and I figured it would make a great blog post (or two), so here I go.
Viewstate + ClientID = HTML Bloat + Slow. I don't think the ASP.net forms model is bad; it just makes it much more difficult than necessary to produce small HTML markup in the typical case. For example, let's say I have ASP.net code something like this
<form runat="server">
<asp:Repeater ID="rptCards" runat="Server">
<ItemTemplate>
<asp:Image ID="CardFace" runat="server" /><br />
<asp:Label ID="CardName" runat="server" /><br />
</ItemTemplate>
</asp:Repeater>
</form>
And then I data bind a playing card to my repeater in the code behind file, which ASP.net proceeds to render it as this…
<form name="ctl00" method="post" action="form.aspx" id="ctl00">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwULLTEyODIyNzUwMDAPZBYCAgEPZBYCAgEPFgIeC18hSXRlbUNvdW50AgEWAmYPZBYEAgEPDxY
CHghJbWFnZVVybAUTL2NhcmRzLmFzcHg/Y2FyZD00NmRkAgMPDxYCHgRUZXh0BQ9RdWVlbiBvZiBIZWFydHNkZ
GQAQrEoOi46tPS8NZ9nekUDim2+Mg=="/>
</div>
<img id="rptCards_ctl00_CardFace" src="/cards.aspx?card=46" style="border-width:0px;" /><br />
<span id="rptCards_ctl00_CardName">Queen of Hearts</span><br />
</form>
What's with the <div> surrounding the __VIEWSTATE control? Where did that style="border-width:0px;" come from? Why is there so much damn view state? Why do my Image and Label controls render IDs on the client? And why is it named rptCards_ctl00_CardFace instead of something shorter, such as rptCards_0_CardFace?
Sometimes I have nested repeaters, sometimes I don't. Sometimes I use HTML controls instead of Web Controls, but the issue is the same. The elements in question aren't getting changed on the client and only get changed on the server during the initial HTTP GET during data binding. Normally, the __VIEWSTATE just grows & grows as I add more stuff to the page. OK, you can avoid this by a few well placed EnableViewState="false" or disabling it altogether in web.config. Unfortunately, I don't always know when you really need it, so often times I end up disabling it on a control by control basis in a trial and error fashion, until my app works and my markup is small. Unless you truly understand viewstate, you could end up meeting a fatal end with ViewState-ious of Borg. Fortunately, I understand that problem.
What bothers me more is ID bloat, especially when you nest Repeaters, so an innocent looking <asp:Hyperlink> control ends up with an ID like...
rptMerchants_ctl01_rptShippingMethods_ctl00_rptLineItems_ctl00_ProductName,
That's ugly, so I end up using shorter IDs for Repeaters. Unfortunately, that's not good enough at times, so I usually end up replacing many of my server controls with <asp:Literal> controls and controlling my markup directly. Unfortunately, doing that stops you from using the server control you really wanted to use, and makes complex page development a huge pain.
Ideally, what I'd like is a RenderClientIDs="false" attribute for all ASP.net server controls. After all, the ID isn't sent to the server on the postback (just name / value pairs from form controls). You really only need it on the client if you are doing client side DOM/DHTML manipulation. I know you need a Control ID as a parameter to __doPostBack, but I usually don't need it on the client side HTML markup. It also seems odd that ASP.net is missing a RenderClientIDs attribute since they did have the foresight to create an EnableViewState attribute on server controls.
Most of the time, a Hyperlink control is just an <a> HTML tag, a Label control is just a <span> HTML tag, and an Image control is just an <img> HTML tag, so the ID attribute is just byte bloat running up my bandwidth bill. Why is it so hard to just get this instead?
<img src="/cards.aspx?card=46"/><br />
<span>Queen of Hearts</span><br />
Is there a diet control library I don't know about or some magic web.config setting to stop unneeded ClientIDs from rendering? How does one fight ClientID bloat? Should I just wait for an MVC version of ASP.net? I'm kind of lukewarm on the whole MVC thing because of ignorance and the lingering bad taste of classic ASP. I don't mind paying the ASP.net tax, when it adds more value than byte bloat. It just annoys me, that I have resort to <asp:Literal> controls to avoid paying the ASP.net tax in some cases.
So what are the downsides of MVC ASP.net vs Classic ASP.net? Will my favorite 3rd party ASP.net web control product work on it? Do I just need to read Phil Haack's blog and Scott Hanselman's blog more often? Any idea when an MSDN event will cover MVC ASP.net? Oh well, it beats tracking down memory or COM interface leaks in an ISAPI application for a living.
Print | posted on Friday, January 11, 2008 11:56 PM