I'm writing this specifically for developers who need to add links into HealthVault Connection Center, but I think the topic is of general interest to anyone who wants to create installer packages.
We're going to be using the WiX (Windows Installer XML) toolset to create msi files.
Note 1: While I find the mixed case "WiX" name quite enjoyable, I'm just going to use "wix" in the rest of the writeup
Note 2: There are some good wiX tutorials out there that you may find useful.
Step 1: Get the tools
Find the Download section on the right side of the WIX home page. I'm basing this on the "Version 2.0 (stable)" bits. If there are newer bits, they might work, and then again, they might not.
Off of that link, you'll find a link to the binaries zip file. Unzip them, and put them in a directory (I found "g:\wix" to be an aesthetically pleasing location).
Step 2: Read the docs
I know that you're going to skip this step, just like you skipped the instructions on the new circular saw you bought last weekend.
If you want to actually read the docs, there are some in the "doc" directory, and some online. But I prefer skipping to the next step.
Step 3: Understand the tools
Wix files use the .wxs extension. If you run the wix compiler over them ("candle"), you end up with a .wixobj file. Running the wix linker ("light") generates a .msi file.
Step 4: Build your first MSI
Here are the bare-bones of a .wxs file:
<?xml version="1.0"?><Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> <Product Name="Fabrikam WidgetTracker" Id="PUT-GUID-HERE" Language="1033" Codepage="1252" Version="126.96.36.199" Manufacturer="Fabrikam" UpgradeCode="PUT-GUID-HERE">
<Package Id="PUT-GUID-HERE" Description="Fabrikam users can use this to track their widgets" Manufacturer="Fabrikam" InstallerVersion="100" Compressed="yes"/>
Most of that is pretty self-explanatory, though I do want to talk about the IDs.
The ids are GUIDs that are used to keep track of things. I won't go into the details because I they're sorta complicated, but basically, the "id" field unique identifies the product and the package within the product. Whenever you release an MSI with any different bits, you need to have a different product id or the installer will think you've already installed it.
Packages also need to be unique, and change when their contents changes.
UpgradeCodes are also GUIDs, but should never change. They are the mechanism that the installer uses to figure out that you're doing an upgrade. If the upgrade scenario is important, you need to set it.
So, to recap, product and package ids need to be unique and generated for each release. UpdateCode should be generated once, and you use that same updatecode for the life of the product.
You do the generation with uuidgen.exe. You can download that with the Windows SDK, or use one of the online generators.
This package does very little, but the way, but you can install and unistall it.
A nice Halo 3 review
One of my readers asked whether there were any UI unit testing tools.
While I have seen some ASP.net tools like this, in general I'd expect that you would unit test a UI by making the UI a very thin layer (one that doesn't really need testing), and writing the unit tests to talk to the layer underneath.
Though I haven't had the opportunity to try it on a full project, I think that Presenter First has a lot going for it.
One of the confusing parts about HealthVault development has to do with certificates. If you've never worked with certificates, you might want to read this.
Under HealthVault, information is controlled based on three keys
The user id is determined by who is logged into HealthVault. The record id identifies a specific health record, and is necessary because HealthVault allows "custodial" access (my mother might grant me access to her record, for example).
The application id uniquely identifies an application to the HealthVault server, but the application id isn't enough for the server to know that the application id *really* came from the application that we think it was.
That authentication is provided using a certificate that is registered by the server. Through a bit of public/private key magic, the HealthVault server can authenticate that the request really is coming from the proper application.
That has a few consequences for application development.
First, it means that you need to use an application id and certificate that the server recognizes to do your development. The development server recognizes the application id and certificates for the sample apps, so you are free to use those during your initial development.
That certificate must be registered and accessible to the web server process that's running on the machine. If you look in the 'cert' directory of the samples, you'll find a readme that explains this. Note that if you are developing with the VS web server, you need to grant NETWORK_SERVICE the access, while if you're using IIS, you need to grant access to ASPNET.
Using one of the sample certificates is what we call the "anonymous development scenario".
I omitted many details, but that's the basic idea.
Astronomers have a concept named "First Light".
After years or even decades of work, a new telescope is finally ready for to be used. You point it someplace interesting, open up the shutters, and the first light enters the instrument. And you find out whether your hard work has paid off.
Usually it does, but sometimes you end up with something like this:
So, it's always a exciting and worrisome time.
Back in 2000, I was lucky enough to be involved in the initial release of C#, and the sense of excitement was palpable. We were pretty sure the reception would be positive, but it was the oppressively hot PDC in Orlando in July that confirmed it.
Today, I'm lucky again - we have shipped the beta of Microsoft HealthVault. And as much as I enjoyed C#, I think that HealthVault has the potential to have a bigger impact on the world, because healthcare is something that impacts everybody.
There's an MSDN dev center and a HealthVault developer blog for developers who are interested, and I'm planning on doing some posts on this blog as well, now that, for the first time in perhaps 3 years, I'm able to talk about what I'm doing.
Though I've been a bit too busy to take a "Halo day" off this week, I have spent a bit of time playing, and I can say that I'm pretty happy.
I really like the "get out of this room" waypoints that pop up when you get stuck someplace - those are an elegant solution to the problem.
And I'm also like the multiplayer, though not knowing the maps is causing some issues ('cause otherwize my mad skillz would rul3z).
But, I've been wondering what is to come in the future. LoadingReadyRun has provided a preview...
Halo 3: The future of gaming...
(and you can find me as Triabolical)
From Jim Newkirk, one of the original NUnit authors...
future? House? Garden Shed? Toybox filled with action figures?
Last weekend, I spend a day or so replacing a couple of outside doors at my ski place and adding security gates. The work itself was mostly uninteresting, but I had a problem.
Each door and gate had both a deadbolt and a handle, so that means 8 locks in total. Which meant that I needed to have 6 locks re-keyed so that they would all use the same key.
Which would be somewhere in the $60 - $90 range. If I remembered to bring in a couple of deadbolt cylinders that I have at home (and are keyed differently), that would be $80 - $120.
Hmm. In these parts, that's what the call "tool money".
Tool money is the amount that you can use to justify a new tool purchase. By choosing projects appropriately, one can get the tools and still end up saving money, on the theory that that you would have done the project anyway, which has been known to be true at times.
Which led me to a few web searches, where I found the:
Schlage Rekeying Manual
Which made things look pretty straightforward, so I found the:
Schlage Lock Retail Keying Kit (40-132)
It showed up a week or so ago, and I sat down to redo the locks.
It's really a pretty straightforward process. Basically, you loosen whatever needs to be loosened to get the cylinder out, and then press it out with a special tool that's the same size as the cylinder. That holds the pins in so they don't get pushed out by the springs. You then let the sized pins drop out, put in the new key, and then replace the sized pins with the appropriate ones for the new key. Reverse the disassembly, and you've rekeyed a lock. The knobs take about 5 minutes, the deadbolts a bit more.
If you mess up the knobs, there's a second option that involves taking everything off and then replacing both sets of pins and the springs. It takes another 5 minutes.
If you mess up a deadbolt, well, you're in for some fun. You have to replace the springs and the normal sized pins one at a time, adding a new one while holding the others in. That took me an extra 20 minutes.
Overall, it's pretty easy to do.
From the ever-popular Worse Than Failure, comes this post
Those of you who remember my work on Microsoft Windows Vista Windows DVD Maker may wonder if the last screen in the post is from DVD Maker.
It is not.
First off, while it is a wizard UI, it is not the DVD Maker UI.
Second, I fixed a startlingly similar bug in DVD Maker pre-ship.
This is pretty common when you're doing a combo box in a wizard. You put all the combo box entries into separate resources strings - so they can be localized into other languages (though I'm not sure how "8x" localizes...) - and when you come to a page, you grab them the strings out of a resource file and stuff them in the combo box.
Which works great the first time, but if you're writing a wizard, you may have forgotten that the UI sticks around even if you hit back/next a few times, so the strings you put in the combo box supplement the entries there rather than replace them.
O'reilly publishes Beautiful Code
Jonathan Edwards counters with a beautiful explanation.
Now, I haven't read the new book, but I have a strong resonance with what Edwards wrote. You should definitely read the whole thing, but I few sentences jumped out at me.
A lesson I have learned the hard way is that we aren’t smart enough. Even the most brilliant programmers routinely make stupid mistakes. Not just typos, but basic design errors that back the code into a corner, and in retrospect should have been obvious.
It seems that infatuation with a design inevitably leads to heartbreak, as overlooked ugly realities intrude.
If there's anything that agile says, it says that we should build things simply and with a eye to revision because we not only are we "just not smart enough", there are too many unknowns when we start.
The problem with "beautiful code" as a concept is that it is closely related to "beautiful design", and I've mostly come to the conclusion that any design effort that takes more than, say, 30 minutes is a waste of time.
The concept also gets confused about what the goal of software is anyway. The goal is not to have beautiful, elegant, code. The goal is to have *useful* code that does what you need it to do.
Discuss and comment
Here's one I've been playing with for a while now. You may have it unwrapped as a salad, or in some sort of tortilla-based containment vessel.
Fish Salad / Fish Tacos
If possible, drain the yogurt in a coffee filter for an hour or so to get rid of some of the liquid part. Add sugar to taste (you want to get rid of most of the bite of the yogurt, but not all), salt and pepper to taste, and then a dash or two of cayenne (yes, it needs it, but it takes an absurdly small amount, so go slow). Crush garlic clove, add to mixture and mix, set aside.
Dice tomato and onion, cut other vegetables in to thin strips. You can use cabbage if you must but don't invite me over. Put them all in a bowl, add the sauce, and mix.
Cut up and bread the fish. You could use an egg wash, but I normally don't. You should probably do the breading before you make the sauce.
Heat up a nice saute/frying pan on medium heat, add a bit of oil (peanut works well), and then add the fish. Distribute it so as much is touching the heat as possible. Add more oil if necessary. Stir (or toss if you have the chops) every 30 seconds or so, and cook until done (which for salmon means a little pink on the inside, or perhaps even a little rarer). If you overcook a nice piece of fish I'm coming after you.
Remove from heat, stir salmon into bowl, serve immediately.
Serves from 1-4 depending on how hungry you are.
In the summer of 1980, I bought my first stereo. And then I started to buy records, though I'm not sure what my first purchase was. I've probably blocked it out because of the whole Christopher Cross/Air Supply thing.
What I do remember is that my good Pam - who I spent 4 years with in independent-study math - and I had a deal. I would buy a record, and she would buy two tapes, so we could each have one (she had a cassette deck in her car but no stereo at home).
And the first record that I bought for this was...
27 years later, I took my 13-year-old daughter (and my wife) to see Rush at the White River Amphitheater, for the "Snakes and Arrows" tour.
Before the concert, I had two big questions in my mind.
The first question was whether, to put it simply, they could still rock. After all, they're all in their mid-50s these days, and there aren't many active rockers that age any more.
The second question was what songs they would play. When a group has created 18 studio albums, they have around 200 songs that they can choose from, and of course I had my own personal favorites I was hoping to hear.
The answer to the first question is a resounding "yes". The band was musically tight. And despite having 30 years of rock on his voice, Geddy Lee has lost a surprisingly small amount of his vocal range. Lifeson and Peart are as good as they've ever been. And they are clearly enjoying performing.
The second question had an interesting answer. Here are the songs I remember, in album order (freewill was first, YYZ was last).
There's something very interesting there. First, there are no songs (unless I missed some) from the last 5 albums (PW, HYF, Presto, RtB, VT). Second, they are all themetic in nature - along the lines of the new album. For me, there were a couple of nice surprises - Entre Nous and Natural Science have alway been favorites of mine.
The sound was pretty good. The shape of the amphitheater helps, and the fact that there are no back and side walls means there are fewer reflections. The sound level wasn't Green Day loud, but I was still happy to have my Etymotics ear plugs with me.
The Trojan Horse
If you have web presence, a very interesting activity:
Go to Google maps, and type in your name. Here's what you get from mine...
From Phil Plait
I'm working on customizing my new blog, and part of that is adding some image content above the link section. I can do that directly be editing the theme.master file (I'm using community server), but I'd like to be able to do it through the CS dashboard.
I've put in a div named EricBlogPictureLinks, but I can't figure out how to set the innerText property through CSS. Is it possible?
The recently-completed fence in the Gunnerson backyard. The fence is 4'1" high and runs about 80 feet across the yard.
The wide boards are 5.5" wide, and the thin ones are 2" wide. Posts are embedded in concrete 18" deep, all the framework is pressure-treated, the cross-rails are attached with Simpson Z-max angles, and the boards themselves are attached with stainless steel fence nails (so the boards don't stain).
Total cost - somewhere around $1000.
Total time - longer than I had hoped - especially since all the thin boards had to be ripped.
Saturn's moon Hyperion, from the Bad Astronomer. Make sure to click on the image to see the full-size version.
A follow-on to the previous discussion about member names.
There were a variety of opinions, some of which argued for using no prefix at all.
For those of you who are in the group, I'm interested in how you manage things when you are doing UI work, and having to deal with your 3 member variables being swallowed by the 100 methods already defined in the base class.
Is this an issue for you? If so, how do you deal with it?
For a while I've been toying with the idea of writing more about cycling than I have in the past - as I seem to have developed a passion for the sport - but too much of any one thing isn't good in a blog (as evidenced by my earnest desire to avoid to much useful C# stuff).
So, I've had things I wanted to write about but didn't. A little time spent installing community server on my hosted site and the simple purchase of a domain name now lets me introduce my new cycling blog:
If you also have that passion, please stop by.
I will still reference major events here, whether they are cycling-related or not.
Thanks for your comments.
I decided to go ahead and write the unit tests for that layer, both because I knew what not writing them would be like, and I wanted to play with wrapping/mocking a system service.
I also decided - as some of you commented - to do the right thing and encapsulate it into a class. That would have happened long ago, but though I've written it several times, I don't think I've ever duplicated it within a single codebase - and the codebases where I did write it are pretty disparate. Now, I have something where I could at least move the source file around...
Writing tests for this was a bit weird, because in some sense what I needed to do was figure out what the system behavior was, break that down, write a test against my objects, and then write mocks that allowed me to simulate the underlying behavior.
So, for example, I created a test to enumerate a single file in a single directory, wrote a wrapper around DirectoryInfo, and then created a mock on that object so I could write GetFiles() to pass back what I wanted. And so on with multiple files, sub-directories, etc.
So, I did that, went to write the little bit of code that I needed in the real version (to use the real GetFiles() calls and package the data up), hooked it up to my real code, and it worked.
*But*, when I went back and looked at the code, I found that what I had really done was create two sets of code. There was the real code that called the system routines and shuffled the data into my wrapped classes. And then there was my mock code that let me control what files and directories got returned. But there wasn't any common code that was shared.
So, my conclusion is that I really didn't get anything out of the tests I wrote, because the tests only tested the mocks that I wrote rather than the real code, because the only real code was the code that called the system functions.
In this case, TDD didn't make sense, and I will probably pull those tests out of the system.TDD may make sense the next level up, where I've written a new encapsulation around directory traversal, but it seems like the only code there is hookup code.
So, the result of my experiement was that, in this case, writing the tests was the wrong thing to do.
I've been writing a small utility to help us do some configuration setup for testing. It needs to walk a directory structure, find all instances of a specific xml file, and then make some modifications to the file.
I TDD'd the class that does the XML file stuff, and I'm confident that it's working well. I'm now going to do the class to walk of the directory structure and find the files.
And there is my dilemna. I don't know if I'm going to do TDD on that.
I know exactly how to write it, I've written it before, and my experience is that that is code that never changes nor breaks. And, figuring out how to write tests for it is going to be somewhat complex because I'll have to isolate out the live file system parts.
So, I've already decided what I'm going to do, but I'm curious what you think. Does YAGNI apply to test code, or is that the first step to the dark side?