I use ClickOnce to publish all my applications I write internally, some of which are VSTO Outlook add-ins. The issue with the inbuilt ClickOnce updates is you have no control over it and it can slow start up time of your app.

So I wanted a generic class that I could put in my common library and use in any of my applications, VSTO or normal. This is what I came up with:

image

This is the public interface, under the covers most of the functionality is declared as protected virtual so functionality can be changed (which I use to create my VSTODeploy class).

Usage:

var deployment = new Deploy();
deployment.CheckForUpdateAsync(result =>     {      if (result.Updated)      {      MessageBox.Show(result.Message, "Application Updated",
                        MessageBoxButton.OK,
                        MessageBoxImage.Information);      }     });

The base class is pretty simple and is just a nice wrapper for the ApplicationDeployment class. Where it gets tricky is updating VSTO applications, as the ApplicationDeployment.Update() method can corrupt your VSTO applications installation :( Also because VSTO and .Net use a different security model, you will get exceptions as soon as you try to access the ApplicationDeployment information.

Kristopher Makey has a good solution to this problem and I used his solution and created my VSTODeploy class, which hides all the nasty implementation details, you can view his solution here: http://blogs.msdn.com/krimakey/archive/2008/04/18/click-once-forced-updates-in-vsto-ii-a-fuller-solution.aspx

There are two main points that he covers, fixing the Trust and make sure you use VSTOInstaller.exe to install your update otherwise you can break everything.

Here is my VSTODeploy class, I welcome feedback, I also have included an Extensions.cs class in the zip file below which you will need to compile this code.

The main extension method to note is StartProcess, it wraps Process.Start nicely making it easy to capture output from the exe as well as the return code.

public class VSTODeploy: Deploy
{
    protected override UpdateResult UpdateApplication(ApplicationDeployment currentDeployment)
    {
        FixTrust(currentDeployment);
        return base.UpdateApplication(currentDeployment);
    }

    protected override bool UpdateCurrentDeployment(ApplicationDeployment deployment, ref string message)
    {
        //Call VSTOInstaller Explicitely in "Silent Mode"
        var installerArgs = string.Format(" /S /I {0}", deployment.UpdateLocation.AbsoluteUri);
        var installerPath = Directory.Exists(@"C:\Program Files (x86)")
                                ?
                                    @"C:\Program Files (x86)\Common Files\microsoft shared\VSTO\9.0\VSTOInstaller.exe"
                                :
                                    @"C:\Program Files\Common Files\microsoft shared\VSTO\9.0\VSTOInstaller.exe";

        var vstoInstallerOutput = new StringBuilder();

        var vstoStartInfo = new ProcessStartInfo(installerPath, installerArgs);
        var returnCode = vstoStartInfo.StartProcess((sender, e) => vstoInstallerOutput.Append(e.Data));

        message = vstoInstallerOutput.ToString();
        return returnCode == 0;
    }

    private static void FixTrust(ApplicationDeployment currentDeployment)
    {
        //Create the appropriate Trust settings so the Application can do
        //Click-Once Related updating
        var deploymentFullName = currentDeployment.UpdatedApplicationFullName;
        var appID = new ApplicationIdentity(deploymentFullName);
        var everything = new PermissionSet(PermissionState.Unrestricted);

        var trust = new ApplicationTrust(appID)
                        {
                            DefaultGrantSet = new PolicyStatement(everything),
                            IsApplicationTrustedToRun = true,
                            Persist = true
                        };

        ApplicationSecurityManager.UserApplicationTrusts.Add(trust);
    }
}