Passing arguments to ClickOnce applications
My company, Red Stapler Software, has a tool we call the Transfer Utility that we use to deploy and update our web applications. Since our live server, our testing server, and each development machine uses this tool, an upgrade to the Transfer Utility results in a lot of work by a lot of people on a lot of machines.
To combat this, we decided to make the Transfer Utility a smart client deployed using ClickOnce. Now when we update the tool, we simply publish to our live server, and every machine that runs the the tool (including the live server it was published to) will automatically pickup the latest version. This is great, but there were a bunch of problems along the way.
First, there are two types of ClickOnce applications: Ones that can run offline and those that cannot. We chose the type that can be run offline so that developers can still work if their link to the live server is interrupted for whatever reason. For this type of ClickOnce application, there are two ways to run it. The first is from the Start menu shortcut (which is not a true shortcut in the sense that if you right-click on it, it does not bring up the normal options such as the path to the file it will be running) and the second is by visiting the URL to which the ClickOnce application was published.
It turns out that the Start menu shortcut method of invocation has a number of drawbacks. First, I was unable to find a way to make upgrades to new versions of the Transfer Utility completely transpartent. It always prompts the user. This is a problem when invoking the utility from the command line or from a scheduled Windows task.
The URL method of invoking the application can be made to upgrade and run transparently, with no prompting at all. To do this, simply create a desktop shorcut of the URL and add the domain to which your ClickOnce app is published to your Trusted Sites list. After doing this, running the desktop web shorcut (even from the command line) will run the program without asking you for permission and without prompting you for upgrades.
This is great until you actually try to run a real application that lives outside of Happy Exampleville, such as those with command line arguments. This brings us to our second problem with the Start menu method of invoking ClickOnce applications: I've been unable to find any way to pass command line arguments to them.
Once again, I've had more luck with the URL method of invocation. To pass command line arguments to your ClickOnce application, simply append "?commandLineArg1[&&commandLineArgN]" to your URL. This works nicely, except that inside your program's Main( string[] args ) method, you'll find your args array very empty. In order to extract command line arguments, you'll have to do the following:
string fullUrl = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[ 0 ];
This will give you the full URL of your application. You'll need to split the string by the question mark and parse the arguments that appear after it. Remember to HtmlDecode (in System.Web.HttpUtility) the string before you parse it. Oh, and you'll also have to check AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData for null before you do this, because if someone does try to invoke the program using the Start menu shortcut, there won't be any activation data and the line of code above will throw a null pointer.
We now have the ability to run our application in one click with no prompting even while passing command line arguments to it. The remaining problem is that we don't want to have to create one web shortcut for every combination of command line arguments we ever want to pass to our program. To accomplish this, I actually had to create my own batch file, which looks like this:
"C:\Program Files\Internet Explorer\IEXPLORE.EXE" http://files.redstapler.biz/transferutility/redstapler.transferutility.application?%1
I called my batch file executeTransferUtility.bat. Note that I'm only passing one argument. You can choose to add more (%2, etc.) or you can choose to mash them all into one with some delimiter (like '/') and parse them yourself. Now I can finally use my ClickOnce application like a normal program from the command line: 'executeTransferUtility auto' will invoke the Transfer Utility with one command line argument, "auto," which incidentally makes the utility perform its normal set of batch operations associated with the machine it is installed on without asking the user any more questions.
That seemed unnecessarily exhausting, but it solved my problem. Since I'm forcing the use of the URL method of invocation, I probably won't be able to run the application while disconnected. I also suspect that there exist (hopefully) easier ways to do what I've done, or that there is a way to make Start menu method of invocation accept command line arguments. Still, I've failed to find any good documentation to walk me through what I'm trying to do, and I suspect I've strayed too far from Microsoft's expected usage pattern for ClickOnce and I'm on my own. I look forward to reading about more solutions to the above problems.
3 Comments:
Have you found a better solution yet? I'm actually trying to do the same thing - I have a desktop app written in VS2005, and need to have the option to execute the app via the start menu, or automatically (through a Windows scheduled task) with a command line argument of "auto". I'd love to hear if you've found an easier way than what you already described, as I'm having no luck finding info on this type of functionality!
We ended up abandoning ClickOnce and creating our own program that downloads a zip file with the newest version of the program and then runs it. The fact that ClickOnce programs don't accept command line arguments when run outside of IE is "by design" and there were a slew of other problems we ran into with ClickOnce that we should never had to have dealt with.
We used the following method / function to obtain the command line argument from the query string:
http://msdn.microsoft.com/en-us/library/ms172242.aspx
It is a bit easier than parsing it yourself.
Post a Comment
<< Home