ClickOnce, Squirrel and Nuts

Update 10/2016 - This posting is better viewed in my new blog.

Background

In a post two years ago I expressed my admiration of ClickOnce. At the time we'd experienced years of tremendous success using it as our client application's primary deployment mechanism and since that time it has not faltered.

I now regret to say that over the last year I've seen evidence that makes me question continued reliance on ClickOnce. I think its life-cycle may be coming to end. Though that saddens me I understand that in the tech world all technology is transient and the best ideas don't always last as long as they should (see Silverlight). Data, however, must continue flowing.

About eight months ago I started searching for alternative deployment mechanism which might provide some of the benefits we'd leveraged with ClickOnce. That search came up mostly wanting. However, one candidate identified was the open source project Squirrel.Windows. The moniker on the GitHub project page says "Squirrel: It's like ClickOnce but Works". I took exception to that statement since for us ClickOnce has provided nearly flawless performance over a decade of heavy use but it got my attention none the less. After a little investigation I decided it might be worth a deep dive into Squirrel. For that purpose I created the Nuts application.

Overview of Nuts

My goal in creating the Nuts project was to explore Squirrel deployments and gain practical experience with the library through testing of deployment scenarios. Specifically, I was interested in how Squirrel handled updates. ClickOnce updates work beautifully, only downloading files newer than those currently installed. I wanted to ascertain whether Squirrel's delta packages provided similar behavior.

Nuts is a .NET application consisting of three projects, Nuts (Windows Forms), Nut.Acorn (class library) and Nut.Walnut (class-library). All logic is contained in the Nuts project. Class libraries exist only to explore versioning scenarios.

Figure 1. Nuts on first run after clicking the List Versions button.

The List Versions button displays basic information about the assemblies found in the current run-time environment, Clear Messages is self evident and Debugger calls System.Diagnostics.Debugger.Launch(). The Check Nuts and Update Nuts buttons both instantiate a new instance of Squirrel.UpdateManager. Check Nuts stops after checking for updates while Update Nuts continues to apply available updates.

Procedure

In my exploration I modified Nuts multiple times to create four separate Squirrel deployment versions. I initially ran Setup.exe from version 1.0 and from then ran Nuts using the shortcut created by that initial setup. For each new version I used the Update Nuts button to download and install. The four versions were as follows.
  • 1.0 - Initial deployment generated following the Quick Start from Nuts project README.
  • 1.1 - Changed the version in the Nut.Acorn library.
  • 1.2 - Added a large file to the deployment package.
  • 1.3 - Changed the version in the Nut.Walnut library.

Results

When the Setup.exe file was first run it "installed" Nuts in the user's AppData folder (Figure 2). The initial install created the app-1.0.0 folder, packages folder and Update.exe file in the installation directory. In addition a desktop shortcut was created as was an entry in the Windows Programs and Features list. Examination of the shortcut showed its target was the Update.exe file with an argument named processStart which had a value of Nuts.exe. The start-in for the shortcut was set to the app-1.0.0 folder. Each successive application update would add a new app-{version} directory and modify the start in directory of the shortcut to reflect the new version folder, e.g. app-1.1.0 for the first update.

Figure 2. Nuts install directory after four version installs.

Figure 3 shows the Releases folder (created by Squirrel) after the Squirrel command releasify has been applied on each of the four versions of the Nuts NuGet package.
Figure 3. Releases folder contents after all four version packages have been created.

Discussion

Initial installation of Nuts was flawless. Squirrel provides a mechanism to include an animated .gif to display during initial deployment but I didn't experiment with that. Successive updates were equally solid however, the mechanism of updating the shortcut's start in directory with a new version's installation path does present one possible annoyance to the user. When a desktop shortcut is updated in this manner is can re-position the icons on the user's desktop. For users who maintain a significant number of desktop shortcuts this can be problematic.

The generation of the deployment packages through the Squirrel releasify command worked fairly well though I did encounter issues attempting to call releasify more than once in a single Visual Studio session. Searching through Squirrel issues on GitHub I found it suggested this may be related to a bug in the Package Manager Console and not Squirrel itself.

The releasify command relies on the existence of the output from its previous executions in order to generate delta packages. This means the historical contents of the Releases folder must be kept in some type of repository to facilitate delta package deployments. This type of binary package tracking is not a typical development pattern and thus could necessitate modifications to build/release methodologies for teams that wish to utilize Squirrel deployments.

Comparison of the final .nupkg file sizes (Figure 3) with the four exploratory versions clearly indicated that Squirrel created deltas that were appropriately sized. Network monitoring further confirmed that delta download size on clients was as expected. How Squirrel handled deltas was one of my primary concerns and it appears that it handles them very sensibly.

Conclusions

Squirrel's performance was exemplary throughout my testing. It appears to be an admirable substitute for ClickOnce in the realm of Windows desktop application deployment. One lamentable difference is that ClickOnce installations (when deployed in online only mode) are guaranteed to run the latest deployment at each startup while Squirrel will not utilize the latest bits until the run after an update. The only other consideration I encountered was that while ClickOnce only retains two installations (current and previous) it appears Squirrel does not perform clean-up on previously installed versions so some sort of application level clean-up procedure would probably be necessary.

At this point I have no hesitation in recommending Squirrel. It will likely be my go-to method of Windows desktop application deployment going forward.

Comments

  1. Nice article. By the way, Visual Smarter has alot of tools. You may like it.

    http://visualsmarter.blogspot.com/

    ReplyDelete
  2. Squirrel is wack. Is it possible to run ClickOnce as administrator?

    ReplyDelete
    Replies
    1. I've certainly never seen a way to run a ClickOnce app as administrator. Squirrel definitely has some limitations but it's by far the closest alternative to ClickOnce that I've seen. Since ClickOnce is definitely nearing the end of its life-cycle concessions will likely have to be made.

      Delete
    2. Yes it is possible to run ClickOnce as administrator. I have a WPF application in production that does so. But ClickOnce doesn't support out of the box, you have to tweak it a little bit in order to run as admin. There was a blog giving the basic steps to do so, but I can't find at the moment.

      Delete
  3. I don't think Microsoft has ever stated they were "terminating" Click-Once but they did stop forward development on it quite a long time ago. For a while Microsoft's Edge browser didn't support it but that has recently changed. I think Click-Once still has legs even two years after I posted this but I wouldn't base new application deployments on it.

    BTW, I did write a follow up to this post with some additional thoughts if you're interested. https://developingdane.com/squirrel-and-nuts-the-clickonce-free-sequel-2/

    ReplyDelete
  4. Yeah, there's definitely some trade-offs. The start-up wrapper is a little clunky but that's how Squirrel manages to allow you to check for new versions, download and run them prior to the application itself starting. i think you could stop a second version of you app from running though by using System.Diagnostics to pull current running apps at start and then terminating prior to displaying any UI if it finds a version already running. Again a little clunky but I've had to do something like that before and it can be made to work.

    ReplyDelete

Post a Comment

Popular posts from this blog

How HTML5 destroyed my CSLA dream

A Walk Through Azure Functions