# Wednesday, October 31, 2007

Since learning about the SubSonic project last week, I have spent a bit of time reading up on it, watching screencasts about it, playing with it, and reading the blog of its creator, Rob Conery. In his post "How MVC, jQuery, and SubSonic Will Make You Smile," Rob talks about the use of .NET 3.5's extension methods, in particular extending a Dictionary<string, string> to return HTML for a drop down list (HTML select); here is what his version of the extension method looks like:

 

 1: public static string ToHtmlSelect(this Dictionary<string, string> listItems, string name,
object selectedValue, object attributes)
 2: {
 3:  // input formats
 4:  string selectFormat = "<select name='{0}' id='{0}' {1}>\r\n{2}\r\n </select>";
 5:  string optionFormat = "\t<option value='{0}' {1}>{2}</option>\r\n";
 6:  
 7:  // output
 8:  StringBuilder sb = new StringBuilder();
 9:  
 10:  foreach (string s in listItems.Keys)
 11:  {
 12:  string selectedFlag = "";
 13:  string text = listItems[s];
 14:  string value = s;
 15:  if (value.ToLower().Equals(selectedValue.ToString().ToLower()))
 16:  selectedFlag = "selected=true";
 17:  sb.AppendFormat(optionFormat, s.ToString(), selectedFlag, text);
 18:  }
 19:  string result = string.Format(selectFormat, name, attributes.ToAttributeList(), sb.ToString());
 20:  return result;
 21: }



 

He also mentions that (on line 19) there is another extension method that "hangs off the object class" which basically enumerates all of the properties of an object, creating a name/value pair attribute list. He doesn't give the code of that extension method, which he states "is ScottGu magic at work and something he shows in his MVC demos." I have yet to watch those demos myself, but the code is probably something akin to this:

 

 1: public static string ToAttributeList(this object attributes) 
 2: {
 3:  StringBuilder sb = new StringBuilder();
 4:  foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(attributes)) 
 5:  {
 6:  sb.AppendFormat("{0}='{1}' ", property.Name, property.GetValue(attributes).ToString());
 7:  }
 8:  return sb.ToString();
 9: }

 

This allows you to pass anonymous types, specifying what might normally be optional parameters, a la something I have been doing in JavaScript for a while using MochiKit (other JavaScript libs exploit the same literal JavaScript object notation in their function signatures). The idea is that you don't need to have a structured method signature that accepts all possible options - you can pass in what you want to specify as a part of an anonymous object. This will make more sense if you have spent any time doing this in JavaScript or want to wait a moment and read on.

Anyway, the whole reason I was even posting on this subject is because of a comment made on Rob's post by one Joe Chung, wherein he states:

"Seeing StringBuilder-generated HTML makes me sad for the future of ASP.NET. Object-oriented ASP spaghetti code is still spaghetti code."

He is referring to the string hacking done in the ToHtmlSelect extension method. I too don't care for it, and simply wanted to show a nicer way of doing this, which leverages objects we already have access to in ASP.NET which do that grunt work for us.

Here is my version of Rob's method (which I still have issues with, but for now we will let those go for the sake of staying on topic) - note, there are no literal strings for those that despise them:

 1: public static string ToHtmlSelect(this Dictionary<string, string> listItems, object selectedValue,
object attributes)
 2: {
 3:  DropDownList htmlSelect = new DropDownList();
 4:  htmlSelect.Attributes.AddAttributes(attributes);
 5:  foreach (string key in listItems.Keys)
 6:  {
 7:  ListItem item = new ListItem(listItems[key], key);
 8:  item.Selected = (key.ToLower().Equals(selectedValue.ToString().ToLower()));
 9:  htmlSelect.Items.Add(item);
 10:  }
 11:  return htmlSelect.ToHtml();
 12: }

 

Now, my version does not use the ToAttributeList() extension method hanging off of  object - mine uses something a bit different, but an extension method nonetheless (although a bit naive, it will suffice for our purposes):

 

 1: public static void AddAttributes(this System.Web.UI.AttributeCollection attributeCollection,
object attributes)
 2: {
 3:  foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(attributes))
 4:  {
 5:  attributeCollection.Add(property.Name, property.GetValue(attributes).ToString());
 6:  }
 7: }

 

My extension method hangs instead off of System.Web.UI.AttributeCollection because my version of the ToHtmlSelect() method works with the System.Web.UI.DropDownList object, which uses that as the place to store its attributes.

The other key to mine is the following extension method which wraps a technique I have been using for over 2 years to create HTML (I didn't figure it out on my own, but can't remember where I saw this exactly - I think in the Google Group for the AjaxPro.NET component back when it was simply Ajax.NET):

 

 1: public static string ToHtml(this Control control)
 2: {
 3:  StringWriter sw = new StringWriter();
 4:  HtmlTextWriter htw = new HtmlTextWriter(sw);
 5:  control.RenderControl(htw);
 6:  return sw.ToString();
 7: }

 

Note - this can be used for all sorts of Control-derived ASP.NET HTML wrapper objects to get you some HTML without string hacking in your layers of code:

 

 1: Calendar c = new Calendar();
 2: string calendarHtml = c.ToHtml();

 

Notice Joe - no literal strings! That should make you happy (I know it makes me happy!).

Now, I love hacking JavaScript as much as the next guy (been doing it hardcore for the last 2.5 years even with ASP.NET because it is too much fun!), but hacking strings to create HTML is still not that fun. Even in JavaScript I don't do it if I don't have to, preferring to use functions that handle that for me (MochiKit has some simple DOM functions for handling HTML creation).

Anyway, hope this is of some use to someone out there!

 

Technorati Tags: , , , ,
Kick It on DotNetKicks.com
Wednesday, October 31, 2007 12:54:06 PM (Mountain Standard Time, UTC-07:00)
Hey Jason- thanks for writing this up. I need to spend a lot more time with extension methods - the one you specify here is one that I wrote up in 15 minutes for the demo... and need to refactor.

Tell ya what - see if you can tweak your CSS so the code is readable (wrap it in a code or xmp tag) - I'd love to add it to the source if you'd let me! Or just email it to me (myname@gmail.com)

Power of Open Source! Yeeha!
Wednesday, October 31, 2007 1:26:46 PM (Mountain Standard Time, UTC-07:00)

Hey, no problem - I understand; I was simply doing it for the exercise more than anything, since I rarely expect anyone to read my blog!

I rarely post code to this blog (something I need to do more of) and didn't know it was going to blow up on me. I am using Windows Live Writer and some code insertion plugins, but apparently they are not working as well as I was expecting.

I will email it to you, who knows when I will have time to fix this. :P

Wednesday, October 31, 2007 1:32:41 PM (Mountain Standard Time, UTC-07:00)
Ahh - much better :). OK so now we have the the Renderer creating the HTML for us - what do we gain by going through the abstraction? Is the HTML that difficult? Or... ?

Wednesday, October 31, 2007 1:50:10 PM (Mountain Standard Time, UTC-07:00)


Well, we get no literal strings, which I personally find nice (the abstractions are less error-prone than your strings, which a stray keystroke can mangle).

The other thing is that you can get, for free, culture-based specialization. Take the Calendar control example I show for example - if I simply change the culture of the page I am rendering the calendar against to "es-MX" (this.Culture = "es-MX"; in the Page_Load), I automatically get a calendar that uses Spanish.

Also, I get controls that can change their HTML based on the requesting client's capabilities (i.e. browsercaps, see adaptive rendering).

I don't have to worry about that or code that chooses different strings based on that - this has been written by the ASP.NET team already, why would I want to do it again?

Thursday, November 01, 2007 5:30:06 AM (Mountain Standard Time, UTC-07:00)
you're asking us to trust asp.net with our web development. i'm not saying that's improper, but trusting asp.net is exactly what got us into this mess to begin with.

we find ourselves at a "liberal" vs. "conservative" paradigm in the asp.net world.
Thursday, November 01, 2007 8:16:02 AM (Mountain Standard Time, UTC-07:00)
Matt,

Exactly where along the range of what is acceptable to you do you want to place your bets? If you are using ASP.NET at all, then you might ask yourself the same question: Should I trust ASP.NET to handle the processing of anything? I mean, if you want to take the idea far enough (without going all the way to total abandonment), you could end up rewriting the ASP.NET framework as a whole. And then you wouldn't be able to expect anyone else to trust what you have written, because who knows what you might do next?

Live the religion - either you use ASP.NET or you don't. Granted, there are a million shades of gray in between, but you gotta draw the line somewhere. I don't think Microsoft is going to royally screw up something as simple as an object model for a DropDownList and the HTML it spits out.

But whatever works for you - trust me, I am the last person that would simply swallow, whole, whatever Microsoft vomits up; that's why I don't use their current Ajax framework or (directly) their data access technologies (read: DataSets and their ilk). You gotta do whatever helps you sleep at night. :P

Friday, November 02, 2007 9:24:00 AM (Mountain Standard Time, UTC-07:00)
i certainly didn't mean to demean your neat methods (although i can see how ignoring your content and focusing on the meta-discussion was impolite - my apologies).

i dunno man... it's murky. and i surely don't have the answers. they've started a "movement" over this debate: the alt.net thing. and i went to the conference and it was a bunch of dudes standing around and generally feeling uneasy and unsure but being very very smart. so i trust that people, the community, will continue to push both edges and make mistakes and figure out exactly how far they can go in either direction without losing too much time, money or sanity. and the pendulum will swing back and forth.. and microsoft will be there, nudging it to it's peak before it swings back the other way. and we'll all get paid and we'll all do cool work and we're all happy because our careers happen to be our hobby.

at any rate, we are in agreement.. that strings in code are generally bad ideas. very nice stuff.
Friday, November 02, 2007 9:26:27 AM (Mountain Standard Time, UTC-07:00)
ps: browsercaps is the devil =)
Friday, November 02, 2007 3:57:57 PM (Mountain Standard Time, UTC-07:00)
Matt -

No worries - I enjoy getting opposition to my code and my ideas; I am mature enough to realize that I don't know as much as I would like to think I do, and that the only way to improve is to engage in discussion with other intelligent people (heck, even discussing things with seemingly unintelligent people can be productive with the right attitude!). I appreciate your comments.

I am well aware of ALT.NET and sorely wish I could have been at that conference; I am jealous! I constantly rant (not on this blog, but with like-minded co-workers (which are few and far between)) about the failings of Microsoft and the majority of developers using their tools. It amazes me how so many people unthinkingly tie themselves into tools and/or process that they have no control over or understanding of. Granted, as I stated before, there is only so far one can take that principle before you end up writing code in ones and zeroes because you don't want to lock in to a specific platform. :)

Definitely happy doing what I am doing - I don't know how people go to a job they hate, I would find that near impossible.
Monday, November 05, 2007 11:20:48 PM (Mountain Standard Time, UTC-07:00)
So what are your thoughts on Subsonic? Good, bad, meh?
Tuesday, November 06, 2007 10:26:06 AM (Mountain Standard Time, UTC-07:00)

I have not had enough time to evaluate SubSonic enough to make any meaningful comments. I have an aversion to the whole Active Record pattern in general, but my reasons are not solid enough to mean much; the only stipulation I have in using the Active Record pattern, if I have to, is that the implementation makes use of dependency injection so that the persistence details are easy to change.

I am actually working on a small project right now with a coworker for which we are using MonoRail, so I don't know if I will really take the time to use SubSonic until it is using the new MVC stuff coming out of MS. If I do use it, I will try to blog about it - though considering my blogging frequency, might not ever happen...

:)

All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, i, strike, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview