Hosting a Private Visual Studio Gallery
Visual Studio extensions are really popular these days. Not surprisingly Visual Studio has a very active extensions gallery. But unfortunately the gallery is public so if you develop some extensions for your personal use, or for your company, then you cannot use the public gallery. Fortunately though VS supports the concept of a private gallery. A private gallery is nothing more than an extension gallery that is not accessible to the world. It is discussed on MSDN so refer to there for more information about the what’s and why’s. Unfortunately the documentation is a little vague and setting one up is not trivial. I’m going to discuss the steps needed to get a private gallery up and running.
First a word of warning. VS supports extensions and the public extension gallery. VS also supports having multiple galleries configured (and usable) at once. Actual support for a private gallery is “Beta” at best. Therefore don’t expect a lot of support from Microsoft in setting up and running a private gallery. You’ve been warned.
Before setting up a gallery it is useful to understand what it actually is. Ultimately a gallery is nothing more than a list of extensions (not necessarily a VS extension) with any corresponding metadata that can be installed into VS. All a gallery is really responsible for is providing a list of available extensions and sending the extensions to VS when needed. Therefore a private gallery really doesn’t do a lot. A gallery uses an Atom feed to send the list of available extensions to VS. VS then displays the list in the UI. When the user selects an extension VS calls back to the gallery and request the extension. The gallery sends the extension to VS and VS takes it from there. Pretty simple stuff.
The feed (atom.html) provides quite a bit of information to VS – the extension name, version, unique ID, author, description, create date and update date. From this VS can generate everything it needs. Each extension only has one entry in the feed. When VS pulls the feed it compares the current version information to what is installed on the user’s machine. If there is a difference then VS adds the extension to the list of updates that are available.
Unfortunately generating the Atom feed is the hard part of hosting a private gallery. Not only is it ugly but it gets bigger as you add new extensions. During the betas and RC Microsoft had a tool to generate this for you but it was pulled before the release. You’ll still see it documented but it is gone. Thus you’ll have to either manage the file by hand or use some other tool to build it.
Here’s what a basic feed might look like.
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title type="text">My Extension Gallery</title> <id>uuid:6df6542f-d22f-4138-90dd-a386fa370e64;id=1</id> <updated>2013-01-11T23:36:04Z</updated> <entry> <id>uuid:6df6542f-d22f-4138-90dd-a386fa370e64;id=2</id> <title type="text">My Extension</title> <summary type="text">Provides something useful.</summary> <published>2013-01-11T11:51:56-06:00</published> <updated>2013-01-11T11:08:09-06:00</updated> <author> <name>Me</name> </author> <category term="Templates" /> <content type="octet/stream" src="galleryurl/Templates/MyExtension.vsix" /> <Vsix xmlns="http://schemas.microsoft.com/developer/vsx-syndication-schema/2010"> <Id>MyExtension.VSIX.ID</Id> <Version>1.0</Version> </Vsix> </entry> </feed>
Let’s break down the elements.
- The title of your gallery.
- A unique ID for the feed.
- This should be updated each time the feed changes so VS will refresh its view. I have not confirmed this but it is reasonable to assume that VS will look at the value and not bother walking through the extensions if it hasn’t changed since the last time the feed was read. Note the date/time values are in UTC format.
Each extension has an
<entry> element within the feed.
- The unique ID of the entry. This should generally just be the VSIX unique ID.
- What the user’s sees when seeing the extension.
- The nice description that shows up below the extension.
- The date/time when the extension was added.
- The date/time when the extension was last updated.
- The author of the extension.
- An optional element that specifies a subfolder the extension should appear under in the gallery UI. This is useful for grouping extensions.
- Specifies the type of extension.
- octet/stream indicates a binary file.
- This is the full URL to the extension. If an extension appears in the gallery but cannot be downloaded then this attribute is most likely wrong.
- This starts the metadata for the VSIX itself.
- The unique ID of the VSIX package. This should generally match the ID of the entry.
- The version of the extension. This should match the version of the VSIX extension.
It is generally assumed that an extension is shipped as a VSIX but it could also be an MSI. Beyond the source URL not much changes in the gallery.
Hosting a Gallery in IIS
To host a gallery all that needs to happen is that a listener on a URL needs to return back the Atom feed when requested. It also needs to return the files when they are requested by VS. This can be done rather easily using IIS. I use the existing TFS web server to help keep things consolidated but you can use any web server that is available.
Create a new web site (or application) in IIS (ex. MyGallery).
Optionally configure it to use a custom app pool.
The site does not .NET or anything so the only additional configuration is to set the
atom.htmlfile as the default document. This should cause a basic
web.configfile to be generated.
atom.htmlfile to the root of the site following the format given earlier.
Browse to the site and you should see the RSS feed.
Note: In IE 10 I was unable to view the feed even though it was working. I used FireFox to confirm it was working properly.
If the feed does not appear then the site is not configured properly. Verify the security on the folder is correct and the site and app pool are running. On newer versions of IIS the app pool will run under
ApplicationPoolIdentity which makes it more difficult to configure. Consider using a fixed account. Use the Basic Settings in IIS to test the connection for the path.
Now you can add new extensions to the site. Ideally extensions should be placed in a subfolder under the site. Remember to account for the folder in the content
src attribute. When adding new extensions or updating an extension one be sure to update the
updated element of the feed and the same element for the extension (if it is an update).
Configuring Visual Studio
Configuring VS to use the new gallery is really simple.
- Go to the Tools\Options dialog (Tools\Options).
- Go to the Environment\Extensions and Updates options.
- Click Add
- Specify a name for the gallery (ex. Company).
- Specify the URL to the gallery (the site root where the Atom feed is).
- Click Apply and then OK.
- Go to the Tools\Extensions and Updates gallery.
- Expand the Online node and the new gallery should be listed.
- Click the gallery and the extensions (and categories) should be shown.
To test the feed select one of the extensions and click Download.
Note: A 404 error indicates either the source URL is wrong or there is a permissions problem.
Hosting a Gallery in IIS (Part 2)
The above process works but you’ll likely run into several problems.
- IIS is picky about serving up files that end with VSIX or MSI.
- Maintaining the Atom feed is a nightmare.
Fortunately there is a better option right now. Jakob Ehn has written a simple MVC application for hosting an extensions gallery. He blogged about it here. The source is available on CodePlex. This application is still a beta but, other than a few issues mentioned below, it seems to work pretty good. To use it you’ll do the following.
- Download the setup program.
- Run the installer on the IIS machine. Note: The installer must run with admin privileges so you’ll need to start it from an elevated Explorer window or command prompt.
- On the first installer options page specify the web site and app pool to use (ex. MyGallery).
- On the second installer options page specify the path to the files on the disk. The default is probably fine.
- Click Install.
Unfortunately it is still not completely configured so open the
web.config and make the following changes.
FeedTitleto the display name of the gallery (ex. My Gallery).
BaseURIto the base URI of the site (ex. http://myserver/MyGallery/Gallery/Extension/). The “/Gallery/Extension/” is required.
VSIXAbsolutePathto the file system path where the extensions will be stored. Personally I don’t like to store data files in the website directory so I use a separate path but be sure that the app pool identity has permissions to read the directory.
- Save the file.
The application was written using MVC 4 but the installer does not install the required binaries. Either ensure that MVC 4 is installed and configured for your web server or manually copy the MVC 4 binaries to the site. Browse to the site to confirm the feed is working.
To add or update extensions simply drop the files into the configured
VSIXAbsolutePath directory. If you want to use a category then create a subfolder. From what I can tell VS only allows a single level of categories so do not try to nest the folders beyond a single level. Behind the scenes the application will generate the Atom feed whenever it is requested via the URL. To generate the feed it enumerates the files in the directory. For each VSIX it generates an entry. The feed is regenerated each time it is requested so the update date will always change. For each entry the published and update date come from the file’s create and last updated values. The remainder of the information is determined by the VSIX file itself. If the extension is in a subfolder of the root then a category entry is added for it. Now you can use VS to browse the gallery.
As of 13 January 2013 there is a bug in the installed code that prevents download from working. When a request is sent to the application to download the file it attempts to open the file for read/write access. Unless the app pool has permissions (generally not a good thing) then it will fail and a “Not Accepted” error will be generated. The fix has already been made in the code but the installer has not been updated. Therefore you can download the source and rebuild it. Then just swap out the binaries.
The application is still in beta so be prepared for some issues. Here’s a list of things I would like to see changed.
- The installer needs to be updated to contain the file download bug.
- The MVC 4 binaries should be installed to the application directory if they do not yet exist.
- The installer should prompt for the settings so we don’t have to manually edit the config file.
- It is probably not a good idea to regenerate the feed each time VS requests it. As more files are added this will get really slow. Ideally a file system watcher should be used to detect changes in the files and the feed regenerated only when changes are detected.
- Currently only VSIX files are supported. MSI-based extensions are not.
- The ID of the entries are based upon the ID of the gallery rather than the ID of the VSIX. Ideally they should match the VSIX of the entry.
- The publish/update date of the files are not good indicators of the extension lifetime. Ideally the publish date should be set the first time the entry is added to the feed and should never be changed. This would require that the feed be updated and never recreated (as it is now).
- Perhaps as an alternative extension metadata could be managed in a database (like NuGet) while the files are stored on disk. This eliminates the need for watching the file system and updating the feed.
None of these are showstoppers unless you are dealing with a lot of extensions. Overall the Inmeta application makes hosting a private gallery a lot easier.
As VS extensions become more popular it is inevitable that you will want to write and publish your own. But some of them will be for personal or company use and should not be published on the public gallery. Hosting a private gallery is relatively painless to do and allows for private extensions. VS fully supports this concept. MSDN provides more information on how to use a private gallery. Hopefully MS will eventually release some tools to make creating and managing private galleries easier. Until then Jakob’s project will fit the bill.