How to automatically notify the user that it's time to upgrade a Windows App
Back in 2007 I did a post called Making your Application Automatically Update Itself. Yesterday I was pairing on a little startup I'm doing on the side with Greg Shackles and it was time do the setup application. I thought about WiX, I thought about InstallShield, but then discovered a wonderful little gem of a setup application called Inno Setup by Jordan Russell. It's free, but it's a joy and you should donate if you use it.
It took me just 15 minutes to make a simple installer, and it's clear that this tool is deep and broad in its support. However, there's no free lunch when it comes to auto-updating. Inno Setup will upgrade my app from build to build when I run a new setup over the top of an old one. I still need my app to notify the user that it's time to upgrade.
This is our little 10 minute solution, but it's actually working very nicely. Inside the latest.txt files is a simple version string like 0.9.9.4.
var http = new HttpClient();
string versionString = await http.GetStringAsync(new Uri("http://www.hanselman.com/SecretStartup/latest.txt"));
Version latestVersion = new Version(versionString);
//get my own version to compare against latest.
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
Version myVersion = new Version(fvi.ProductVersion);
if (latestVersion > myVersion)
{
if (System.Windows.MessageBox.Show(String.Format("You've got version {0} of SecretStartup for Windows. Would you like to update to the latest version {1}?", myVersion, latestVersion), "Update SecretStartup?", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Process.Start("http://www.hanselman.com/blog");
}
}
I'm thinking:
- We'll add an SSL certificate and confirm its identity on the HTTP call as a little added security.
- Error Handling, natch.
- One could also download the setup app to %temp%, check it's SHA hash, launch it and close myself. Not sure I like it this automatic, though.
- Maybe only check the version once a day or once every few days.
Comments?
Sponsor: Big thanks to Red Gate for sponsoring the blog feed this week. Check out the Free Starter Edition of their release management tool! Deploy your SQL Server databases, .NET apps and services in a single, repeatable process with Red Gate’s Deployment Manager. Get started now with the free Starter Edition.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Sadly not that wellknown for what was a nice tech in a pre app-store world.
I'll check out Squirrel and NorthernLights. Somehow I thought NorthernLights was mostly Windows Phone.
I've used Inno Setup (great product) too; and implemented almost the same code to check for updates in my first app. I made it up, and thought it was a bit of an amateur hack (because I made it up) - but seemingly not. I did want to use the VS(express) to create the installer but struggled getting a "single file". Perhaps if I RTFM it wouldn't have been such a problem.
Here's the most damning aspect of it: if you sign your ClickOnce application (which you are required to or else ClickOnce's installer displays scary "Don't Install This" messages), then the cert expires, every user has to uninstall and reinstall. Completely untenable.
if your application targets .NET 4.0, or your application is not an Office solution and it targets.NET 3.5 and uses automatic updates, or none of your customers have Windows Vista, you can just replace your certificate, issue an update
OH THAT'S RIGHT. IT DID BUT MICROSOFT KILLED IT AFTER VS2010!!!
Sigh...
https://github.com/synhershko/NAppUpdate
Thanks for this post -- it and the comments present some good choices.
This was truly epic moment, I know now that there is still hope for humanity and Windows :) .
Nowadays MSI is a basic requirement, so WiX is the open source solution if you have more time than money. I for one prefer to rely on the wonderful folks at Advanced Installer. The included updater is small, well thought out, fully featured but flexible and well tested in the wild.
Just thinking about all the scenarios like per-user/per-machine, elevated/non-elevated updates and so on makes my head explode...
This is one thing I'd really like to see Microsoft help manage through windows update or something, some kind of built in updater that people could send their url / files to like Nuget for Visual Studio.
Click once is a pain to manage in a release environment.
Have you used Inno Setup in a continuous integration build environment before?
The only downside is no MSI support althought I suspect that is also one of the reasons it is so good.
We have integrated it in Jenkins through Nant. It's not very difficult : you launch "ISCC.exe" with the script path in parameter. We also have a batch to sign our exes and setup packages.
Updates are handled through that system then ...
Updates are handled through that system then ...
Updates are handled through that system then ...
Combined with Inno Setup for initial install and DB Ghost for managing upgrading of database schema and records we have a solid deployment/upgrade solution for our enterprise sized software. Both are commercial systems, but well worth the reasonable licensing fees.
The Northern Lights link does say, "Northern Lights WP7 Toolkit contains some common tools for WP7 Developers."
BTW, thanks for the code; I'm going to see if I should refactor my auto-update code with it.
The Northern Lights link does say, "Northern Lights WP7 Toolkit contains some common tools for WP7 Developers."
BTW, thanks for the code; I'm going to see if I should refactor my auto-update code with it.
Nayway, here is my gist showing how I download updated files to a Windows client from an ASP.NET Web API server app:
https://gist.github.com/bclayshannon/9667160
However, with your solution, since you're rolling your own, you might want to have a "Stable" and a "Beta" line, like "Stable:0.9.0.0" and "Beta:0.9.9.4", giving yourself "channels" like Chrome, so that you can have power users select a Beta channel and get updates faster to help you iterate if they aren't afraid of possible bugs. This also lets you test internally with a Dev channel.
I also like the idea of silently downloading the installer and executing it silently when the program closes or tell the user via an unobtrusive icon that one is available (again, a la Chrome). When you ask the user to make a decision, the user typically chooses the path of least resistance (clicking "no" or "later").
I'm not sure who the audience of SecretStartup is though. Knowing you, it is probably a more technical audience, but I think we all enjoy Chrome's update mechanisms.
- ClickOnce is basically a black boxed version of XCopy; it leaves you with few recourses for your end users if something goes horribly wrong during an upgrade (1 in a million is next tuesday). There's no way to drive people back to your site or contact number if something goes wrong, either, so instead of making communication easier it does the opposite in my experience.
- ClickOnce certificates are a nightmare. Issuing new certificates is easier said than done when people are hosting your CO installer in a disconnected environment. Installers should validate via hashes, leave certificates to the OS.
- ClickOnce has virtually no support for customized installations. You need something special done? Hope you're good at updating app.config files. Which by the way can get blown away by all kinds of standard things; i.e. adding files. Also MAGE is just so complex to use and requires all sorts of magic handshakes to get an application built if you don't toe the standardized line.
- It's sloooowwwww. I can install /qb MSIs faster than our ClickOnce project.
This coming from ~8 years of varying degrees of install dev support, writing updaters, installation dev, etc. I've seen most of it all :-)
Also Chrome has the right update experience. I don't know why apps even bother to ask a majority of the time. When I close the app it should update - with an indicator it wants to do so. If you need to set out of band updates (say major upgrades not chrome style) then approach those ad-hoc. But a majority are just like "Would you like to install these critical bugfix/security patches we released?"
From a dev point of view, any time you make an update optional people won't install it. I wish I could access the very depressing A/B testing we accidentally did on this, but it's blocked. Perhaps others' mileage varies, but this was several widely distributed consumer apps :)
@Thomas - Inno itself is written in Delphi (Object Pascal). I like both Object Pascal and C# (peace) :)
If I open the application, I want to use it. Rarely will an update be interesting enough for me to actually perform it before I get to do what actually I intended to do when opening the application.
If I open a video file in VLC, I'm not interested in updating, I'm interested in watching a video. Exceptions can be made for seriously important updates (security-wise) or actually required updates (an online multiplayer game needs to be updated asap so as to be able to connect to the game servers), but definitely not for every update imagineable.
I'd love it more if those types of questions were asked either at the end of the application (shutting down, then mentions it can update itself), or allowing the prompt at startup another option, i.e. to download the update in the background and start installing it when the application is being shut down.
Am I overlooking something?
There's another thing which hasn't been mentioned yet: with this autoupdate system, the software vendor can also track the number of times a tool is used and by whom and when (one can send as much info as possible in the call to the service to check whether there's a new version, it's unclear what's being send).
As a software vendor this is great, as a user I definitely don't like it: I don't want to leak whatever I do on my PC to whatever 3rd party is out there. This is one of the reasons I haven't implemented it yet in my own software, although as an ISV I'd be very interested who uses the software when and how many times a day.
So IF a vendor is implementing it, at least add an option to disable this. Which mitigates the feature, I know, but it also gives more peace of mind. At the moment I have no idea what is send along the 'phone home' request in various apps.
The main reason I didn't like ClickOnce is because your application is no longer a real application.
You can check out my simple updater here:
http://jvance.com/pages/SimpleUpdater.xhtml
That rules it out for use in terminal services and a lot of domain environments. For me if it doesn't work for all user profiles it doesn't work.
It doesn't work because ClickOnce apps install into %localappdata%\Apps only the local app data folder isn't stored in your roaming profile so when you log off you lose the install. We have an app that does this at work and its an absolute nightmare.
What we really need is a way for windows (desktop) apps to register for updates. Then windows takes over downloading and where possible installing updates.
the room. Remember to include luxurious sheets and blankets, plush
pillows, and most importantly, a comfortable mattress.
Stays super sharp with just a little touch up now and the with included honing
steel.
With installshield, setup creation had to be part of the planning and took a reasonable amount of time. With innosetup, building a setup for our software is a task that takes little or no time and it allowed us to create an environment for automatic publishing/distribution of our software via central web service that publishes versions for the different modules.
But every solution has it's downsides:
MSI: Single instance install induces problems with multiple software installing at the same time, like when Windows Updates decides it's that time of the week. Working with different tech support teams saw a lot of issues with crashed Windows Installer Service that would no longer respond (solution was to un-register the service and re-register it). Also there's a chance Windows Installer is in a limbo state (Restart needed for changes to take effect). Sadly MSI is far from stable or perfect even for Microsoft products. Also MSIs use CAB compression and these are not the dark ages. Now we have proper compression algorithms and huge processing power / memory.
Other installer scripts (NSIS, Inno Setup, etc) seem to work more or less on the same principle.
Clickonce: Installer main purpose is to install prerequisites. Using Clickonce you suppose the user already has a Clickonce compatible .NET Framework version ( and you would be wrong in lots of cases where users own an XP OS )
If your app has nothing complicated to deploy, you'd be better off having a self-extracting archive :)
As for updates:
After many experiments it seemed like a really bad ideea to trigger updates at system startup - I've experience a multitude of issues like really bad internet connection, a lot of processes hugging up the whole memory ( like Antivirus engines, Chrome etc) leaving your app prone to weird issues.
Don't ask the user for an update. Everyone hates it, especially when they are starting your app. If you can, download the new version silently, store it side by side with your app, and trigger a swap between the current version and the update at the next app launch. If something fails, make sure you can rollback.
Make sure you have some kind checksum in order to check if the thing you downloaded is not corrupt. Don't give up on the first try, retry the downloads. Catch exceptions.
If you want to optimize you could always use Torrents depending on your app size. Download update patches instead of full version. Download binary differences instead of files.
Statistics. You should be able to track everything. Be able to update the update system. Unexpected errors happen ALL the time.
Something to always consider about updating a user's software in this way is a user's permission level. I have written (more than once) frameworks that do things like performing the check in user context, while performing the installation under system context to avoid any untidy group policy lockdown issues.
Inno and the technique above have really helped us to extend the usability of windows applications in a web application world.
P.S. Friends don't let friends use ClickOnce
Comments are closed.
http://northernlights.codeplex.com/
No need to re-invent the wheel.
Same concept, but perhaps a little bit more error handling etc.