ClickOnce Is a Complex XCopy
ClickOnce was designed to make deployment of applications easier. The goal was to allow a user to start using an application without having to install it. Additionally ClickOnce was suppose to allow developers to auto-update their applications without having to write hardly any code. One of the premises of ClickOnce is that you don’t need to be an administrator to use a program. Overall it met these goals. The reality though is that ClickOnce is horribly, horribly out of date for the modern times and yet Microsoft continues to push it as “the” easiest deployment strategy. My recent attempts at using it for a simple client application met with a resounding failure.
Here’s the list of benefits ClickOnce supposedly brings to the table.
- Publish an application to a website or file share
- Does not require administrative privileges to deploy or run
- No setup program needs to be run but an application can still add itself to the Start Menu, Desktop and create an icon in Programs and Features
- Automatically update an application with only a handful lines of code
ClickOnce does all this but unfortunately it is simply too old to be useful in modern .NET applications. Let me identify the areas where I had trouble when I recently tried to use ClickOnce.
Publish Our Way… Or Else
In my particular case I need to be able to control how publishing occurs based upon whether a client has a web server (unlikely) or file server available. Ideally I would like a user to be able to enter a URL into a browser and my application automatically downloads and runs. Think WCF service here. Unfortunately ClickOnce doesn’t support this approach. Even worse is that, unlike almost all of the .NET Framework, it is completely locked down so you can’t even override the implementation. You’re stuck with the publishing options that ClickOnce exposes. Who thought it was a good idea to completely prevent extending ClickOnce? If there is anything we’ve learned over the years it is that developers like to extend things. Here ClickOnce just doesn’t have the flexibility, or extensibility, needed to allow custom publishing options.
No Administrators Here – Ever
One of the important features of ClickOnce is the ability to run an application without administrative privileges. This is important and useful for a lot of applications. However with the advent of Vista and UAC the rules have changed a little. It is now more common to have an administrative application run as a normal application until such time as administrative privileges are needed.
Visual Studio allows you to add an application manifest to your application. The manifest contains a variety of things but on the security side it allows you to specify how you want to support Vista and UAC. On one side is the default setting where UAC kicks in when needed. But on the other side is an option to require administrative privileges automatically without requiring the user to change shortcut settings or anything else crazy like that. Yes there do exist applications that require administrative privileges.
Once again ClickOnce will thwart your efforts. If you have an application manifest with UAC settings in your application then ClickOnce won’t work. Why? I have no idea. It seems that the designers of ClickOnce thought that this requirement meant that an application shouldn’t be allowed to have administrative privileges, ever. Hence if you plan to use a manifest to control UAC then you can’t use ClickOnce.
No Setup Required – Even If It Already Exists
ClickOnce gets this one mostly right. You don’t need to install any files to get a ClickOnce application working. But what if you need to install some additional files. Well then you are going to have to ditch ClickOnce. Sounds like a fair tradeoff but here is one very big gotcha – this includes versions of system binaries that have been around as long as .NET.
Specifically I’m talking about the v6 Common Controls added in Windows XP. To avoid breaking code Microsoft made the decision to make the v6 CCs optional. Most applications would instead target the v5 CCs. Sounded great because it ensured that an application written under XP would run under Windows 2000 without change. Fast forward to today. .NET v4 only supports XP+ so any v4 .NET application can safely use the “new” v6 CCs where all the new Windows controls reside. But if you’re using ClickOnce then you are once again out of luck. The issue is that in order to get the v6 CCs to load properly you have to add them as a dependency in your application manifest (I’ll blog later about this hack). Adding a dependency to the manifest causes the publish process to fail because the publisher assumes you are relying on a binary that isn’t available to ClickOnce (even though it will be there for all versions of Windows).
So, in summary, if you want to use ClickOnce then you are stuck with a pre-XP user interface. Now you might think you can work around this limitation by building your app, publishing it and then editing the post-build manifest but guess what – it won’t work. See ClickOnce doesn’t want you tampering with any files once published so it checksums them. If any file is modified then ClickOnce fails. In order to modify a file you’d have to make the modification and then run a command line tool to regenerate the publish data. Needless to say switching from Visual Studio to the command line to work around a severe limitation in ClickOnce just doesn’t sit well with me.
Autoupdate Your Application – Sometimes
Finally we have autoupdate. Autoupdate sounds like a great idea – push a new version of your application to a website and users can be notified to download it. All this wonderful technology is wrapped in a simple static class you can use from your application, some conditions may apply. These conditions include the fact that the application must have been deployed via ClickOnce to begin with (i.e you can’t install via a CD and then autoupdate). You also cannot be running in the debugger. Do what??? Yes that is right the designers of ClickOnce figured that nobody would be debugging code. If you call the autoupdate code within the debugger you’ll get an exception. The logic of this design alludes me. I’m also confused as to how they could even test it but that is a different story. Nevertheless in order to use autoupdate you have to first verify your app isn’t running in the debugger and you were originally deployed using ClickOnce (they at least provide a method for that check).
I fail to see why either of these requirements is necessary for the proper implementation of updating. No problem, says a developer, .NET is extensible so I’ll just extend the infrastructure. Or not. Again, the designers of ClickOnce felt autoupdate was either too tricky or too special to allow any sort of extensions. The only extending you can do is to rewrite it yourself.
If you felt like I’ve been harsh on ClickOnce you’d be right. I think it is deserved. This isn’t some legacy technology that we’re talking about. It is one of the preferred deployment approaches that .NET recommends and yet it is completely outdated and inflexible. I believed the hype and samples that I saw on ClickOnce so much that I was going to use it in a recent project. Within the first few hours I realized I’d have to either hack my way around ClickOnce or give up on it entirely. So now I have to write my own publishing code and autoupdate code just because ClickOnce is outdated.
Here’s my feature request list for the ClickOnce team.
- ClickOnce has to be extensible. Publishing and updates are the primary areas.
- ClickOnce must support the newer OS features like UAC and v6 Common Controls (and others).
- ClickOnce needs to be fully integrated into Visual Studio without the need to run command line tools for something as common as changing a post-published file.
- Autoupdating needs to work whether I’ve deployed via ClickOnce or via an alternative manner. After all it really just needs to know where to go check for updates.
- ClickOnce has to work within the debugger. If I cannot run Visual Studio then the tool is useless. I shouldn’t have to code around technologies.
I’m hoping that one day ClickOnce will be brought up to snuff with the rest of the framework but for now I consider it no better than the old Visual Studio Setup Projects – good for novices but a complete waste of time for “real” applications.
You’re really only touching the surface.
I read about ClickOnce and its restrictions seemed fine in my project. (My application is a xcopy deployment, but the auto-update for free part was what I wanted.)
I have cursed that decision many, many times.
1. ClickOnce crashes for a whole lot of various reasons on many different machines. My application is freely available to everyone and I got tons of error reports… ClickOnce is NOT a stable and perfectly working technology. Apparently it can fail for many reasons on your customer machines. (Have to say I got fewer error reports now that I’m using .NET 4, but still.)
2. Upgrading your application binaries is easy, but managing your local data and settings is a mess. The API for that is a joke. I ended doing clever workarounds that I wished I’d never do.
3. When things go wrong (e.g. the application doesn’t update anymore) it’s a pain to debug. Moreover you never know the exact location of files, and the actual path names are incredibly weird. It always makes a great impression when talking to a customer.
4. By default ClickOnce keeps copies of all your previous versions of local data and binaries… If you release often or have big amount of data I strongly advise you to perform some cleaning behind ClickOnce…
Honestly I regret using ClickOnce. I will use another auto-updating technology in the future, that’s for sure.
“I would like a user to be able to enter a URL into a browser and my application automatically downloads and runs. … Unfortunately ClickOnce doesn’t support this approach.”
Really? I’ve published ClickOnce apps on a URL before, and it worked fine. If you’ve already got .NET installed, you can just enter the URL of the “.application” file, and it will download and run.
“If you have an application manifest with UAC settings in your application then ClickOnce won’t work.”
ClickOnce applications do not attempt to elevate to admin privileges at runtime because they can expose the client to security elevation attacks. This is by design.
“… in order to get the v6 CCs to load properly you have to add them as a dependency in your application manifest …”
What’s wrong with calling Application.EnableVisualStyles?
“Really? I’ve published ClickOnce apps on a URL before, and it worked fine. If you’ve already got .NET installed, you can just enter the URL of the “.application” file, and it will download and run.”
Yes but you have to use either HTTP or FTP. If you (or more correctly your clients) aren’t running a web server then CO is dead in the water for this approach. Even worse is that CO forces updates through this same approach. In a client-server architecture the server should be responsible for telling the client when an update is available. Alas CO doesn’t support this.
“ClickOnce applications do not attempt to elevate to admin privileges at runtime because they can expose the client to security elevation attacks. This is by design.”
Yes and a very poor design. CO is a deployment technology. Deployment != security. CO should put no restrictions on the security aspects of an application. I want to use CO to easily deploy my app but I don’t want the restrictions that it entails. There is absolutely no reason for it. You can argue that CO is designed for non-admin users but I disagree. CO is designed to allow you to deploy an app w/o a setup program. But nothing should prevent an app from elevating its privileges via UAC – especially the deployment tool.
“What’s wrong with calling Application.EnableVisualStyles?”
Firstly its a WinForms call so you have to include WinForms even if you’re using WPF. Very, very poor design. Secondly the point was that any dependencies listed in the manifest (of which CC is only one) will cause CO to fail.
Granted CO works for some applications but it is certainly not the best approach for applications that might benefit from its no-setup/auto update capabilities simply because of it is poor, outdated design.