Web standards with ASP.NET
Good interface code is a mix of CSS and HTML, and while most frameworks offer full control over the CSS, they rarely offer that for HTML. This article looks at how ASP.NET developers can help their interface developers gain that control. Disclaimer: I'm no .NET expert, but too few people write about this stuff, so I'll make a try.
Controls that keep the HTML customizable#
Splitting pages into "controls" is a common way to build sites in ASP.NET. There's lots of different kinds of controls available, and I can't list all of them or name their differences. But I know I don't want to compile a .cs file every time a change some HTML. That pretty much rules out anything but user controls (as far as I know, but any kind of control that fills the above requirements would do). User controls have two sides, one for C# code (code-behind), and one for tags (HTML and calls to other controls).
There's also the issue of built-in stuff. ASP ships with many pre-built controls that help developers push out things quickly, the problem is that almost all of them neglect the HTML (DataList, GridView, …). They only allow setting a few properties, sometimes a CSS class, and assume that's OK. It isn't. I need full control over both the CSS and the HTML to be productive. There's one tag in particular is built with my kind of mindset, and that's the Repeater. A repeater is used like a for loop, but outputs no HTML itself. Instead it allows you to specify some code to output before the loop, inside the loop, every other step, and afterwards. That goes a long way, and that's often enough. If the predefined templates are insufficient, like if you want the last item to be rendered differently, you're out of luck.
I think I agree with the MVC Framework guys in how to solve missing parameters of default controls and bad output: Use C# code inside your templates. Why is this different than the spaghetti code of old ASP? Because you only use layout related logic, nothing else. People tend to think mixing C# and HTML looks messy, but isn't it stranger to make two very different things look the same?
There's also tags like asp:hyperlink, asp:label, and so on; tags that essentially does exactly the same as the HTML they're hiding. Please don't use them, there's no abstraction layer needed for HTML.
Don't repeat yourself - not even in the interface code#
Often when developers move from writing C# code to writing interface code they throw their coding skill out the window. You never copy a C# method just to make it output a different number - you make that number a parameter to the method instead. In the same way, you should never copy a piece of HTML from one place to another - move that code to a common masterpage or usercontrol instead. I've seen this many times, even from experienced developers. Never copy code, it makes for nightmare maintainance.
Also, use nested masterpages. So if you have three pages you need to build, and they have some code in common, you break that common code our into a masterpage. If two of the pages have even more in common you break that out into another masterpage, and let that one use the first one you made. Each Aspx page should only contain what makes it different from the other pages! Repeated HTML can also come in the form of small snippets of code, maybe 10 lines. You might not be able to break that out into a masterpage because it shows up all over the place. For those cases, break the snippet out into a usercontrol instead, and call that. Simple, and DRY.
Disable viewstate#
HTTP is by default stateless. That means that each HTTP request to the server knows nothing about all the other requests made. For scalability and performance, that's a great thing. By default, ASP.NET makes web development stateful. Every form field you fill out gets saved into a hidden form field, called viewstate, and sent with every request. But I'm not talking about performance here, I'm talking about interface development:
To be able to save state across requests there's a hidden form field, and to be able to send that with every request there needs to be a form covering all your form fields. I can't help to think that handling statefulness in the HTML (the view) is the wrong place to do it. Aside from taking away some of my control over the HTML, it also has accessibility issues. JAWS, a popular screen reader, switch to a different reading mode when inside of forms, and while it's possible to get to all content inside a form, it's harder.
So, start by disabling viewstate by default. If you must have it for a certain control, only enable it for that control.
Summary#
There's lots of stuff you can do to make the HTML look better with ASP.NET, and that's a good thing. The bad thing is that it isn't that way by default. Now get out of here and go build some good HTML :)
Comments
By: Nick Dunn (#1)
- Set the xHtmlConformanceMode to "strict" in the Web.config. This way, even if you do use server controls which generate a lot of HTML, it will at least be valid.
- Don't write off the ASP:Label control. It's main purpose is for form labels and it achieves this very well. Using an ASP:Label and ASP:TextBox pair will generate the same HTML markup I would write by hand anyway (except the auto-generated ID/name attributes).
The ASP:Label control becomes confusing when no AssociatedControlId is set, as it outputs a SPAN rather than a LABEL to the HTML.
The two most powerful server controls for the standards-aware developer are the ASP:Repeater (as you mentioned) and the ASP:Literal. The latter is simply an empty placeholder into which you can stuff any text or HTML.
Avoid the Validation server controls like the plague, if you care about markup. Adding a validator will add an onsubmit() handler to your form, and force the client to download a ton of JavaScript.
ASP.NET is incredibly powerful and indeed web-standards compliant. But only in the right hands :-)
By: Emil Stenström (#2)
The same with asp:literal, you could use <%= text %> instead if you wanted.
No matter what, I don't think that distinction is too important. As long as you know what you're doing and care about the HTML.
By: Martin S. (#3)
- CSS adapters for better semantics: http://www.asp.net/CssAdapters/
- How to control adapters: http://www.singingeels.com/Articles/How_To_Control_Adapters.aspx
Btw, use Literal instead of Label when you need to output text from codebehind, unless it should be - then you can use the AssociatedControlId attribute. And PlaceHolder is always better than a Panel. The Panel creates a wrapping div, which PlaceHolder does not.
By: buckley (#4)
"Maybe the most important feature of this control is that like the Repeater control it provides much more control over the rendering process at the cost of more markup code in the page."
By: Emil Stenström (#5)
By: Anna Kolesnik (#6)
thank you
By: Alan Cyment (#7)
Cheers,
Alan
By: Scott (#8)