July 2009 Blog Posts

Four Days of Birthday Awesome

My birthday was last week Thursday and I had some PTO to burn so I decided to take Thursday and Friday off. Four day weekend, right?

It actually sort of started Wednesday when my team at work brought in a black forest cake and we had a mini-celebration in the afternoon. Nice.

Snap Circuits ExtremeThursday, my actual birthday, I woke up and Jenn gave me my gift: a Snap Circuits Extreme set - 750 projects to help you learn about electronics. I've been wanting that for a while since I'm not really "electrical engineer" inclined and it's pretty awesome.

Later that day my parents came over, Jenn got off work early, and we went out to lunch at Red Robin. After lunch, we saw The Hangover, which was pretty damn funny... and just a little gross in parts. We ended Thursday with a tiramisu we picked up at Haggen.

Friday was a pretty relaxing day where I took care of a few chores (like cleaning up the office) that I'd been wanting to get to and I started playing Dead Space on Xbox 360, which is a pretty freaky game I got from my friend Jason.

Saturday my parents came back over in the morning, we mounted the bikes on the car, and headed out to the Banks-Vernonia state trail. We didn't ride the whole thing, just about an eight-mile round trip, but the first half of the trip was a slight uphill so it was a nice, light workout. The return half of the trip was awesome, though - we were able to coast almost the whole way back without pedaling. (We had a contest to see who could coast the furthest. Jenn won by a few yards.) Jenn also picked up my official birthday cake, a tasty lemon chiffon from Beaverton Bakery. (Yes, for those counting, that's three cakes in four days. I do so love me some cake.)

Sunday Jenn and I finished up the weekend by going to see Harry Potter and the Half-Blood Prince. I'd seen it already, but Jenn hadn't and it was nice to see it again. Plus, it was pretty hot on Sunday afternoon and who can beat the heat better than the movie theater?

All in all, four days' worth of fun and celebration, which was relaxing.

Music Memory

I have a pretty extensive music collection on my near-full 160GB iPod Classic and sometimes I run across something that I haven't heard in a long time and wonder why I haven't.

Depeche Mode 101

This morning I've been listening to Depeche Mode 101, a live concert album they did in Pasadena, CA, in 1988. It reminds me of my first job.

Back in high school, when I was 14, I got a job at a local dry cleaner. I actually got notified of the opening through a long-time friend of mine and, for a time, we both worked there, though he left before I did.

It didn't start out well, at least, it didn't in my 14-year-old mind. My first task, on my first day, was to get a bucket and brush and scrub the walls in the tiny bathroom in the back. Pretty nasty.

As time went on I got more responsibility and, after a year or so, was tending the shop solo. I wasn't running the equipment, but after the folks doing the actual cleaning and pressing had gone home, I'd stick around and handle the customers coming in to drop off or pick up clothes - write up the order tickets for people, play cashier, that sort of thing. I can still remember the general pricing structure - $3.80 for a shirt/blouse to be dry cleaned, $0.50 extra for silk or rayon because they needed to run in a separate load and took extra care when spot cleaning; $1 for a washed/starched/pressed men's dress shirt.

When folks weren't coming in, I'd clean the place - sweep up the lint that accumulated on the floor, mop, wipe down the equipment - and prepare things to be cleaned the next day - separate clothes into different bins based on which load they needed to run in, undo all the buttons on the dress shirts to be washed and bundle them into bags for washing, and so on. Eventually I got to a point where I could run the washer for the shirts and the Permac dry cleaning machine.

You'd get to know the customers who came in, what they usually brought in, how often, and so on. There was one lady who always came in driving this Porsche 964 Turbo with rear fender vents. We always looked forward to that - it was the coolest car we'd ever seen. She offered to take us for a ride in it, but none of us ever took her up on it.

It's amazing some of the weird skills you pick up when you work places. I can still usually tell by feel if something has silk or rayon in it, even blends (faster than checking the label when pricing things). I can unbutton all of the buttons (sleeves, collar, front) on a button-up shirt in a couple of quick movements (gotta be unbuttoned for washing and pressing).

Anyway, hung on the back wall, above the giant washing machine (actual washing with water, for the men's shirts), was this boom box with a tape deck. It was covered in the oily lint that got all over the place. The speakers were detached from the body and hung about four feet on either side of it. On the Saturdays when I was there minding the shop, I'd break out my 101 tapes and pop those into the boom box. I listened to them enough that they got demagnetized in places and the tape was sort of stretched and weird sounding in others. With Depeche Mode cranked in the background, I'd get into a work flow and take care of business.

It's weird how music can make you remember stuff. Now, every time I hear 101, it's like I'm back at the cleaners on a hot Saturday afternoon, waiting for that Porsche to roll in. Maybe this time I'll take that ride.

Paraesthesia.Tools.NAntTasks 2.0.0.0 Released

It's been a while since I touched these, particularly since I don't use NAnt much anymore, but I got spurred into action by one of my readers (thanks Mark!). To that end, I did some updating to get things to work with a more recent environment...

  • Updated to .NET 2.0.
  • Updated to NAnt 0.86 beta 1.
  • Fixed nunitexec task to no longer output the "framework" parameter.
  • Fixed nunitexec task to properly quote only the value of command-line parameters.
  • Fixed alpharesx to output .resx files in 2.0 schema format.

Go get it!

Tears for Fears at the Oregon Zoo

Tears for Fears performs at the Oregon ZooSaturday evening Jenn and I went to the Oregon Zoo to catch the Tears for Fears concert. I gotta say, it was awesome. Hearing the hits played live was so cool - the crowd singing along to "Head Over Heels," dancing to "Shout," and getting back to the original "Mad World" was not to be missed.

Michael Wainwright opened, played a nice set, and then joined Tears for Fears to round out vocals. He was a great "Woman In Chains," I have to say. :)

The weather was totally agreeable - nice and sunny, in contrast to our B-52s outing. We kicked back, relaxed, ate an elephant ear, and took in the music. If you get a chance, see these guys live. If they come back, I'm there.

If SQL Server Install Always Requires Reboot, Check the Registry

More a reminder note for myself than anything... I always - always - run into this problem when I'm trying to uninstall SQL Server. The installer runs some checks on a screen saying "Setup Support Checks" and always fails the check labeled "Restart Computer."

I always end up Googling for the answer and it's always the same (and it always works):

Go to the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations key in the registry and clear it out.

Once that's done, run the installer again and the check will pass. Done and done.

Sandy Fireworks 2009

2009 Sandy Fireworks Shoot

Jenn and I normally go work on a professional fireworks shoot each year, but this year was special - we were in charge of our own show in Sandy, OR.

The show was actually sponsored by the City of Sandy and they had some donations come in to make the show larger than last year's, so it turned out there was a lot to shoot. I think we calculated it at just under 900 individual shells and seven pre-fused boxes.

Setup took five or six hours because it was pretty hot out and we took frequent breaks to rest and rehydrate. Something different about this show than we'd dealt with in previous shows was that we were burying the mortars in sand above ground, rather than having a trench to put them in or wood legs to attach to the mortar racks. Setup went smoothly, though, and we had a couple of hours to eat and rest before the actual shoot.

The show proper lasted 33 minutes, which was almost 20 minutes longer than the previous year's show. We were told we were trying for a "20+ minute show" and we thought we'd try for about 25 minutes so it wasn't too long (people get bored) and it wasn't too short. We didn't know how fast it would go, so we started off taking our time... but Jenn was watching us with a stopwatch and saw that we got to the 1/4 mark and were eight minutes in, so we sped up. By the time we'd shot half the shells, we were going as fast as we could light them.

Clean up went super-fast, just around an hour, and we got a bit of help of some of the community emergency response team folks in picking up garbage. While half the team picked up trash and raked, the other half loaded the mortars back on the truck, and that was that. Smooth sailing.

Our team was new to the fireworks game and they did a fantastic job. Big kudos to Ronda, Paul, Torin, K, Curt, Jessica, and Garth - you guys were awesome.

Really, there were only two small snafus we ran into.

First, I'm not super comfortable driving large trucks, and this was a pretty decent sized truck. I had a little bit of a mishap involving the gutter above my garage and the back of the truck due to some misjudgment in the length of the truck. No damage to the truck at all, but I'll be getting a new gutter.

Second, we had a rough time finding someone to open the gate and let us onto the field to start the setup. Sgt. Shawn Burns from Sandy Police totally came to our rescue with that and with anything else we needed all day - huge thanks to Sgt. Burns for all of the help!

After all was over we got several compliments from the people working security and from some of the spectators saying this was they best show they'd seen in years. That's really what makes it worthwhile - the cheer of the crowd and the ability to legally and safely light off some pretty amazing explosives.

Definitely a good show to work. It could have been a little cooler, but only having to drive an hour or so and easy clean up? Can't be beat.

UPDATE: Here's a video of the show from the crew perspective:

Getting the Windows OS Version in MSBuild

I saw a tweet come across asking how to get the OS version in MSBuild. MSBuild will automatically import any environment variables... but it appears the OS version isn't an environment variable, so it doesn't have any OS version info you can get out of the box.

You can, however, do a registry key lookup. Here's a quick MSBuild snippet showing how to get the Windows version out of the registry. If you want more version-related information, there's a lot in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DisplayVersion" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <OsVersion>$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion@CurrentVersion).$(registry:HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion@CurrentBuildNumber)</OsVersion>
  </PropertyGroup>
  <Target Name="DisplayVersion">
    <Message Text="Version: $(OsVersion)" />
  </Target>
</Project>

Granted, it would be kind of nice to have this out of the box, but at least you don't have to write a whole custom task for it.

Changing Windows Service Runtime Behavior with Typemock Isolator

Let's say you have a Windows service written in .NET that you got from a third party. It doesn't really matter what it does - maybe it monitors something or responds to web service requests or something. And let's say it works really well and does everything you need it to do... except this one little thing way down the stack is misbehaving.

You've done your homework - you've used Reflector and found exactly what the problem is, and it's just a small thing - maybe it reads from a fixed configuration location and you need it to read from somewhere else. Maybe it throws an exception because it isn't handling errors right. Whatever it might be, you have this boxed service that would be perfect for your needs if only this one thing could be fixed.

So what do you do? One option: Typemock Isolator.

WARNING: What I'm going to show you may make you feel a little weird. You may intially think "it's wrong" or something. But as you're thinking this, consider - what if this could save you a year of development time? What if it could save you a ton of QA time in testing every function of the service and allow you to focus only on the code path you've changed? From a pragmatic standpoint, would it be worth it?

ADDITIONAL WARNING: If you actually do this, it's all at your own risk. Seriously. It's all you, baby. "Works on my machine!"

Normally you'd think of Typemock Isolator as a testing tool. But its ability to run via the profiler API and substitute in behavior for just about anything makes it far more useful than just testing. For example, there's an aspect-oriented programming framework called CThru out on CodePlex that uses this functionality. In our case, we can use Isolator to fix up the problematic behavior in the boxed service. Here's how you do it:

Set up a service account that will have Typemock Isolator enabled on it. You'll want this to be a separate user account that doesn't do anything else because you're going to globally enable Typemock Isolator on any process that account runs. You probably don't actually want that on anything except this service you're going to fix up, so make it a dedicated account. You'll need to make sure this account has permissions to run as a service and has all the permissions it needs to run the boxed service - like if it reads from a certain file location, the account will need those rights. You'll get an "Access Denied" error if you don't set this up right.

Set the environment for the service account. To enable Typemock Isolator, you'll need to set a couple of environment variables. Run regedit as the service user:
runas /user:MACHINENAME\username "regedit"
Make sure you don't already have regedit open or this won't work. (It only allows one instance to run at a time.) Now navigate to the HKEY_CURRENT_USER\Environment key and add two string (REG_SZ) values:

  • Cor_Enable_Profiling = 0x1
  • COR_PROFILER = {B146457E-9AED-4624-B1E5-968D274416EC}

Yes, they look like numbers, but make sure they're string values. Setting those two environment variables will make it so any process that user account runs will have Typemock Isolator enabled.

Create a Windows service application. You'll be using the main entry point (Program class), but eventually won't need the actual Windows service. The Windows service in your wrapper project is helpful because it makes it easier to create an installer.

Add references. You will, at a minimum, need to reference the .exe file that has the boxed service's Main method. If the malfunctioning component is in a different assembly, you'll need to reference that, too.

Set up expectations and call the boxed service's Main method. Use Typemock Isolator to replace the problem code with code you want to run, then just let the boxed service execute as usual. Your Program class will probably look something like this:

public static class Program
{
  public static void Main()
  {
    ExpectationSetup();
    BoxedService.Program.Main();
  }

  public static void ExpectationSetup()
  {
    ReplacementComponent replacement = new ReplacementComponent();
    MalfunctioningComponent fake = new MalfunctioningComponent();
    Isolate.Swap.AllInstances<MalfunctioningComponent>().With(fake);
    Isolate.Swap.CallsOn(fake).WithCallsTo(replacement);
  }
}

Create a service installer. Open up your Windows service class in the designer. In the Properties window, give your service a name - this is what the user will see in the Services control panel. Now right-click on the designer for the service - the background of the designer, not any components that may be there - and select "Add Installer." This will add a class called "ProjectInstaller" to your wrapper application.

Set the installer properties. Open the "ProjectInstaller" class in design view. You should see a two components on the designer surface: "serviceInstaller1" and "serviceProcessInstaller1."

  • Select "serviceInstaller1." In the Properties window, check the ServiceName to ensure it's what you want folks to see in the Services control panel (it should have taken the name from your Windows service). Also set the StartType to be what you want - Automatic, Manual, or Disabled.
  • Select "serviceProcessInstaller1." In the Properties window, set the Account property to "User."
  • Right-click the designer surface of "ProjectInstaller" and select "View Code." In the ProjectInstaller constructor, just after the call to "InitializeComponent," update serviceProcessInstaller1 with the username and password for the service account you created. This will make it easier to install; otherwise you have to manually go in and set this later.

The constructor of ProjectInstaller will look like this:

public ProjectInstaller()
{
  InitializeComponent();
  this.serviceProcessInstaller1.Password = "password";
  this.serviceProcessInstaller1.Username = @"MACHINENAME\username";
}

Delete the Windows service from your project. You only really needed this to make it easy to create the installer. It doesn't do anything and you don't need it.

Build the service wrapper and place the executable in the same folder as the boxed service. The reason you want it in the same folder as the boxed service is because when you pass control on to the boxed service, it's going to need to find all of its dependencies and such. Rather than try to fight it into some other place, just stick that tiny .exe you just built into the folder with the boxed service.

Stop/disable the boxed service. If the service you're wrapping is installed, you need to stop and disable it. You can uninstall it if you want, but you're going to basically be running a different copy of the service and you don't want two running.

Use InstallUtil to install your service wrapper. With the installer class you made, it's simple:
installutil MyServiceWrapper.exe
(Obviously you need to use the name of your service wrapper .exe file there.) If you ever need to uninstall, it's just as simple:
installutil /u MyServiceWrapper.exe

Start your service and watch the magic happen. Typemock Isolator will replace the behavior you specified, just like it does in a unit testing environment, but it'll do it in a regular Windows service runtime environment. You may need to do some additional work if your boxed service is really complex, but it'll work. (For example, if the boxed service, BoxedService.exe, has a configuration file, BoxedService.exe.config, you'll need to copy that for use by your wrapped service  - MyServiceWrapper.exe.config or whatever. That way the .NET configuration system will work... but that sort of tweak will be specific to the boxed service you're wrapping.)

HOLD THE PHONE. What's the performance impact? Honestly, I don't know. You'll have to measure a before-and-after on your own system and make your own call. You'll probably also want to balance that out against how much time something like this will save you, etc. It's all trade-offs, right?

SAMPLE CODE! WE WANT A SAMPLE! I created a little sample so you can see what this looks like. In the solution, you'll find two projects - "BoxedService," which has a malfunctioning component in it that we want to fix; and "ServiceWrapper," which has the Isolator expectation setup that fixes the behavior. Both of these services write to Trace so you'll want to have DebugView so you can watch the trace output without having to fight with the debugger. Debugging a Windows service is painful.

If you install the BoxedService, you'll see an error message get periodically written to Trace; uninstall that and install the ServiceWrapper (running under an account that has Isolator enabled) and you'll see the problem behavior get replaced.

[Download ServiceWrapperDemo.zip (20K)]

posted @ Wednesday, July 01, 2009 10:41 AM | Feedback (0) | Filed Under [ .NET ]