简体   繁体   中英

Automatically update Visual Studio Extension

I'm trying to make my extension automatically update itself when new versions are pushed to the Visual Studio Gallery. There are a few guides on how one may achieve this, but they are a couple years old and may not apply.

For starters, I'm trying to query the IVsExtensionRepository as follows:

var _extensionRepository = (IVsExtensionRepository)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsExtensionRepository));

var query = _extensionRepository.CreateQuery<VSGalleryEntry>(false, true)
                .OrderByDescending(n => n.Ranking)
                .Skip(0)
                .Take(25) as IVsExtensionRepositoryQuery<VSGalleryEntry>;

query.ExecuteCompleted += Query_ExecuteCompleted;
query.ExecuteAsync();

At Query_ExecuteCompleted I'm receiving an exception from the server: "The remote server returned an error: (400) Bad Request."

A stack trace is provided:

Server stack trace: at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result) at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result) at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeEndService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

The service is hosted at: https://visualstudiogallery.msdn.microsoft.com/services/dev12/extension.svc

Does anyone know how I can create a Visual Studio extension that automatically updates itself from the Visual Studio Gallery? Either through the IVsExtensionRepository or manually?

Edit: Now in Visual Studio 2015 extensions are downloaded automatically.

So I've completely abandoned querying the IVsExtensionRepository . I'm not sure why, but there must be some internal problem with the queries it constructs. I queried the same service using ErikEJ's suggested project, and it worked fine.

However, I didn't want to construct the service from the WSDL as it appears SQLCeToolbox has done. Instead I used the IVsExtensionRepository , but avoided the CreateQuery() method.

Attached is my approach to updating my VSPackage. You'll need to replace any GUIDs or Package specific names with your package's information.

NOTE There is one Gotcha' in the following code:

Note that CodeConnectRepositoryEntry only implements DownloadUrl . When updating the VSPackage, this is all one must worry about as it allows us to download the new package. This URL can be found on the VSGallery page for your VSPackage.

However : You must trim the URL as follows:

http://visualstudiogallery.msdn.microsoft.com/c0c2ad47-957c-4e07-89fc-20996595b6dd/file/140793/4/CodeConnectAlpha.vsix

to:

http://visualstudiogallery.msdn.microsoft.com/c0c2ad47-957c-4e07-89fc-20996595b6dd/file/140793/

Above, the /4/ represents the fourth upload. By removing it completely, the Visual Studio Gallery will download the latest version.

internal class CodeConnectUpdater
{
    IVsExtensionManager _extensionManager;

    IVsExtensionRepository _extensionRepository;

    //We need only supply the download URL.
    //This can be retrieved from the "Download" button on your extension's page.
    private class CodeConnectRepositoryEntry : IRepositoryEntry
    {
        public string DownloadUpdateUrl
        {
            get; set;
        }

        public string DownloadUrl
        {
            get
            {
                //NOTE: YOU MUST TRIM THE DOWNLOAD URL
                //TO NOT CONTAIN A VERSION. THIS FORCES 
                //THE GALLERY TO DOWNLOAD THE LATEST VERSION
                return "http://visualstudiogallery.msdn.microsoft.com/c0c2ad47-957c-4e07-89fc-20996595b6dd/file/140793/";
            }
            set
            {
                throw new NotImplementedException("Don't overwrite this.");
            }
        }

        public string VsixReferences
        {
            get; set;
        }
    }

    //I have been calling this from the VSPackage's Initilize, passing in the component model
    public bool CheckForUpdates(IComponentModel componentModel)
    {
        _extensionRepository = (IVsExtensionRepository)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsExtensionRepository));
        _extensionManager = (IVsExtensionManager)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsExtensionManager));
        //Find the extension you're after.
        var extension = _extensionManager.GetInstalledExtensions().Where(n => n.Header.Name == "Code Connect Alpha").SingleOrDefault();

        return CheckAndInstallNewVersion(extension);
    }

    private bool CheckAndInstallNewVersion(IInstalledExtension myExtension)
    {
        var needsRestart = false;
        var entry = new CodeConnectRepositoryEntry();
        var newVersion = FetchIfUpdated(myExtension, entry);
        if (newVersion != null)
        {
            Install(myExtension, newVersion);
            needsRestart = true;
        }

        return needsRestart;
    }

    //Checks the version of the extension on the VS Gallery and downloads it if necessary.
    private IInstallableExtension FetchIfUpdated(IInstalledExtension extension, CodeConnectRepositoryEntry entry)
    {
        var version = extension.Header.Version;
        var strNewVersion = _extensionRepository.GetCurrentExtensionVersions("ExtensionManagerQuery", new List<string>() { "6767f237-b6e4-4d95-9982-c9e898f72502" }, 1033).Single();
        var newVersion = Version.Parse(strNewVersion);

        if (newVersion > version)
        {
            var newestVersion = _extensionRepository.Download(entry);
            return newestVersion;
        }

        return null;
    }

    private RestartReason Install(IInstalledExtension currentExtension, IInstallableExtension updatedExtension)
    {
        //Uninstall old extension
        _extensionManager.Disable(currentExtension);
        _extensionManager.Uninstall(currentExtension);

        //Install new version
        var restartReason = _extensionManager.Install(updatedExtension, false);

        //Enable the newly installed version of the extension
        var newlyInstalledVersion = _extensionManager.GetInstalledExtension(updatedExtension.Header.Identifier);
        if (newlyInstalledVersion != null)
        {
            _extensionManager.Enable(newlyInstalledVersion);
        }

        return restartReason;
    }
}

I have some code to access the service and produce a RSS feed from it here: sqlcetoolbox.codeplex.com/SourceControl/latest - In the NuGetDownloadfedd.zip file (has nothing to do with Nuget!) - Also includes the version number:

 foundItem.Project.Metadata.TryGetValue("VsixVersion", out version);

In fact I am already hosting a RSS feed service, let me know if you would like to use it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM