Proactive Logic
Home | About Us | Services | Products | Blog | Contact  | Search
 
 
   
 
 

Packaging a ClickOnce Server Deployment

Recently, I have helped one of our clients with ClickOnce deployment. Part of the system that our client sells consists of application servers that have a .Net web service, and a smart client application. We helped our client improve the architecture of the web service and the Smart Client application to support extensibility for customizations specific to their customers. These customizations are out of the scope of this post, but during this re-architecture, the technology base was upgraded from VS 2003 & .Net 1.1 to VS 2005 and .Net 2.0.

The extensibility, plug-in and pipelining portions of the project went over very well. We did however face an unforeseen complexity: ClickOnce Deployment. We had done our fair share of reading on the benefits of ClickOnce and had read some of the deeper technical articles, that all focused on ClickOnce deployment from the web server to the client. The benefits seemed great on paper, even though there are issues with Xbrowser support that quickly rear their head. Also, there seems to be a lack of documentation around actually getting the server portion of ClickOnce installed, and that is what this post focuses on.

ClickOnce deployment has two very important files: the application manifest that defines what files make up the application and the deployment manifest that has the deployment version information and the path (the ProviderURL) for the ClickOnce application to look for updates from. These manifests are signed and this leads to a very tough issue to get around: how can you have a setup package that contains a deployment URL that you do not know ahead of time?

Our client sells their web applications to many customers. These servers are all imaged with Windows Server 2003 and the .NET framework 2.0. Then a deployment team installs the web service and ClickOnce application on the server via an MSI setup package. In the field, servers are always added to server farms to increase capacity. The need for quick setup of machines via a setup package is required.

The nature of the client application that we built, includes dynamically loaded assemblies in order to support customizations of the core application. This scenario is not covered by the “right click -> deploy” ClickOnce deployment method in Visual Studio or MSBuild. When using MSBuild /deploy, the ClickOnce setup package only consists of statically linked assemblies.

What we did was prepare a nAnt script for the build team to use, which creates the proper setup program, including dynamically linked files and additional files needed for server setup. The setup program itself is created via a Web Setup project in Visual Studio.

The nAnt script that we created performed the following steps:

  • Get files from source safe and label
  • Update all assembly info files with version information (remember that the assembly version is not what is used by ClickOnce to determine if there is a new version to download, the deployment manifest is used for that purpose)
  • Build all of the assemblies that are statically and dynamically linked.
  • Create the application manifest using Mage.exe, linking all of the statically and dynamically linked assemblies
  • Create the deployment manifest and version it with Mage.exe – ensure that the deployment provider URL points to an invalid host name
  • Sign the Deployment and Application manifests with a certificate that is not issued by a certificate authority
  • Copy all of the files that are needed into a temporary build area with the Web Setup Project
  • Update the default web page with version information
  • Include a vbscript that is invoked during the install that will update the manifests (more on this later)
  • Invoke the Web Setup package via devenv (you need Visual Studio 2005 installed on the build machine)

After the NAnt script is run, there will be a setup.exe and MSI install package for your ClickOnce server deployment. In this package a dummy certificate is included and a vbscript for updating the deployment and application manifests.

In the Web Setup project we configured the vbscript to run during the server install. The vbscript prompts the user to input the URL that will be used for ClickOnce client updates. This URL is then used to update the deployment manifest with the new deployment URL. The prompt also tells the installer that they should point to the load balanced hostname or as opposed to the specific server IP or hostname. The vbscript invokes mage.exe to perform this step. Mage.exe is part of the .Net Framework 2.0 SDK and must also be deployed with the setup project.

mage.exe -Update myclickonceapp.application -ProviderUrl http://myserverhostname/myclickonceapp

The installer then prompts for a path to the certificate to sign with. Customers can use their own certificate to sign the application manifests with, or they can use the unsecured dummy certificate that is included in the setup package.

mage.exe -Sign myclickonceapp.application -CertFile somecertificate.pfx -Password somepassword

Next the installer vbscript must update the bootstrapper that is used to install the prerequisites. This step is needed because the bootstrapper itself will invoke the ClickOnce application after it installs the prerequisites. Note, that there are even issues around this if the client browser is not IE. There are some very good work arounds for ClickOnce Firefox issues discussed over on the Microsoft Channel 9 forums.

setup.exe /url= http://myserverhostname/

After this is complete, the vbscript is left on the server in case if the user wants to update the deployment URL after setup.

This build and installation has worked very well for us, but you do need to at least provide instructions on the setup web page for Firefox users on how to properly install the application, or follow some of the work arounds detailed on the Microsoft Channel 9 Forums.

I hope this helps
-Jon

31 Responses to “Packaging a ClickOnce Server Deployment”

  1. Robert Says:

    Hi,

    Very good post, I am struggling with the exact same setup.

    To be able to run mage.exe on the client machine to update the manifest, do I have to include the whole .Net FW 2.0 SDK (~350MB) as a prerequisite? Or is there some other way to accomplish this?

    Thanks!

  2. jon Says:

    Hi Robert,

    Thanks for your kind remarks.

    I added the mage.exe file to my install, not the entire .Net Framework SDK 2.0. I need to check with MS on the redistribution terms on the mage.exe utility. I don’t see a reason why they would not allow it to be put in a setup program since it is needed to update the manifests.

    Also, just to be clear, do you really mean running mage.exe on the client machine? I would think you would run it on the server.

    Thanks,
    Jon

  3. Robert Says:

    Hi,

    Thank you for your quick reply. Indeed, I meant to run
    mage.exe on the server.

    Hopefully I will get this resolved soon :)

    Thanks again!

  4. Anil Issac Says:

    I tried to update my clickonce url by executing following code and its not updaing. But same thing executing fine from command prompt (manually). Please tell me where I am wrong….Need Urent help!!!!
    ——————————————————
    Private Function ConfigureclickOnce() As Boolean
    Dim Prsc As Process
    Dim startInfo As ProcessStartInfo
    Dim StrFullPath, StrArgs As String
    Try

    StrFullPath = “C:\Program Files\Software Solutions Centre Ltd (SSC)\NaviCare\ClickOnce\mage.exe”
    StrArgs = New StringBuilder(500).Append(” -Update NaviCareCore.application -ProviderUrl “).Append(ClickOnce_IISPath).Append(”/NaviCareCore.application”).ToString()
    ‘MsgBox(StrArgs)
    startInfo = New ProcessStartInfo(StrFullPath)
    startInfo.WindowStyle = ProcessWindowStyle.Hidden
    startInfo.UseShellExecute = False
    startInfo.RedirectStandardOutput = True
    startInfo.RedirectStandardError = True
    startInfo.Arguments = StrArgs
    Prsc = New Process
    Prsc.StartInfo = startInfo
    Prsc.Start()
    Prsc.WaitForExit()
    Prsc.Close()

    While Not Prsc.HasExited

    End While
    ‘————————————————————————–
    StrArgs = New StringBuilder(500).Append(” -Sign NaviCareCore.application -CertFile NaviCare.pfx -Password sscess”).ToString()
    MsgBox(StrArgs)
    startInfo = New ProcessStartInfo(StrFullPath)
    startInfo.WindowStyle = ProcessWindowStyle.Hidden
    startInfo.UseShellExecute = False
    startInfo.RedirectStandardOutput = True
    startInfo.RedirectStandardError = True
    startInfo.Arguments = StrArgs
    Prsc = New Process
    Prsc.StartInfo = startInfo
    Prsc.Start()
    While Not Prsc.HasExited

    End While

    ‘’————————————————————————–

    StrArgs = New StringBuilder(500).Append(” /url=”).Append(ClickOnce_IISPath).Append(”\publish.htm”).ToString()
    ‘MsgBox(StrArgs)
    startInfo = New ProcessStartInfo(StrFullPath)
    startInfo.WindowStyle = ProcessWindowStyle.Hidden
    startInfo.UseShellExecute = False
    startInfo.RedirectStandardOutput = True
    startInfo.RedirectStandardError = True
    startInfo.Arguments = StrArgs
    Prsc = New Process
    Prsc.StartInfo = startInfo
    Prsc.Start()
    While Not Prsc.HasExited

    End While

    Return True

    Catch ex As Exception
    Throw ex
    End Try
    End Function

  5. Jon Says:

    What is your error?

    Also try setting your working directory to where your application manifest is located (NaviCareCore.application).

    Let us know,
    Jon

  6. Tracter Says:

    “Invoke the Web Setup package via devenv (you need Visual Studio 2005 installed on the build machine) ”
    Could you please tell me how can I invoke the Web Setup package in NAnt script? I what to write a build script to build my web setup project which is created in VS2003.

    Thanks,
    Tracter

  7. Jon Says:

    First, make sure you can build your web setup package from the command line.

    Doing that will look something like this:

    C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE>devenv /build release “C:\WebSetup1\WebSetup1.sln”

    Once you get it to work, you can include the command to run devenv from the command line to your NAnt script like so:

    Of course, I would recommend parameterizing your actual script.

    Hope that helps,
    Jon

  8. Roxana Says:

    Hello,
    Very good post! I used it to solve the same problem, but now I am still testing the mage commands to see if the republishing on another web server works with my scripts.
    I published the application on the dev machine, then I used mage tool, as you adviced, to change the install url:

    mage -Update App.application -ProviderUrl http://server/location/App.application

    I created the pfx key (installed locally on the dev machine) and used it to resign the manifest:

    mage -Sign App.application -CertFile MyKey.pfx -Password MyPass

    Then I executed:

    setup.exe /url= http://server/location
    All the package was then moved to the location above and when I clicked on my installation link to execute the App.application manifest, I get this error:

    ERROR DETAILS
    Following errors were detected during this operation.
    * [12/15/2006 11:10:08 AM] System.Deployment.Application.InvalidDeploymentException (ManifestParse)
    - Exception reading manifest from http://server/location/App.application: the manifest may not be valid or the file could not be opened.
    - Source: System.Deployment
    - Stack trace:
    at System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri)
    at System.Deployment.Application.DownloadManager.DownloadDeploymentManifestDirectBypass(SubscriptionStore subStore, Uri& sourceUri, TempFile& tempFile, SubscriptionState& subState, IDownloadNotification notification, DownloadOptions options, ServerInformation& serverInformation)
    at System.Deployment.Application.DownloadManager.DownloadDeploymentManifestBypass(SubscriptionStore subStore, Uri& sourceUri, TempFile& tempFile, SubscriptionState& subState, IDownloadNotification notification, DownloadOptions options)
    at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut)
    at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
    — Inner Exception —
    System.Deployment.Application.InvalidDeploymentException (SignatureValidation)
    - Manifest XML signature is not valid.
    - Source: System.Deployment
    - Stack trace:
    at System.Deployment.Application.Manifest.AssemblyManifest.ValidateSignature(Stream s)
    at System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri)
    — Inner Exception —
    System.Security.Cryptography.CryptographicException
    - No signature was present in the subject.

    - Source: System.Deployment
    - Stack trace:
    at System.Deployment.Internal.CodeSigning.SignedCmiManifest.Verify(CmiManifestVerifyFlags verifyFlags)
    at System.Deployment.Application.Manifest.AssemblyManifest.ValidateSignature(Stream s)

  9. Roxana Says:

    Hi,
    I managed to do all this work, but my problem is that

    setup.exe /url= http://myserverhostname/

    prompts a confirmation message inside the installer. Did you find any way to automatically respond with yes?

  10. Aaron Says:

    Great information! This has always been one of the biggest weak points with ClickOnce deployments for the kind of work that I do.

    Great article, you made my day :)

  11. Suren Says:

    Hi,
    After I publish the application, I want to specift the update path. While publishing the application I dont know the update path. When I am at client side I would know the update path. At that time I have only the Setup.exe and 2 XML (Deployment and Application manefest) files. How can I do this. So when the next time if I run my application then it should check in the update path for a new version.Can u please help me regarding this issue??

  12. Jon Says:

    Suren,

    I’m not sure what you mean by “When I am at client side I would know the update path. ” What is your definition of client? You confused me when you said you would have “Setup.exe and 2 XML” on the client side. Are you talking about a web distro or by CD rom, etc….

    How is the application getting delivered to the client machine to begin with?

    Please explain your exact usage scenario.

    Jon

  13. Suren Says:

    I am installing using a CD ROM. Forget abt the client. I mean to say that when I am physically existing at client location. I have the installation CD with me. All the required files are there in the CD. So now how can i change the updates path?

  14. Jon Says:

    Suren,

    Have you looked at using Mage.exe that is included in the .net 2.0 SDK? I have not done a CD based install, but I assume you still need to use Mage to update the deployment manifest for the update url.

    Thanks,
    Jon

  15. Jhoan Says:

    Hi guys,

    Im new in clickonce and VS 2005, i read the articles above and its very informative. But can anyone tell me more about how security for clickonce application works? And what if the user does not have enough rights to install the application is there a code to bypass it? or a workaround to do this?

    Thanks!!!

  16. Eti Says:

    I’ve been able to use this to get it working:
    String sPath = ;
    DeployManifest dManifest = (DeployManifest)ManifestReader.ReadManifest(”DeployManifest”, sPath , false);
    string sNewUrl = @”http://”;
    sNewUrl += Environment.MachineName + “/” + virtualDirectory;
    sNewUrl += “/iToolBox/iToolbox.application”;
    dManifest.DeploymentUrl = sNewUrl;
    X509Certificate2 cert;
    cert = new X509Certificate2(”x:\myKey.pfx”));
    ManifestWriter.WriteManifest(dManifest);
    SecurityUtilities.SignFile(cert, null, sPath);

    I noticed that like Anil, using the mage process seemed to run successfully but the manifest was unchanged, but my using Microsoft.Build.Tasks.Deployment it worked.

  17. Jon Says:

    Eti, thanks for the post!

    Seems this post is becoming a place to exchange our ClickOnce woes.

    Cheers to the contributers!
    Jon

  18. Jimmy Says:

    Did someone say ClickOnce woes? I have been going crazy trying to solve the problem Mike Caito points out in this brief post:

    http://geekswithblogs.net/thibbard/archive/2006/02/22/70375.aspx

    We are trying to run a web distro with a CD rom option to install. Generally our users install from CD and recieve updates from our website. However, the first update after the CD install doesnt copy data files into the new version’s DataDirectory. Any data previously entered is lost. Argh.

    Note: Our DB is created and updated dynamically by running sql scripts. It is not published with the app, which is a common cause of the ‘data being lost after update’ problem.

    Has anyone got around this one before?

  19. Jon Says:

    Hi Jimmy,

    I actually never did a CD install. Does this happen after every version update or just the first update from the web?

    Cheers,
    Jon

  20. Sabir Says:

    Hi,

    I am new to use OneClick deployment. I have developed a test project and published it using .net 2005 publishing wizard. It create a virtual directory named testOneClick. I can successfully use this functionality as far as I used the website where i published it.

    But if I copy the contents of the published virtual directory to server and create a virtual directory with same namd and contents as on my system it does not work. infact I can browse the application deployed on server “http://Server001/OneClick/publish.htm” but when I click on install button it prompts the error and in details following details are shown:
    ERROR DETAILS
    Following errors were detected during this operation.
    * [6/25/2007 1:27:25 PM] System.Deployment.Application.InvalidDeploymentException (ManifestParse)
    - Exception reading manifest from http://localhost/OneClick/OneClick.application: the manifest may not be valid or the file could not be opened.

    I have also changed the machine(system) name from localhost to server001 in all of these files “OneClick.application”, “OneClick_1_0_0_0.application”, “OneClick.exe.deploy”

    I want to do this using .net 2005 publishing wizard not MageUI.

    Sabir
    gsabirmalik@hotmail.com

  21. Jon Says:

    Hi Sabir,

    If you modify the manifests manually, you will have to resign them using mage.

    HTH,
    Jon

  22. gyurisc Says:

    Very good article, Thanks. This is similar how my publishing process works, although I am using msbuild instead of NAnt. How do you write the version numbers into files? Is there a task for this in NAnt?

  23. Jon Says:

    gyurisc - For the manifest files I just use the generic execute NAnt task to invoke mage.exe and use mage to update the manifest versions.

  24. John Rusk Says:

    What are the downsides to the customer if they use the dummy certificate?

  25. John Rusk Says:

    I found a good answer, for .net 3.5 at least, here: http://msdn2.microsoft.com/en-us/library/bb384248.aspx It works better than the options available in .net 2.0 and 3.0

  26. Jon Says:

    Hi John,

    Thanks for posting the link, it seems to be a really helpful writeup of the trade-offs. This certainly did not exist when I took the steps that I took in my post. People who find my post I’m sure will be grateful for the link.

    Cheers,
    Jon

  27. Kumar Says:

    I am also looking for the same feature Roxana needs

    setup.exe /url= http://myserverhostname/

    prompts a confirmation message inside the installer. Is there any way to automatically respond with yes?

  28. Jeff Says:

    Kumar, I’m Also looking for a solution for the same problem you and Roxana have run into regarding the following command.

    setup.exe /url= http://myserverhostname/

    I haven’t found a solution however I have found the following post on the Microsoft feedback site (see my comment at the bottom of the page).

    https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=390992&wa=wsignin1.0

    I’ve also found the other following resources on the issue.

    http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/633a284c-6485-4266-a6c5-01055e43dcf4

    http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/65cf51bd-b9a6-4a7a-b8f0-d0a837055703

    http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/c3c5063c-9f5a-4754-81f7-990d82f5855c

    http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/6a2a299d-932b-4a1e-87e3-fe535a883fae

  29. Jon Says:

    Hey all,

    I wrote these scripts a long time ago for an old client of mine, so I don’t have the source anymore. I believe message boxes were ok in our setup because the person installing it would need to choose the correct deployment URL in popup no matter what (so answering other popups might have been ok). However, I would think there has to be a way for a vbscript or a powershell script even to somehow answer/suppress popups.

    Please share your experiences, as thousands of people have come to this page for click once install help (so your experiences are helping people).

    Cheers,
    Jon

  30. Jeff Says:

    So far there doesn’t seem to be any way to suppress the prompt. What I have found is that if you answer Yes to the prompt that after subsequent attempts to change the URL you will no longer get the prompt. This still isn’t acceptable for automated build scripts though.

    Supposedly this was supposed to be fixed in Visual Studio 2008 but I can still reproduce it and it seems that others are having the same issue still as well. In order to get some official response I’ve posted a new bug report on the Microsoft Feedback Center for Visual Studio. Please follow the link below and vote, comment, or just track the progress of this issue if you are interested in seeing this fixed.

    I created a new bug report on the Microsoft Feedback Center site to help try to get the -url= parameter to work in a silent manner. If anybody is interested in voting in order to get this issue addressed or to just follow the progress please follow the link below.

    The bootstrapper (setup.exe) created along with a ClickOnce application in Visual Studio 2008 is supposed to update without prompting
    https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=426896

  31. Jeff Says:

    Unfortunately it doesn’t appear that the problems with the bootstrapper that I mentioned above have been addressed yet in Visual Studio 2010 Beta 2.

    https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=519149

Leave a Reply

For spam detection purposes, please copy the number 9777 to the field below:


 
 
Home | About Us | Services | Products | Blog | Contact  | Search
Copyright 2005-2006 Proactive Logic LLC. All rights reserved.