Saturday, April 01, 2006
The ClickOnce support in Visual Studio 2005 is nice and easy but falls-down in number of areas:

  1. The application manifest (i.e. the "stuff" that comprises your app) is determined by walking the project references of your Windows app.  What this means is that if you have deployment artifacts that are non-reference content or late-bound loaded assemblies then the default ClickOnce mechanism in Visual Studio will not pick them up.
  2. Oftentimes the versioning scheme for your assemblies is driven by your build process and ideally you'd want the ClickOnce version number to be in-sync with your assembly version.  The Visual Studio ClickOnce mechanism has a very limited versioning scheme that is completely decoupled from assembly versioning and is inaccessible outside of the IDE.
  3. For enterpirse scenarios, it is very common to have a segmented network dedicated for specific functions (e.g. development, test, production).  In this scenario the Windows app has to be designed such that certain information (e.g. connection strings, web service urls, etc.) are pushed-into environment-specific configuration files.  The deploy process then involves indicating what environment the built bits should be pushed into and then the appropriate configuration files are pulled-in by the deploy process.  In this way the same set of bits may be "promoted" from dev to test and finally to production.  The default Visual Studio ClickOnce mechanism has no notion of nor capability of dealing with environment-specific information.

For the uninitiated there are four ways to create a ClickOnce deploy package:
 
  1. Via the Window app's Publish property page in Visual Studio (easiest but essentially unuseable for apps of even moderate complexity for the reasons listed above).
  2. Via mage.exe (command-line utility).
  3. Via mageui.exe (Windows app).
  4. Via MSBuild (using the GenerateApplicationManifest, GenerateDeploymentManifest, GenerateBootstrapper and SignFile tasks).
 
Note that despite the chosen method, everything eventually calls the MSBuild tasks. So, for the cleanest solution you should just cut straight to the chase and call the MSBuild tasks, right? Ah, but here's the rub -- you have to determine what your application manifest is and feed this list to the GenerateApplicationManifest task via an ItemGroup. You really don't want to have this fixed list that you have to maintain but rather have the application manifest dynamically generated for you. This is the real value of mage.exe which you can point to a directory and it will build-up the app manifest for you. Where mage is less than useful is generating the deployment manifest but you can just use the MSBuild task to do this instead.
    
This sample demonstrates how to use mage.exe in conjunction with the ClickOnce MSBuild tasks to resolve the deficiencies with the Visual Studio approach.  The sample consists of a simple Windows app which displays a value stored externally in the application's App.config file.  Note that in this sample there are three versions of this file (stored under the Config directory) -- a "development" version, a "qa" (i.e. test) version, and a "production" version.  They are structurally identical, the only varying bits are the values.  There is also a satellite class library that is late-bound instantiated and invoked when a button is pressed on the app.  There is no reference to this assembly from the Windows app.

In my shop we run the deploy scripts seperately from the build scripts but you could easily tack this on to the end of your build process if so desired.  Have fun!
4/2/2006 6:06:11 PM (Pacific Standard Time, UTC-08:00)
Hi Mike. Thank you so much for your sample! You're solving a real problem I'm having since a couple of months ago. I just want to mention that I got an strange message when I ran this: "Deploy.cmd Dev":

C:\Development\ClickOnceDeployTest\Deploy.proj(101,5): error MSB4062: The "Microsoft.Sdc.Tasks.Xml.ModifyFile" task could not be loaded from the assembly C:\Development\ClickOnceDeployTest\Microsoft.Sdc.Tasks.dll. Could not load file or assembly 'Microsoft.Sdc.Configuration, Version=1.2.5000.0, Culture=neutral, PublicKeyToken=e24a7ed7109b7e39' or one of its dependencies. Strong name validation failed. (Exception from HRESULT: 0x8013141A) Confirm that the UsingTask declaration is correct, and that the assembly and all its dependencies are available.

It seems like I had to sign the assembly Microsoft.Sdc.Configuration.dll, so I had to run this line prior to running the cmd:

sn –Vr Microsoft.Sdc.Configuration.dll

I also had to use the .NET Framework SDK Command Prompt, because the Windows XP Command Prompt didn't find the mage.exe file.

Thanks again for the sample!
4/2/2006 8:49:58 PM (Pacific Standard Time, UTC-08:00)
Thanks for the feedback Julio! I updated the README.txt in the sample to make these steps more explicit.
4/4/2006 5:32:50 PM (Pacific Standard Time, UTC-08:00)
What I did to make it work was download this Sdc Tasks Standalone from the Microsoft Services (UK) Enterprise Solutions Build Framework (SBF) workspace
http://www.gotdotnet.com/codegallery/codegallery.aspx?id=b4d6499f-0020-4771-a305-c156498db75e

Btw, great job Mike
Matias

8/7/2006 8:34:40 PM (Pacific Standard Time, UTC-08:00)
Hi Mike,

Thanks for this wonderful post. I'd like to use something like this for our build process, however, I am completely new to this area. Where can I find more details on the elements used in the Deploy.proj file and what are some other options available. For instance, how can I change this to use a certificate from a certificate store rather than a file. Also, What role does the "PublishDir" property play and so forth. Thanks in advance.
Clark
8/28/2006 6:53:47 AM (Pacific Standard Time, UTC-08:00)
Hi Mike,

I wanted to thank you as well for this excellent, excellent post! This was exactly the sort of thing I was looking for and your sample has described what we want to do, perfectly! Thanks again!
9/2/2006 8:04:55 AM (Pacific Standard Time, UTC-08:00)
Would you mind send me your email? I used your example to perform our builds for clickonce and I'm having a problem with

+ Manifest XML signature is not valid.

+ No signature was present in the subject.

Obviously something around signing, but I'm not sure what's up.

I just wanted to shoot you what I shot Microsoft support. Maybe you've seen the issue and have an idea.

I would appreciate it.

Thanks,
Murray Gordon

10/10/2006 12:04:50 PM (Pacific Standard Time, UTC-08:00)
This is really very useful information. Thank you so much.
JT
10/31/2006 1:33:02 PM (Pacific Standard Time, UTC-08:00)
This is the only thing I found to make clickonce even remotely usable in a company environment. Maybe they have never heard of a QA and Development setup. Anyway, after looking at a lot of the other help out there I can not figure out how to (using your system) to setup files which are supposed to be installed in the \data directory.
12/9/2006 1:00:31 PM (Pacific Standard Time, UTC-08:00)
Hi mike,

I'm blocked using your code sample regarding ClickOnce deployment, integratimg it in TFS Build. Is there anyway you can give me feed back on my issues?

Regards,

R

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1003510&SiteID=1&mode=1
12/10/2006 10:48:26 AM (Pacific Standard Time, UTC-08:00)
You may have multiple manifests getting created -- check to make sure that the *.csproj or *.vbproj file of your WinForms project has the GenerateManifests property set to false.
1/14/2007 9:19:07 AM (Pacific Standard Time, UTC-08:00)
Hi Mike,

Excellent sample and works great. The only question I have is around signing and how you got your file to be created. Whenever I use makecert to create a certificate for ClickOnce, it fails on the signing part saying it doesn't have a private key. Just wondering how you created the certificate for your sample? Any help would be appreciated.
1/26/2007 3:29:26 AM (Pacific Standard Time, UTC-08:00)
There is another small problem: the DeleteVirtualRootFiles target has an error in the Exec task: it doesn't include quotes around the filename. This means working under a path with spaces in its name won't deploy.

Change the command to:
<Exec Command="del /f /s /q &"$(MSBuildProjectDirectory)\$(ClickOnceVirtualRootDir)\*.*""/>

It works fine then.
10/3/2007 5:13:47 AM (Pacific Standard Time, UTC-08:00)
Wow, this sample looks promising. But HOLY CRAP DUDE! I built it in a folder on my desktop:
C:\Documents and Settings\Blah\Desktop\My Folder

Without really thinking about it, I clicked the cmd file to kick off MSBuild. As it turns out, THE PATH IS NOT ESCAPED WITH QUOTES! Oops, since I have a folder called "C:\Documents", that contains lots of important documents, THIS MSBUILD SCRIPT SILENTLY DELETED EVERYTHING IN THAT FOLDER! Oops, there went two years worth of company email and my entire OneNote notebook.

Definitely not blaming you, it's my own stupid fault for blindly running an MSBuild script without checking the path syntax first. But be warned if you download this, HOLY CRAP! BTW, using 3rd party recovery tools didn't help me much, the email file was so large, it was already overwritten past the point of recovery.

Oh well, I guess sometimes you have to start work life over with a clean slate (no data or record of previous work done for company). :)

Cheers
Sam
10/3/2007 8:33:36 AM (Pacific Standard Time, UTC-08:00)
I'm so sorry Sam that your files got smoked. I never tested the sample under my Documents and Settings folder as I always work out of a seperate top level directory for code projects. For whatever it's worth I've updated the sample and have escaped the path so this won't happen again...
10/4/2007 8:58:35 AM (Pacific Standard Time, UTC-08:00)
Hey, no problem! I really appreciate the sample code, it's probably the best I've found on the web for this particular topic. BTW, I was able to recover all of my OneNote stuff thanks to some handy backups that the program makes. I basically just broke rule #1 when working with script-like languages, which is to look at it first to make sure it won't do something unexpected in my environment. Again, thanks for the awesome code, it's actually helped me quite a bit!

Cheers
Sam
10/10/2007 7:49:22 AM (Pacific Standard Time, UTC-08:00)
May I say, excellent sample - we have used it as a starting point for our project for nearly a year now without any difficulty.

Now we do have one question: how can we specify files in the build script to be deployed to the Application.UserAppDataPath?

Thanks,

Steven Wood
12/3/2007 5:24:45 AM (Pacific Standard Time, UTC-08:00)
Hello Mike!
Thank you for a very good sample code, I have been using your code to deploy the clickonce app for several environments since 2006 now. But after I have upgraded the project to 2008 I get the error message "Reference in the manifest does not match the identity of the downloaded assembly Myapp.exe." I share the same build files for a 2005 branch, and that is still working.

Do you have any ideas experiences about this? Is your files working with VS 2008? (We still target the 2.0 framework)
Milzit
12/4/2007 12:33:21 AM (Pacific Standard Time, UTC-08:00)
Milzit,

We're just now getting ready to move to 2008 and I haven't tried running my scheme under 2008 as of yet. It doesn't surprise, however, that some things broke. I'll probalby get it figured out though around the January time frame next year -- I doubt I'll have time to look into it much beforehand. If anyone else can shed some light on this that would be great!
12/4/2007 4:20:43 AM (Pacific Standard Time, UTC-08:00)
very nice
12/5/2007 6:22:58 PM (Pacific Standard Time, UTC-08:00)
Sorry! I do not quite understand it, you can say some more detail?
12/6/2007 5:58:47 AM (Pacific Standard Time, UTC-08:00)
Mike,
Under the conversion to VS 2008 under the application tab of the exe-project the manifest setting was changed to "Embed manifest with default settings", I changed back to "Create application without a manifest" and this is now working with 2008!! (Thanks to dfirka on the MSDN Forum for the solution)

Thanks again for create sample code Mike.
Milzit
1/10/2008 7:29:17 PM (Pacific Standard Time, UTC-08:00)
thank you
2/2/2008 6:37:02 AM (Pacific Standard Time, UTC-08:00)
Cool, the post.

Thanks for the information.
2/11/2008 9:25:54 AM (Pacific Standard Time, UTC-08:00)
Milzit, thank you
serge
2/26/2008 12:44:09 PM (Pacific Standard Time, UTC-08:00)
Thanks for showing us how to create a ClickOnce deploy package.
4/20/2008 11:43:58 PM (Pacific Standard Time, UTC-08:00)
I just had to modify the line 165 of the Deploy.proj. It now looks like this :

del /f /s /q "$(MSBuildProjectDirectory)\$(ClickOnceVirtualRootDir)\*.*"

There was a little problem with the quotes here.
Merlimoo
5/7/2008 4:35:12 AM (Pacific Standard Time, UTC-08:00)
Don't you just love having your post still running strong ?

Wonderful work you have done here! I have searched so loooong to find a solution and finally found
your post. Great work and thank you very very very much!

This has enabled us to cut out about 2 hours of time wasting a week.

Also did the same change as Merlimoo, but other than that everything ran 100%

Thanks again!
5/20/2008 3:32:58 PM (Pacific Standard Time, UTC-08:00)
I still get the error - "Reference in the manifest does not match the identity of the downloaded assembly Myapp.exe" , when I install my application. I am using vs2008, I dont see the "Embed manifest with default settings" option under the application tab and I tweaked the app.proj file and updated it as - GenerateManifests = false. But still I get the same error.
5/23/2008 4:02:18 PM (Pacific Standard Time, UTC-08:00)
I resolved this issue myself. This is what I did.
Issue -
Reference in the manifest does not match the identity of the downloaded assembly Myapp.exe - when i used the Deploy.Proj file crteated by this technique.
Solution-
MY Project had some dependencies of Cystal reports 11.0 dlls which I figured out and was able to add only from the PUBLISH tab of the IDE - "Application Files" . I published the dependecies without the .deploy extn to the default publish folder from the IDE. and then copied the extra crystal report files to the new folder called support and modified this Deploy.Proj to copy the crystal report files from thsi support folder to the "PUBLISH" folder as required by this Deploy.Proj. Viola -- It started working.
Lesson Learned - if project dependencies are not copied properly before creating the manisft, then you might end up with such issues.
***********************************
5/24/2008 7:36:49 AM (Pacific Standard Time, UTC-08:00)
get cheapest butalbital
5/24/2008 7:38:16 AM (Pacific Standard Time, UTC-08:00)
Discount US wellbutrin
5/24/2008 7:39:42 AM (Pacific Standard Time, UTC-08:00)
Cheapest Elavil Order Online
5/24/2008 7:41:09 AM (Pacific Standard Time, UTC-08:00)
buy online diflucan
7/22/2008 4:24:51 AM (Pacific Standard Time, UTC-08:00)
Great thanks
7/24/2008 10:01:42 PM (Pacific Standard Time, UTC-08:00)
I had the same problem as Murray gordan until I turned off Click-once security
9/8/2008 5:54:22 AM (Pacific Standard Time, UTC-08:00)
Mister, how can I change app.config after Publish ??

Thanks in advance.
10/16/2008 4:02:32 AM (Pacific Standard Time, UTC-08:00)
Thanks in advance.Thanks in advance.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):