Wednesday, October 31, 2007

Code Camp Presentation Posted - LINQ to XML

Twin Cities Code Camp 3 was a blast and I had a lot of fun presenting this time on LINQ to XML. Hats off to Jason Bock who did a fantastic job pulling all this together (as did everyone else who helped out). All the presenters were first class, many of them Microsoft MVP's. It was an honor working along side them.

If you missed my talk or just have a general interest in LINQ or LINQ to XML, feel free to download my Powerpoint presentation. If you have any questions, shoot me an email at: peter at twistedstream dot com.

Monday, October 08, 2007

Fall 2007 Code Camp

One of the more recent really cool tech events to hit the Twin Cities is the Twin Cities Code Camp. They happen usually every 6 months and #3 is occurring at the end of the month on October 27th. Code Camp is organized by Jason Bock, a Microsoft MVP and a good friend of mine from Magenic Technologies. It is sponsored by a number of area technology businesses including Magenic, Microsoft and New Horizons, which is where its held.

The event is free to attend (plus they feed you breakfast and lunch). You get to choose from a number of sessions where you can learn about new technologies and chum with a lot of really smart people.

Also, I've been given the privilege to present one of these sessions. I'll be talking about LINQ to XML, Microsoft's new XML API. If you're interested in LINQ (which you really should be since its the main feature add for the next version of .NET), there are two others sessions before mine that talk about LINQ to SQL and LINQ to objects. Very cool stuff! Check out the schedule to see all the topics.

Thursday, July 19, 2007

Google Maps API Weirdness in IE6

For the past few months I've integrating the Google Maps API into an existing website. Last month we finally released the new version of the site and everything seemed to be working fine, except in IE6.

Specifically, the map marker icons (you know, the little red teardrops) were not rendering properly. Here's how they looked in IE7 and Firefox:

and here's how they looked in IE6:

Yuck! Now, it's a well-known fact that IE6 can't render PNG files properly (specifically if they have any transparency to them, which these icons do). However, the Google Maps API is aware of this and employs the AlphaImageLoader filter to compensate. Go to on IE6 and the icons look just fine.

So why were my icons turning out so crumby?

Well, my scenario was a bit more complex than all the standard 'hello world' samples out there. First, I was using custom icons. But on top of that I wasn't simply slapping some static JavaScript code on my page to display the Google Maps API objects. Rather, I was generating all of the JavaScript code dynamically in my .aspx page on the server side. However, the final HTML output of my page (specifically the JavaScript code rendering the GIcon objects) looked right.

Except for one difference. Like I said, I was using custom icons. Just about all of my custom icons were the same shape; they really only differed in color, which meant the only real difference was the GIcon.image property (all the other properties were pretty much identical). In my inifinite wisdome I thought it would be clever to consolidate all of the other image URL properties associated with each GIcon (shadow, transparent, etc) and I would do this by storing those images as embedded resources within my assembly and referencing them via WebResource.axd.

The end result was that instead of the GIcon JavaScript code looking like this:
icon.shadow = "my-shadow.png";
it looked like this:
icon.shadow =
And what was tripping up IE6 was the fact that the image URL wasn't ending in ".png". Really what was being tripped up was the Google Maps API JavaScript code running in IE6. Perhaps the version of their code that runs in IE7 is able to automatically detect PNG files without requiring a .png file extension. Who knows. But the bottom line is that the image URL must end in a .png file extension, ruling out any standard dynamic image URL resource (like WebResource.axd).

This took me a fair amount of effort to solve. Hopefully, I'll save someone else the time.

Monday, June 11, 2007

First MS150 a Success

I've had way too busy of a summer. So much so that one of the biggest events, the MS150, came and went, and I never even bothered blogging about it. Well, here it is, better late than never.

In short: we (Jeff and I) had a blast. 150 miles of fun... and soreness. My butt got pretty sore and at the final 10 miles of the tour my left knee was giving me problems. Jeff had been drafting behind me most of the way and, at the end, was able to take the lead, which was nice. Jeff had weird gloves and one of his hands was numb for about 3 weeks afterward!

But the benefits definitely outweighed the costs! I will do this event next year.

Here were some lessons learned:
  • Stretching is very important (lack of is what caused my knee injury).
  • Get on the trail earlier in the morning next year to beat the heat.
  • Get more power with higher RPM's instead pedalling harder; this is much easier on your joints.
  • Hang with a group to take advantage of drafting. I would struggle to maintain 15mph (with a head wind), but it a group could do 18mph with ease.

Tuesday, May 22, 2007

No more room in my VHD

Hold the phone. A reader just tried the procedure described in the UPDATE section below and found out that when you finally go to convert from the fixed back to a dynamically expanding disk, you never get prompted for a new disk size. If this is true, this handy workaround is pretty much worthless. Has anyone else attempted this that could confirm? Yes, I'm too lazy to do it myself.

The information in the original post is pretty much obsolete, or perhaps more accurately put, incompetent. Thanks to a recent anonymous comment, all I had to do was convert the VHD to a fixed disk and then back to dynamically expanding. Read on if you'd like to learn how to do it the hard way.

So, you may or may not know that I'm a huge fan and user of Virtual PC and Virtual Server. For over two years, I've been using virtualization exclusively for software development. Sure, there's a slight performance hit, but you can't beet the flexibility you gain from having one (or more) isolated development environments. Before using Virtual PC, it was common for me to be wiping my laptop once every 4 to 6 months. Now, since I don't run any development tool software on my host OS, it's rare that I have to rebuild my host machine. And, of course, creating new virtual PC's is a snap.

Virtual PC, Virtual Server, and VMWare all use the concept of virtual hard drives (or VHD's). These are nothing more than files on your physical host OS's drive that represent a virtual drive. They can be fixed in size (like a physical drive) or dynamically expand. The later option is handy in that such a VHD only takes up as much physical space as it needs, gradually growing over time. The benefit is it saves a lot on physical drive space, especially if you manage multiple virtual machines.

When you create a virtually expanding VHD you have to specify its maximum size; for Virtual PC the default max size is 16MB. The kicker is when you're using that VHD and all of the sudden one day you run out of room. It's the same experience you have when you run out of room with a physical drive - you immediately try to free up space by deleting unnecessary files and uninstalling unused apps.

However, I recently ran into a scenario where making more room wasn't enough. I was installing Visual Studio 2005 Service Pack 1, which requires a ton of free disk space (over 2GB I think) and I couldn't make it happen. Since you can't change the max size of an existing VHD, I only had two options:

  1. Rebuild my virtual machine with a larger VHD.
  2. Somehow transfer the contents of my existing VHD to a new empty VHD.
The second option was much more appealing since it would require minimal effort. I just needed a tool that could do it. Transferring or cloning a disk is more involved that simply copying files since you need to transfer boot record, partition, as well as other information.

Doing a little digging, I found there are several utilities out there. Norton Ghost is one. The one I chose was Acronis True Image Server (I installed the Server version since my OS was Windows Server 2003). Neither of these are free, so you have to either buy them or use their trial edition. The process I used was the following:

  1. Create a new empty dynamically expanding VHD (with a more desirable max size) and mount it to the virtual machine.
  2. Install Acronis True Image Server on the virtual machine.
  3. Start True Image and run the Clone Disk wizard.
  4. Unmount the old VHD.
  5. Mount the new VHD as drive 0.
I think there are free disk cloning utilities out there, but I'm not sure how trustworthy they are. Disk cloning isn't something you want to mess up.

Before you perform this operation, make sure you have plenty of room on the physical drive that contains the new VHD. Running out of physical drive space as the new VHD is getting filled (and expanded) can cause the clone to fail. Learned that one the hard way :).

Thursday, May 03, 2007

Back in the saddle

It's been over two weeks since I've biked (to work)!!! I've been slacking and am running out of excuses. Most of it has to do with over-busy-ness. Blah, blah, blah...

Tomorrow I AM biking in and the rest of the blogging world can hold me to it.

Looks like we're going to get some rain too. Perfect.

Sunday, April 01, 2007

Converting the primary key type in a SQL Server database from int to GUID

I maintain and develop a database for a web application that I've worked on for several years now. The application and the database have evolved significantly, and as things got larger and more complex, I've had to employ more advanced techniques and tools to perform database updates from development to production.

One of the "mistakes" I made when I originally designed the database was to use primary keys with the int data type (along with setting the primary key column as an identity column) for all of the tables. I have nothing against int's or identity columns and, in fact, that simple, tried-and-true configuration has worked well for this application... except for one, unfortunately very painful side-effect. When it comes time for me to push a major update from development to production, sorting out duplicate columns between both development and production database can be a real pain in the undercarriage.

The reason for this is often times in development I'm added new rows to tables that exist in both development and production to test and/or enable a new feature. If the primary key for that table is an int that is auto-generated by the database (since its an identity column) then there's a VERY good chance that same ID has been duplicated in a row in the production database. Things get even more complicated when that primary key ID is referenced by other columns in other tables via foreign key relationships. I tried a few production push sessions where I pretty much took the production database offline (which meant I pretty much took the website offline), pulled down the entire production database, integrated the development data into production by hand (I use RedGate products), and finally pushed the whole thing back up to production. Not pretty, but it worked... until recently. Within the last few months, for various reasons the production database has nearly tripled in size, making the whole pulling of the entire production database, and, worse yet, the pushing of it back up, ridiculously impractical. My last push took over 12 hours! Now, granted, I'm restricted by the limits of a cable Internet connection, but I came to the realization that I needed another solution.

Well, the solution is simple: switch to GUID primary keys. They never duplicate (in theory) so I can create rows in development that will never interfere with new rows in production. Unfortunately the road to this solution is not so simple. However, I was able to finally get there, so I thought I would share how I did it.

How to do the conversion

The main issue with a conversion of primary key columns from int/identity to GUID is the fact that you can't simply do a TABLE ALTER to remove the identity status of a column. You actually have to drop the column and re-add it!

Following are the steps I took. In this example, we'll call the starting database db and the final database db_new-schema.
  1. Create db_new-schema as an empty database with new schema (i.e. everything the same as the old schema except the primary and foreign key columns are all of type UNIQUEIDENTIFIER).
  2. Create another empty database called db_load whose schema is identical to db's except all the primary and foreign key columns are of type NVARCHAR(36) and contains only tables (views, stored procedures, functions are unnecessary). Also, there should be no foreign key constraints between tables.
  3. Use an ETL tool (like DTS or SSIS) to copy the raw table data from db to db_load.
  4. Create a SQL script that uses a cursor to enumerate the rows of a given table in db_load, updating each row's primary key with a new GUID value (using the NEWID function), and updates the rows in all foreign key tables with the same GUID value (selecting them using the old INT id). This script needed to modified and run for each table in the database until all of them were updated. In the end, all INT values were converted to new GUID's (although all primary and foreign key columns were still typed as VARCHAR).
  5. Convert all primary and foreign key columns from VARCHAR to UNIQUEIDENTIFIER.
  6. Use an ETL tool (or RedGate Data Compare) to load the db_new-schema database with all the data in db_load.

Good luck!

Saturday, March 03, 2007


This June I'm going to be riding in the MS150 Bike Tour, which is an anual fund raising event for multiple sclerosis. It's 150 mile trek from Duluth to the Twin Cities that lasts 3 days (2 days of actual biking).

Anyway, I'm very excited as this is the first real long-distance bike trip I've ever taken. And it's for a good cause!

If you'd like more information about the event or would like to donate, check out my personal MS150 page.

Sunday, February 25, 2007

(In the words of Kip) "That's what I'm talkin' about."

We got snow!

For once the weather man didn't cry wolf. I opened up my back door and here's what I saw: beautiful, white, fluffy snow!

It's been several years since we'd had a dump like this one. I know where we live, we got at least 12" and we're due for more.

And the coolest part is the kids and I built a snow hut. I haven't built one of these since I was in Boy Scouts!

Wednesday, January 24, 2007

Radical Islam

I watched a very interesting documentary last night called Obsession: Radical Islam's War Against the West.

I think since 9/11 everyone has been aware of a link between Islam Extremism and terrorism, but I'm not sure everyone is aware of the gravity of this movement. What I liked about the film was that just about everyone interviewed was a Muslim (one person was a former PLO agent). This diminished the notion that the movie was a biased message from non-Muslim groups (i.e. Jedeo-Christian). And, of course, the first point made was that Islam Extremism is a view only held by a small percentage of practicing Muslims (something like 10 to 15%). However, that number is getting bigger as the "movement" is being very effective in recruiting non-Extremists to their cause - especially the youth.

The scary thing is the end goal of Radical Islam: to take over the world (by force) and make everyone Islam, killing everyone who apposes. A lot of people, including myself, questioned why Al Qaeda attacked the World Trade Center. Why do they hate us so much? Why were they willing to kill Americans, including Muslims? The answer, according to the film, is that they will kill anyone who apposes their mission of world domination. Right now, Western Civilization, is a huge target since it apposes this world view.

The movie also drew a very interesting parallel between Islam Extremism and the Nazi movement in WWII. Hitler's end goal was similar: to take over the world and eradicate anyone who didn't fit his world view, his primary target being the Jews. An interesting point was made that the current Radical Islam movement is potentially more dangerous than the Nazi movement because the Nazis fought because Hitler told them to; Islam Extremists fight because they believe God is telling them too.

Taking all this into account, puts a new spin on the War in Iraq, at least for me. Like most Americans right now, I'm getting weary of this conflict: the money being spent, the lives lost, yada yada. Up until the last few years, I've considered myself a conservative. I voted for Bush. However, these days its been tough to understand and support what he's doing. After all, wasn't it Osama bin Laden who attacked us, not Iraq? There were no WMD's. It just seems like we're there now because we opened a can of worms and can't get out.

Well, if what this movie says is true, then there is some logic for being in Iraq. Assuming the US government realized the real threat of Islam Extremism (world take-over), they had two options: build US defenses and just wait for the movement to grow and attack us or be proactive and attempt to stabilize the region where most of the Islam Extremism was coming from. At the time we invaded Iraq, everyone, left and right was certain that Saddam Hussein had WMD's. And if he was in on this movement, there was a huge threat here. Well, he didn't (at least we didn't find any). So we finally took him out only to find that removing him destabilized the country even more. But given the threat of Radical Islam, did we have any choice? Had we just sat back and let the movement take over the rest of world, we would have had very little chance of effectively defending ourselves in the future. Tough call. I'm glad I'm not the President of the Unites States.

As a Christian, I'm still not sure where I stand on the War in Iraq. I guess from a strategic standpoint, it makes sense. But as far as showing the love of Christ, I'm not so sure. War is never a black and white issue.

A final point. About a month ago I watched Al Gore's An Inconvenient Truth. This movie openned my eyes as well. I find it interesting that both the left and right have a doomsday prophecy: the left thinks the polar ice caps will melt within 50 years and the right thinks a global Jehad will take over the world. Both sides say we need to take action now to prevent the end of the world as we know it.

Wouldn't it be ironic if both sides were true.

Tuesday, January 23, 2007

January Bike Ride

This will be a true test to see if my wife reads my blog.

I biked into work today. In me defense, it wasn't totally planned. The plan was to drop off my car at the shop and bike to the bus stop, which is only about .5 mile away. However, the problem with the bus, I've found, is that you have to get to the bus stop on time. So I missed the bus and my inspiring bus schedule said the next one would show up in about 50 minutes. The decision was easy: wait 50 minutes at a cold bus stop or bike to work in 35.

The good news was that I was fairly well dressed. I had assumed before this that I really didn't have the right clothing for anything below 30°F (this morning it was about 20°F). The only thing that got a little cold were my toes. The roads were fairly clear and the Gateway Trail, which I rode for about half the trip, was mostly plowed. As long as I didn't make any sudden turns, everything was smooth.

Overall, I enjoyed it and it's getting my more excitied about biking. Spring could not come soon enough.

Monday, January 22, 2007

Will Google take over the world?

For years I've had to endure Microsoft-bashing. I call it bashing because for the past 8 years I've made a living off of the success of Microsoft and knocking Microsoft (or M$ as the affectionate abbreviation goes), meant you were knocking the entity that ultimate allowed me to get a pay check. But don't get me wrong, it's fun to bash large corporations, and I'll admit I've made an occasional M$ jab from time to time. Microsoft has done some cool stuff and some not so cool stuff. And, ironically, many of the sins they were accused of back in the day have been committed by many of their competitors since then. I guess it's the game of business.

I remember something Bill Gates said a few years ago when Microsoft was at its peak. And that was that at any given moment, Microsoft Corporation was 12 months away from going under. What he meant was that even a software giant like Microsoft could never stand still or the competition would eat it alive.

Well, I think Microsoft has met it's match: Google. It's no secret that Google has quietly become a huge player in the technology world. They are the standard search engine. I love many of their free services, including Gmail, Google Maps, and Google Reader. But I've always found it a bit odd that they offer so much stuff for free.

What exactly is G$ up too? Check this out.

Wednesday, January 03, 2007

Why I HATE Cingular

Ya, harsh subject line. And for people who know me, I'm not one to start flaming people or companies. But I've had it. And I need to vent this somehow.

About a year and a half ago I switched from T-Mobile to Cingular because I wanted a phone that only Cingular offered. Dumbest mistake of my life. The very second my 2 year contract is up, I'm switching back. Now, granted, Cingular has been better than AT&T, but not by much. And just an FYI - my biggest annoyance with Cingular is that they claim to have the fewest number of dropped calls; I get a dropped call about once a day.

Anyway, I open up my cell phone bill today expecting it to be around the normal $75. Not this time. Today it was 498.54! Holy crap! So I scrambled to figure it what the heck happenned. Of course, disciphering the billing charges requires a PhD and a half, but I finally found the issue. The bill claimed that I had done a 39,578KB data transfer. I don't have a data plan. I haven't done any data transfers since the first month I had service after which I cancelled their $20/mo data plan.

I called customer care and the rep did a little research and found out the transfer occurred at 3:52pm on Tuesday 11/28/06. I was at work at that time and to my knowledge was not using my phone to transfer megabytes of data (I did a quick calculation and discovered it would take at least 2 hours to transfer that much data with my phone). So I told them that and they claimed there was nothing they could do. Ha! I asked to speak with a manager. After sitting on hold for 10 minutes, a manager came on and said the best they could do was credit my account $150. When I proceded to explain to them that I wasn't going to pay any of the erroneous data charge, the connection went dead. Cingular - network with the fewest dropped calls. That was the moment that I almost ate my cellphone while tearing the countertop off my kitchen cabinets.

There is a happy ending. I called back, sat on hold for a while, and finally spoke with a rep who was able to credit me half of the charge and fill out a form that would supposedly credit the rest back within 30 days. I pray that happens; God have mercy on the poor customer care person who answers my call if it doesn't.

There, I feel much better now. :)

UPDATE 9/4/07:

I'm happy to report that Cingular did manage to completely reverse the charges. It took a month, but at least it was taken care of. Why I had to go through so much pain is still irritating to think about. The conspiracy theorist in me thinks they sprinkle little fees like this all the time to customers and bank on the hopes that the customer won't go through the hassle to reverse them.

Anyway, in the end, I got even. The very day after my 2 year contract was up I switched to T-Mobile. And, like the comment of one of the readers, I haven't had to think about my wireless provider ever since.

One more funny thing. Just after I switched, T-Mobile put up some billboards in the Minneapolis/St. Paul area stating "Don't drop dad! T-Mobile, fewest drop calls in the Twin Cities". I knew it wasn't just me!