Monday, October 31, 2005

Long Weekend

I had a fairly long weekend, in both senses of the word. I can't complain, though: it was much better than others', as I'll explain in a moment.

 

Friday was my daughter Ellen's first birthday. It's hard to believe it's already been a year; my aunt used the expression "Long days, short years" and I have to say I find it apt. Ellen is an absolute riot. I swear she gets more fun to hang out with by the hour.

 

My wife is getting her MBA at Wharton, and Friday was one of her class days. So I planned to take Ellen up to Philadelphia so she wouldn't have to miss Ellen's birthday. Additionally, Alice's parents were staying with us, and I need to drop them off at the airport that same morning. Ellen and I took the train, so already a fair amount of running around was on the schedule, especially given our plans to co-host Ellen's joint birthday party on Sunday with some friends whose daughter was born just a week after Ellen. No big deal, though - just par for the busy parent course.

 

The level of insanity jumped from "parents of toddler" to "Rory" at about 2AM Friday morning, though. That's when we got a call from the police letting us know that our good friend Alex had been hit by a car. He was riding his bike home from helping a friend move, and the dirtbag that did it drove off without stopping, leaving Alex lying in the street.

 

Alex is a triathlete, who has competed in several Ironman events just this year, including the big one in Hawaii. If you're not familiar with Ironman (Wikipedia entry), it consists of a 2-mile swim, followed by a 112-mile bike, followed by a 26.2-mile run. That's right - it ends with a full marathon.

 

Anyway, all this is to say that Alex has probably biked almost 7000 miles just this year, all of it with a helmet. And of course, this time, on a short one-mile trip home, he wasn't wearing one. Fortunately, Alex was not killed. He didn't even suffer any head injuries. He did get hurt, though, and not in a small way: several ribs broken, two seriously; a broken collarbone; and worst of all two fractured vertebrae, one of them basically crushed.

 

The prognosis for Alex's full recovery is quite good. Even now, just three days later, he can walk, even up and down stairs, albeit very, very slowly and with a cane. He'll need to wear a back brace for several months, and it takes him a long time to get in or out of a chair or a bed right now. We've all wondered where he'd be at if he weren't in essentially perfect physical condition before he got hit.

 

Getting hit by a car will generally always ruin your day, but this already hasn't really been his year. He lost his job after getting screwed by an unscrupulous consulting company, his visa to stay in the US is expiring, his landlord is selling the house he's living in, and perhaps worst of all he has no health insurance. Yikes.

 

He was released from the hospital yesterday. Of course, we insisted that he come to stay with us. It works well because either Alice or I are basically always at home. Should anything happen, he won't have to lie at the bottom of the stairs for six hours waiting for someone to come home. And we're glad to help.

 

Anyway, like I said, a crazy weekend. I had planned to do a post about what I've been up to work-wise, but when you work at home a lot, your work and personal lives tend to blur together a bit. So I thought I'd start here - sometime soon I'll do the complementary post.

Monday, October 24, 2005

Master of Pages

My buddy Jason Whittington wrote this fantastic set of lyrics to the tune of Metallica's "Master of Puppets". Check it out:

 

Master of Pages
==========
 

In your darkest day, Child Controls array
Try to use SqlConnection
Children disappear, code-behind not clear
Too much Stylesheet distraction

 

[chorus:]
Write me and you see
I am all you need
You provide the views
I am calling you

 

Your site is plastered
Obey your master
Your page loads faster
Obey your master
Master

 

Master of pages is pulling your strings
Formatting output, displaying your themes
Without placeholders you can’t see a thing
Just call my name, 'cause I’ll hear you scream
Master!
Master!

 

Just call my name, 'cause I’ll hear you scream
Master!
Master!

 

Try to do your bit, Handle PreInit
Binding to a data table
You've been led astray, data won't display
Worker process grows unstable

 

[chorus]

 

Master, master, where’s the page that I’ve been after?
Master, master, now my server dies

 

Laughter, laughter, all I hear and see is laughter
Laughter, laughter, laughing at my cries

 

Now your viewstate's fat, didn't use the cache
Do you really need more reason?
You're lost in the maze, Come to righteous ways
.NET 2.0's in season

 


I will lead the way
I will make you pay
You will start anew
Now I rule you too

Saturday, October 22, 2005

Galleon + Tivo = Nice

I noticed recently that my Tivo started displaying a new menu item: "Enable Home Network Applications". Encouraged by the implications, I did a a little research and I ran across Galleon at SourceForge. I downloaded and installed it, and I have to say, it's ever so nice.

 

Despite a clunky interface typical of open source (and of Java apps), I didn't have too much trouble figuring out how to set up true two-way integration between my PC and the Tivo. I can now move shows back and forth, controlling the process from either the Tivo or my PC. This basically allows me to use the PC as both an archive/backup and a second TV. You can even set up rules so that certain shows are automatically downloaded to the PC.

 

Of course, I'm only scratching the surface of Galleon. It's really more a Java-based platform for writing custom Tivo apps than it is a transfer program. I've played around a bit with a few of the plugins that ship with the program, but haven't fully plumbed the possibilities. So far, my favorite is the podcast plugin. I like being able to listen to any episode of Science Friday in the living room on demand - it brings the Tivo experience to radio.

Friday, October 21, 2005

IList<T> Won't XmlSerialize!

So as long as we're talking about XmlSerializer bugs, let me point out a really, really bad one: if your type has members of type IList<T>, it won't serialize! Aagh! What's worse is that Microsoft has decided not to fix this bug until after 2.0. Crap!

 

OK, I can sort of understand that not everyone uses XmlSerializer directly as their XML API of choice (as I do). So maybe if people like me were the only customers who would be affected by this problem they'd be justified in saying "we'll fix it later". But I'm not: XmlSerializer is used by the ASP.NET web services infrastructure. So if you were thinking of using IList<T> properties from your web service parameter types…forget it. Won't work. Guaranteed to be busted in v2.0.

 

Of course, it's not the end of the world. Generated collection classes (I use CodeSmith) have been an option for typesafe collections since v1.0. But generics were supposed to free us from those, not just give us a slightly more efficient way to implement them.

 

This bug has me pretty annoyed right now, but maybe I'm just moving my way through The Circle of (Software) Life.

 

Update: OK, this isn't quite as bad as I thought. It turns out that List<T> will serialize just fine. However, FxCop complains about List<T>, and if you've ever tried to use FxCop, you know that dealing with exclusions is often more trouble than it's worth. Fortunately, the FxCop violation that got triggered suggested using either Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<T> instead. As you know, I've already worked a bit with KeyedCollection<T>…suddenly System.Collections.ObjectModel seems even cooler.

 

Anyway, once I switched over to using Collection<T> (the appropriate choice in this case) everything serializes correctly. Woohoo! I'd be happier with support for IList<T>, but I can totally live with this.

 

I hope you don't mind my constant updates. I was going to be embarrassed about having to constantly correct myself, but then I remembered that this blog is nothing if not a public record of the fact that I still haven't managed to learn everything there is to know. :)

Wednesday, October 19, 2005

Serializing a KeyedCollection

The other day I pointed out System.Collections.ObjectModel.KeyedCollection. Towards the end, I claimed that you could use XmlSerializer to serialize an instance. Well, it turns out this is only true if you use System.String as the key type. For some reason, the serializer barfs with "The given key was not present in the dictionary" when you try to serialize a collection that's keyed off of any other type. Or at least, any of the other types I tried.

 

I'm not sure if this is a serializer bug, an issue with KeyedCollection, or if it's a by-design limitation for some subtle reason. I know I'd sure like it if it started working in the RTM version of Whidbey.

 

Update: Astute readers Aaron and Bart figured out that this is due to a bug in XmlSerializer (a bug which made #1 on the MSDN Product Feedback Center). Apparently XmlSerializer calls the object IList.this[int index] indexer, rather than the type-specific indexer. Fortunately, there's an easy workaround: just add an new indexer which hides the indexer in the base class. Modifying my earlier example, you'd do this:

 

class People : KeyedCollection<string, Person> {

   protected override string GetKeyForItem(Person item) {

      return item.Name;

   } 

 

   public new Person this[int index] {

      get { return ((IList<Person>)this)[index];

   }

}

 

I've put the new code in bold. Of course, it already works when string is the key type, but you get the idea. The key here is the "new" keyword on the method, which makes this indexer hide the indexer in the base class, causing it to be used instead.

 

I've included a more complete sample below that uses a DateTime (birthday) as the key type instead of a string. Note that (as far as I can figure so far) you can't use an int as the key type, because that conflicts with the positional indexer already exposed by IList<T>. And it makes sense - if I were representing age as an integer, and my age were 33, how would I know whether people[33] meant "the 33rd person" or "the person with age 33"?

 

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.IO; 
using System.Text;
using System.Xml; 
using System.Xml.Serialization; 

namespace SerializeKeyedCollection {
    class Program {
        static void Main(string[] args) {
            // Set up a collection with two people in it
            People people = new People();

            Person craig = new Person();
            craig.Name = "Craig";
            craig.Birthday = new DateTime(1971, 11, 29);

            people.Add(craig);

            Person alice = new Person();
            alice.Name = "Alice";
            alice.Birthday = new DateTime(1973, 11, 3);

            people.Add(alice);

            // Serialize the collection to a string
            StringBuilder stringBuilder = new StringBuilder();
            StringWriter stringWriter = new StringWriter(stringBuilder); 
            XmlSerializer ser = new XmlSerializer(typeof(People));
            ser.Serialize(stringWriter, people);

            // Print out the serialized collection
            string xml = stringBuilder.ToString();
            Console.WriteLine(xml);

            // Deserialize the collection to show that deserialization works
            StringReader stringReader = new StringReader(xml);
            people = (People) ser.Deserialize(stringReader);

            DateTime birthday = new DateTime(1971, 11, 29);
            Console.WriteLine("Person with key 11/29/1971 is {0}", people[birthday].Name); 
        }
    }

    public class Person {
        private DateTime _birthday;
        private string _name;

        public DateTime Birthday  {
            get { return _birthday; }
            set { _birthday = value; }
        }

        public string Name {
            get { return _name; }
            set { _name = value; }
        }
    }

    public class People : KeyedCollection<DateTime, Person> {
        protected override DateTime GetKeyForItem(Person item) {
            return item.Birthday; 
        }

        public new Person this[int index] {
            get { return ((IList<Person>)this)[index]; }
        }
    }
}


 

Friday, October 14, 2005

Thread.IsBackground

I've been doing some code reviews recently, looking in particular for threading issues. It's particularly important in this case because the code in question is a service that needs to run for a long time under high load. It also needs to shut down gracefully if something wonky happens.

 

One of the things I noticed was some weirdness in the OnStop method of the service, where it iterates through its child threads and tries to get them to shut down gracefully, calling Abort if they won't. Since it turns out that everything important is protected by a database transaction anyway, I suggested a shift to a slightly different model: set it up so it doesn't matter if the threads stop at all.

 

Part of doing this involves changing the threads to run as background threads. A background thread is represented by a System.Threading.Thread object like any other thread in the CLR, but it has had its IsBackground property set to true. When you do this, you're saying, "It's okay if the process shuts down while this thread is still running." You may have encountered this already if you've ever used the .NET thread pool for anything - all of its threads are background threads, so even if one of them is still doing something, as soon as your last non-background thread goes away, the process dies.

 

Of course, every effort should be made to ensure that the threads exit cleanly, since proper cleanup is better than whatever automatic cleanup you get when a process dies. But this change should at the very least help the service from hanging on shutdown, which makes it easier to support.

Tuesday, October 11, 2005

System.Collections.ObjectModel.KeyedCollection

I spend a lot of time dealing with collections when I code: should this thing be a list? An enumeration? A hashtable? Decisions about data structures abound. Which is one of the reasons I like Whidbey so much - the new support for generics makes life in the collection world ever so much nicer. But the other day I was poking around and came across System.Collectons.ObjectModel - a sister namespace to System.Collections.Generic, and one I hadn't heard much about. But it makes the story even better.
 

There's not a whole lot in the namespace at the moment. Just three classes: Collection<T>, ReadOnlyCollection<T>, and KeyedCollection<T>. Collection<T> and ReadOnlyCollection<T> are pretty obvious - they provide simple collection and read-only collection wrapper functionality. Handy, but my favorite is KeyedCollection<T>.

 

KeyedCollection<T> is an abstract base class that gives you that Hashtable/ArrayList crossover class you've probably written at least once in your life. That is, it gives you list semantics, but adds a non-integer indexer for doing lookups in the collection. So, for example, if you have a Person class that looks like this:

 

class Person {

  private int _age;

  private string _name;

 

  public int Age { get { return _age; } set { _age = value; } }

  public int Name { get { return _name; } set { _name = value; } }

}

 

All you need to do is create a collection like this

 

class People : KeyedCollection<string, Person> {

   protected override string GetKeyForItem(Person item) {

      return item.Name;

   } 

}

 

where the implementation of GetKeyForItem is whatever makes sense. It's the only method you need to override, because without it, the collection has no idea what the key is. But once you do, you can now access the collection as follows:

 

People instructors = Pluralsight.Instructors; // Acquire a collection from somewhere

 

Person craig = instructors[7];        // Can access by index

Person keith = instructors["Keith"]; // Or by name

 

In addition to being convenient, the documentation also suggests that KeyedCollection was implemented to provide roughly constant-time lookups by either index or key regardless of the size of the collection. Whether that means "consistently fast" or "consistently slow" I haven't measured yet. :) But I think the best part might just be that the class you derive from KeyedCollection is serializable via XmlSerializer, despite having dictionary-like semantics. That's basically the end of the old "Damn! I can't serialize a Hashtable" problem.

Monday, October 3, 2005

.NET 2.0 It Is, Then

Based on the feedback from my question about upgrading FlexWiki, it looks like we're go for throttle-up to a .NET 2.0 deployment. I'll start making the switch today. Of course, it'll be quite a while before I have anything I can go public with (or that even compiles for that matter), but I think this is the right move. If nothing else, it gives me an excuse to spend more time working with the new bits.