Monday, January 29, 2007

I dealt with several situations in the past months where the crux of the problem was confusion over assemblyname and filename.  Let's define what we're talking about:

  • Filename - The name of a file in the filesystem, such as System.dll
  • Assemblyname - The name given to an assembly to establish its identity.  In this case, we'll only concern ourselves with the "simple" name. such as System

Usually, any confusion that arises between the two can be resolved by reminding people that a filesystem is just one of the places you can get an assembly from.  For instance there are APIs for getting assemblies from byte arrays.

For those that still do see it... In the managed world, the assemblyname gives identity to the code that resides in the assembly.  If you have 2 assemblies with the same assemblyname, you expect them to represent the same identity (perhaps different versions, build flavors, bitness, etc.).  If we relied on the filesystem name, the identity of the code could change just by changing the filename.  That's not the semantics we expect.

So, why does the filename matter?  Why do we recommend keeping them the same?  Some of the reasons are simple convenience.  It's nice to look at a file and know what it is without cracking it open.  If the names are different, it's like me going to a party and wearing a nametag that says, "Peter".  While there is nothing keeping me from doing it, it causes confusion.  However, another more important reason to keep them the same is that assemblies are rarely loaded by filename.  References and most dynamic loads are done by assemblyname.  You don't take a reference to System.dll, you take a reference to System.  At some point, the loader has to find an appropriate file to load to satisfy that reference.  If System's filename is Peter.dll, then it's going to have a difficult time finding it to load.  This is actually the very reason that gacutil will not let you install an assembly into the global assembly cache if the filename doesn't match the assemblyname.  However, I think it's silly that it doesn't just fix the name for you.

What about multi-module assemblies?  Well, it's the module with the assembly manifest that matters.  It's the one that should match.  Then the rest of the files need to match the assembly manifest :). But, if you're using multi-module assemblies, let me know.  I'd like to know why.

posted on Monday, January 29, 2007 12:46:56 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Thursday, January 25, 2007

Yup, it's that time again.  Today is my birthday.  I was lucky enough to get a Wii, which has been quite enjoyable.  Now I just need to get the component cables so I can stand to look at it. :)

posted on Thursday, January 25, 2007 9:05:54 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Monday, January 22, 2007

I've mentioned before that one of my ownership areas at MS is the CLR "shim".  Most people I've said that to ask me, "What's that?".  I usually reply that generally, it's mscoree.dll, to which they typically respond, "Oh yeah.  What does that do?"  In general terms, the shim is in charge of firing up the runtime in a process.  In addition, it exposes all the hosting APIs and other stuff you need to do stuff with the CLR from unmanaged code. If you look at a managed app, you will see that it has a dependency on mscoree.dll, and nothing else CLR-related.  Ater the runtime is spun up, most of the things that mscoree exposes are simply forwarded calls into the mscorwks.dll of the runtime you have installed.

What's interesting about mscoree.dll, is that it is the only piece of the runtime that doesn't run side by side.  You can have v1.1 and v2.0 installed on the machine, but you will only have one mscoree.dll.  You always have the version of mscoree.dll that corresponds to the latest version of the runtime installed on your machine (unless you have installed a patch or something that services mscoree, in which case you may have a v2.0 shim even though only v1.1 is installed on your machine).

So, naturally, backwards compatibility is extremely important in the Shim.  When you start up managed code, the Shim decides which version of the CLR to fire up based on lots of different things.  These things are all fairly well documented and all have a specific scenario they enable, but by their nature they are very confusing.

Aside: When I was job hunting, I interviewed at several companies other than Microsoft.  During some of those other interviews, I was asked questions about what runtime would be started under certain conditions. The rules are so confusing, that some of the interviewers, although all extremely smart people, had formed incorrect models of what the rules were.  Some told me I had the wrong answer to their question, when if fact it was correct. (that's not to say that I knew the correct answers to all of them.)

I'm not certain that I can clear up the confusion, but I do hope to have a series of posts in the coming months on why the shim does what it does under certain circumstances.  Then, at least you might understand what's going on when it happens.

posted on Monday, January 22, 2007 10:50:36 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Tuesday, January 09, 2007

I have had occasion recently to play with the latest (December 2006) CTP of WPF/e.  It's a really cool technology that I think is poised to change the way people write rich web apps.  It's cross-platform (Windows and MacOS at the moment) and cross-browser (IE5-7, Firefox, and Safari at the moment).

The CTP has some limitations at the moment that are keeping it from really being a replacement for HTML-based web apps (It's missing the WPF layout manager for one), but it certainly doesn't keep you from doing some really cool stuff with it.

Rather than just point you to the existing samples (scroll down to see them), I thought I'd put together one of my own.  I created a proof of concept replacement for my blog's header that shows my photos from Flickr as if they were hundreds of polaroids strewn about and panning by.  You'll need to go to the WPF/e site and download the plugin that's appropriate for your OS (look under Top Downloads on the right). After you've done that, click the image below to see the demo.

Click to see demo

It consists of:

  • A xaml file with the "background" (some of which is in the foreground) and some general declarative animation instructions.
  • An html file with some script infrastructure for pulling JSON data from the Flickr APIs and turning them into visual elements.
  • The provided WPF/e scripts for instantiating the control
  • the MicrosoftAjax.js file from the AJAX library.
  • A little .ashx proxy for routing the async calls to Flickr (to avoid cross-domain scripting issues)

If you watch long enough, it should scroll through all 7,140 of my pictures (with some gaps in between while loading new images), and then start over.

All in all, it was really easy to do.  There are some problems I need to address before it could realistically take over as the header for my blog, but I think it shows some real promise.  I can't wait for the actual WPF/e release.

posted on Tuesday, January 09, 2007 2:52:10 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Thursday, January 04, 2007

The couch that we ordered over 2 months ago was finally delivered yesterday.  When we moved into our house here, we picked out a couple of couches...  a less-expensive, fold-out sleeper for the upstairs living room, and a really nice, non-sleeper for the big downstairs room where we spend most of the time.  The sleeper arrived shortly after we ordered it, but the nice one was delayed multiple times.

We spent our first 7 years of marriage with really old couches that my parents had when I was growing up.  They were so old and broken down that we decided not to bother bringing them with us to Washington.  It's very nice to have a sweet couch (it's nice to have a couch at all).  We made sure to get one long enough that I can lay on it without my head or feet having to be on an armrest (something I rarely experience at 6' 2").  It also sits up nice and high so you don't have to feel like you're climbing out of a hole when you get up.  Becky's feet don't even touch the floor when she's sitting on it.

posted on Thursday, January 04, 2007 2:33:13 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Wednesday, January 03, 2007

Someone asked me the other day if you could reflect on other people's assemblies using the CLR.  My answer was, "ABSOLUTELY!!!!!"

As it turns out, they were having some problems achieving this, and they were wondering if there was some kind of security mechanism in place that was preventing reflection on 3rd party assemblies.  Here's the basic scenario.  They had a 3rd party library with a type that defined several "constants" using fields.  They needed to be able to specify a named constant via a string and return the value for the constant.  Security and performance arguments aside (they had already been considered), they simply wanted to lookup the field by name via reflection and get its value.  This can be accomplished via just a few fairly reasonable lines of code using one of the GetField family of methods on System.Type and then getting the value.  I'll leave this as an exercise for the reader so they can have the fun of wresting with the silly BindingFlags enum.

After some discussion, I learned that the trouble actually revolved around getting the Type object in the first place.  They were using Type.GetType to load the type with a namespace-qualified name as the string argument.  It was returning null (Nothing in VB).  They were validating that the string was correct using Intellisense, and concluding that since Intellisense could see the type, that Type.GetType should also "see" it (which seems like a perfectly reasonable assumption).

Type.GetType() takes a string argument specifying the type to retrieve.  When specifying types in strings, you can usually use a namespace qualified name ("[namespace.]type"), or an assembly-qualified name ("[namespace.]type, assemblyName").  If you don't provide the assembly name, the API looks through the assemblies already loaded in the AppDomain for a type that matches the name.  If an assembly name is specified, a bind occurs to the assembly and it is loaded if necessary.

In this case, there was a reference to the assembly containing the type, so Intellisense was picking it up and providing completion. The trouble was that, at runtime, the assembly had not yet been loaded into the AppDomain, so the type was unavailable.

So, the options were (in order of appropriateness in my opinion):

  • Use an early-bound type - Since the type was known at compile-time, use typeof() (GetType() in VB).  This will create a compile-time, assembly-qualified type reference in the IL rather than a runtime parsing/bind/load of the type string.
  • Use an assembly-qualified type string - Adding the assembly name to the type string will let the CLR know what assembly to look in (and load if necessary).  There are some subtle versioning issues with this approach, especially for strongly-named assemblies.
  • Make sure the assembly is loaded prior to calling Type.GetType() - Making an early-bound call to something else in the assembly first will get it loaded into the AppDomain.  This seems like a fragile solution and I would not recommend it, although it will technically work.

The real issue here is the number of samples (especially in VB) provided by MS that use Type.GetType() with a non-qualified name (ex. "System.String").

posted on Wednesday, January 03, 2007 9:09:25 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Tuesday, January 02, 2007

This year, we gave the gift that keeps on giving... the stomach flu. But, before I get to that, let me back up a bit...

If you recall, we got our power restored after over a week of outage with just a little more than 12 hours to prepare for our holiday travels.  However, we managed to get everything together and arrive at the airport the suggested 2 hours before the flight.  Out trip went through Phoenix instead of Denver, so I figured we'd be in the clear weather-wise since nothing ever happens in Phoenix.

Wouldn't you know it, we got to the airport to discover our flight had been delayed due to fog in Phoenix.  After a bout with a touchy airline representative (which I may eventually devote an entire entry to), we decided to go ahead to Phoenix since everything was delayed coming and going in hopes that our connecting flight would be delayed as well.

4.5 hours after our flight was to leave originally, we boarded the plane with still a slight chance of catching our connection.  After we landed in Phoenix, we discovered we'd missed the connection by a mere 19 minutes.  With no flights available to El Paso until Christmas, we really had only one acceptable option... rent a car and drive.  So, at about 9pm, we hopped in a car and drove the 6.5 hours from Phoenix to El Paso to Becky's parents house.  All in all, I felt a great sense of accomplishment in having executed such an old-school road trip with a 1-year-old.

Christmas with the Pattersons was great.  I got something I have wanted most of my life... a radio-controlled helicopter.  Thanks everyone.  The only issue was that things in our room were much colder than we were used to, which resulted in Jenna waking up every 30 minutes after midnight due to being cold, and she got all sniffly and such.

We went to Cattleman's (a world-famous steakhouse) for dinner Christmas eve, and I had a huge t-bone.  It was delicious.  Becky had been feeling ill earlier in the day, but we attributed it to lack of sleep.  After dinner, she took a turn for the worse.  I started feeling bad, but attributed it to eating too much.  Becky went to the doctor while I put Jenna to sleep.  By the time Becky got back, I was full on sick, but it was too late to see the doctor.  It was probably the worst night of my life.  Becky's dad helped us tremendously by tending to Jenna, who had also caught the bug.

The next morning, after an unpleasant episode in which I thought I was literally dying, I went to the doctor too.  We were scheduled to fly to Austin and drive to Belton this day, and were contemplating delaying the trip.  We ultimately decided that the pros of keeping our original schedule outweighed the benefits of staying longer.  So, somehow, we got on a plane to Austin and then drove the hour from Austin to Belton.  Unfortunately, the wake of our illness still spread to virtually all of Becky's family.  Some of them got sick on their flights home.

In order to avoid getting sick when we arrived in Belton, my parents just waved to us as we went to the apartment behind the house where they work.  They had gone to alot of trouble to quarantine us away, which was great because we had alot of room for Jenna and we had complete control over the temperature.  For the next few days, we followed a protocol of constant hand washing and such to prevent the spread of the plague.  We even avoided seeing my brother's family completely to avoid any complications for their new son who was less than a few weeks old.  This seemed to be working until my Dad got sick, followed by my mother that night.  My aunt also got sick on her flight home.  We ended up canceling several rendezvous we had planned with friends in the area.  In the end, we finally had a very short visit with my brother's family on his back porch.

Even though we had to be up at the crack of dawn on the 1st to get to the airport, we thankfully had an uneventful and undelayed flight home, and we just sat on our couch in disbelief of the events that had transpired during the previous few weeks.  Now, we just have to shift Jenna 2 hours back to Pacific time.

So, to everyone we had hoped to visit while we were in Texas, we're sorry things had to go down like that.

posted on Tuesday, January 02, 2007 4:26:53 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]