ASP.NET WebForms Without The Suck

Time to Ruffle Some Feathers

ASP.NET MVC gets all the notoriety these days in the Microsoft web-programming world. ASP.NET WebForms is kind of the ugly stepchild, sitting in the back corner, mostly neglected. “Did you see WebForms last week? He was awful, just awful,” say the voices at the party. “But MVC! MVC is sooo elegant. And so smart! Did you hear she was given early admission at Dartmouth?”

Now, I’ve been coding for thirty years, and I’ve seen a lot of technologies, languages, and environments come and go. And Microsoft is a major, major offender in this category: They have a tendency of building these big, awful, overarching frameworks that make the U.S. Federal Government look under-managed, and then they drop them as soon as the Next Big Thing comes along. MFC was a horrendous mishmash of bad ideas that all managed to somehow end up in one ball of code. COM was a fever-driven acid nightmare that the computer industry has thankfully mostly wakened from. And VB — do I really even need to explain why VB is bad?

Which brings us to ASP.NET. Now I know that the original goal with it was to bring the VB WinForms programmers to the web and get them the heck off of the junky VB/C++/COM conglomerations that were killing Microsoft’s own abilities to fix issues in Windows itself. To that end, they came up with some clever abstractions that made the web sort-of vaguely smell like Windows programming for programmers who weren’t really clever enough or willing enough to get with the future.

And if you were offended by that last sentence, then you can stop reading right now, because this article is not for you.

Trust Me, I’m Not a Doctor, But I Did Stay at a Holiday Inn Express Last Night

I started coding ASP.NET about five years ago after a long history of coding HTML by hand on Un*x systems. My server-side code was first done with M4 macros, and then raw C programs, and then Perl, and then PHP. I come from an open-source background, so you better believe that when I was hired to do ASP.NET WebForms, I was skeptical. Really skeptical. Really skeptical.

And at first, my skepticism was justified. There was a lot of overarching stultifying monolithic framework crap in ASP.NET. It had abstractions that weren’t just bad, but that were badly engineered. Dear Lord, they used tables for layout even when just rendering radio buttons? And this monstrous page lifecycle thing? And ViewState? And ControlState because ViewState wasn’t good enough? And a zillion lines of ASP.NET Ajax to do nothing? Were they on crack when they wrote this? (And it didn’t help that my initial exposure was entirely through people who were die-hard and clueless Microsoft apologists, either: They didn’t know why they were promoting the FormView, just that Microsoft offered it and therefore it was a Good Thing.)

But —

After some years of working with it, I’ve found that there’s more to WebForms than what I saw at first blush. All of the concerns that people tend to poke at in WebForms — the page lifecycle, the ViewState, the control IDs, the bad built-in controls, the single-form-for-everything, the bizarre Ajax support — they’re all real concerns, but they can all either be worked around, avoided, or aren’t as relevant as they initially seem. Microsoft’s literature doesn’t help the perception that WebForms can be a modern web programming environment, and the third-party control vendors make that perception even worse, but it really can be modern. Really modern.

Ajax-friendly, high-speed, CSS-layout-driven, HTML5-compliant sites can be built in WebForms, but you have to look at WebForms differently.

WebForms: The Good Parts

What does WebForms do well? Abstraction. Ruby on Rails, CakePHP, ASP.NET MVC — these are all about removing abstraction. Getting you closer to the metal. And that’s fine if that’s where you want to be; if you want to hand-write every <div> and <span> in your website, by all means, go for it. But the rest of us have real problems to solve: We don’t want to think in terms of individual <li> elements; we want to think in terms of menus and dropdowns and popups. We don’t want to think about <table> elements; we want smart grids with sorting and paging and filtering and all sorts of dynamic content.

WebForms manages to get a lot wrong, but the one thing they did the most right was to create the Control tree: Building up a document not just from individual atomic elements like <div> and <span>, but from bigger concepts like Grid and Pager and Chart and Menu. <div> and <span> can wrap those bigger concepts, and be embedded within those bigger concepts, but you try to express your markup as high-level concepts that match your domain instead of low-level concepts that match what HTML offers. WebForms doesn’t prohibit you from using <div> and <span>; it just encourages you to try to think at a higher level whenever possible.

I think that’s by accident: I’m pretty sure it wasn’t their intent; Microsoft’s goal was to just wrap up the web in things that smelled like VB controls. But a clever abstraction was what they really created, and it’s what no other environment I’ve found yet offers.

WebForms: The Bad Parts

WebForms has craptacular built-in controls. ListView and GridView and dear Lord, FormView, what were they smoking when they made these things? Even things like LinkButton and Checkbox are just awfully designed, inflexible, and emit terrible markup. And a major part of the complaints about WebForms is based not on WebForms itself but on its awful, awful built-in controls, which give you the worst of both worlds: Lack of control and lack of flexibility. The third-party control vendors just pile on top of that, adding things they think will sell rather than trying to resolve those native deficiencies.

WebForms also has its “page lifecycle.” Now, running 97.3 million stages of execution per page load is kind of a bad idea. But computers are faster than they used to be, and the performance argument is a lot weaker now. A bigger issue is that of comprehension: PreInit-Init-PreLoad-LoadViewState-Load-LoadViewStateAgain-PostData-RaiseEvents-PreRender-Render-Unload is a heck of a lot to remember, and I may have even gotten the order of a few of those wrong. Another big issue is the weird catch-up logic that skips some stages but not others when controls are dynamically created. And the fact that the Page itself runs these rather than the controls individually doing it. All of the well-known page-lifecycle issues could have been avoidable with a different, much simpler design (you really only need Load/Post and Render), but this is what we have. Thankfully, you can avoid most of it, and work around the problems introduced by the rest.

And then there’s ViewState. This is one of those things that isn’t necessarily a bad thing, but it’s been abused so much that people give a knee-jerk reaction to it. Having hidden fields on your page to remember state isn’t a bad thing. MVC websites do it. Rails websites do it. PHP websites do it. They just all do it explicitly. ASP.NET WebForms just makes it so trivially easy to add data to a hidden field that people tend to jam everything and the kitchen sink into it and then gripe when their resulting HTML is measured in gigabytes. And again, this isn’t helped by the fact that the built-in controls tend to automatically add data there as well in an attempt to make the web seem more stateful than it really is. But ViewState isn’t inherently evil; it’s just badly used and badly misunderstood. Other websites do the same thing, just by a different name.

And don’t get me started on the incredible silliness that is the UpdatePanel.

Whither Then?

I’ve said more than once that with ASP.NET MVC, they threw out the baby with the bathwater. WebForms had some good things, and you lose those in MVC. It’s possible to make WebForms good. Not easy, but possible.

I say that because in my current job, I’ve been doing exactly that for the last five years.

We have a massive website built entirely around WebForms. More than 400 pages and around 250 user controls. And it’s modern.

We really do target HTML5 Standards. Nearly every page uses Ajax somewhere. We have big, complicated grids that are a joy to both build and use. It uses a sophisticated security model where even individual elements can be sliced and diced out for individual users. There are popups, dropdowns, dialog boxes, and dynamic content everywhere. jQuery is the foundation for its JavaScript. The JavaScript uses modern modules and careful namespacing. Sass is the foundation for its CSS. We have controls that emit clean markup, purely styled by CSS, and purely powered by unobtrusive JavaScript.

How we got to here wasn’t easy. It was a really bumpy road. Most of the native ASP.NET WebForms controls were left on the sidelines in favor of our own (we did extend some where possible, but we wrote our own where the existing ones were simply unusable). We had to introduce some new completely concepts like our AjaxPanel and a radical new data-binding technique and a custom routing engine and a custom security model.

But the point is: We did this all without MVC. And, in fact, some of the things we’ve built — like our grid control and AjaxPanel — would be nearly impossible without the Control tree and the page lifecycle. Deep under the hood of WebForms, beyond the bad controls and the insane business-driven design decisions, there’s a really elegant framework struggling to get out. MVC may get all the notoriety, but the ugly duckling has the ability to be a swan.

You might wonder why I’m talking about this: Why not just jump on the MVC bandwagon? Aren’t I only talking about this because of the investment my company made in WebForms? Well… no. WebForms isn’t actually a bad thing, and I want to show how it can become a modern web development environment. There are a lot of sites I would far rather build in WebForms than in MVC, sites that would take far less time to build in WebForms than in MVC.

In an upcoming series of blog postings, I’m going to begin talking about the pieces of a better WebForms. I built this stuff once already for our company, and I can build it again without referencing any of our proprietary code. Ideally, I’d love to share exactly what we did, but if I have to build it again to avoid intellectual-property issues, I can certainly build it again. And by convincing you all that WebForms doesn’t suck, I do indirectly help my company, too, by increasing the potential pool of hirable candidates, and also by showing current candidates that we’re not behind the times but going a different direction by choice.

So if you’d like to know what I’ve been doing for the last half-decade, or you’d like to know how to make WebForms sites that don’t suck, stay tuned.