MyPublisher is a publishing add-in which integrates Source Control and Web Deployment projects into a single publishing solution. It also allows for file level control over the published website. This article will cover existing Visual Studio publishing mechanisms and their short comings. It will go on to describe the goals of the MyPublisher project and how those goals are implemented.
Unless you’re a hobbyist or an extremely small shop, you probably have a formal publishing process. This will be different for pushing a site to a production server vs. pushing a site to staging, and will involve using some sort of source control system. This will look something like this…
- Get latest from Source Control
- If no errors, then check-in and label as Release Candidate 1
- Push site to staging server for testing (robotic or manual)
- Get label that passed testing
- If no errors, then label (nothing should be checked out) as Final
- Push site to production
The biggest difference is when you go to production, you should get from the label that passed testing. If you use common components between various products (which you should be doing), then you must ensure that the version which goes to production is the tested version. This will eliminate the risk of incompatible code from being published.
Visual Studio 2005 Publishing
One of the largest grips that ASP.NET developers have with Visual Studio is the lack of options when it comes to publishing. At face value, Visual Studio offers two flavors of publishing: “Copy Web” and “Publish”.
The Copy Web functionality is essentially the same as an FTP type of publishing vehicle. It is only useful if your site has its code-behind in the app_code folder. While this has its place, most web administrators don’t take well to the idea of having source code on the production server.
The Publish functionality is clearly more useful as it will build the site DLLs and publish the finished build via FrontPage, FTP, or File share. This, however, is not without issues. First, if it’s on your local, it will get published. Likewise, it completely rebuilds the target site from scratch based on your local. So, if you have users upload files to the production site, and then you publish your local, you just blew away all the user uploads. The only way around this is to make the folders you do not want to publish sub-web’s on your local IIS and folders you do not wish to be written over sub-webs on the target. Then, the VS’s publisher understands that they are separate, exclusive websites, and will not publish them. But if you have files locally which you do not want published in a folder which will be published, you’re out of luck. Also, you have no control on how Visual Studio generates the DLLs. It will take your code and spread it out across several DLLs, and publish those to the bin directory for the site.
Web deployment projects go a long way in solving that as they will build your website in accordance to several options you can select from a nice UI interface to an XML MSBuild file. But, it simply builds the site and does not deploy it. Also, there is no integration with source control; specifically labeling your releases and ensuring the latest code always is published or code as of a specific label is published. All these things can be done from the Source Safe client. However, it’s not integrated into the publishing process.
Goals of MyPublisher
The idea with this add-in is to give the developer an easy way to publish sites, automating the source control labeling and file fetching, but giving the developer a low level control on what is published. This is done by integrating with Source Safe and using Web Deployment projects. In addition, a controlling XML file is added to each directory to allow for the developer to prevent publishing specific files in a directory or the directory itself. Also, MyPublisher should not remove files from the target web unless directed to do so by the developer. This will allow for user uploads without having to create a virtual directory for them.
Web Deployment Projects
Let me take a minute to talk about Web Deployment projects (WDPs). You can learn a lot about WDPs from MSDN, so I won’t regurgitate that for you, but what I will do is give you some advice on using them. A Web Deployment project can be created by right clicking a website and selecting Web Deployment Project: pretty straight forward so far. For MyPublisher to find these, you must put them in a Build folder off of your solution’s *.sln file. This is because there is no way to know from the
EnvDTE object where they are because the
Filename property of the project throws an error (very frustrating). I build all my websites as actual websites in IIS, and not in the file system. For this type of setup, you need to make sure you have the “Use IIS Metabase for Source Inputs” on the compilation tab so the deployment project knows you are not using the file system. Likewise, you need to make sure you do not check the “Create an IIS virtual directory for the output folder” on the deployment tab, or if you do, make sure that you don’t select your development virtual directory as you will deploy over your development directory, thus causing havoc.
Source Safe Integration
By using interoperability, you can integrate into Visual Source Safe simply buy referencing the Microsoft.VisualStudio.SourceSafe.Interop DLL. One of the biggest mistakes I see developers make with this is to make the user enter the path to the srcsafe.ini file. Some solutions parse the project file itself, which will work as long as you’re not dealing with web projects. This is completely unnecessary though as this information is obtainable from the project file itself, although it’s a bit tricky to find.
I implemented a common interface that VSS and Team can both use (Team is as yet undeveloped). You get the bindings from the project, and pass them into the constructor.
SourceControl2 sc = (SourceControl2)DTE.SourceControl;
SourceControlBindings d = sc.GetBindings(proj.FileName);
case "MSSCCI:Microsoft Visual SourceSafe":
return (ISourceControl)new SourceSafe(d);
return (ISourceControl)new VSTS(d);
This is the constructor to the
public SourceSafe(SourceControlBindings Bindings)
DirectoryInfo di = new DirectoryInfo(Bindings.ServerName);
msFileName = Bindings.ServerBinding.Split(',');
msFileName = msFileName.Substring(msFileName.IndexOf("$"));
msFileName = msFileName.Split('\"');
vssDB.Open(di.FullName + "file://srcsafe.ini/", Environment.UserName, string.Empty);
The rest of the object is pretty straightforward. One thing to notice is that our SourceSafe logins are our user names, and we don’t have passwords on them. The main reason is that if a developer has left for vacation, has code checked out, and we need to do a push for some reason, we can undo the checkout and change the file and then merge the versions later. If you are not doing this, then you should consider creating settings for the UID and password for SourceSafe. Although I haven’t tried it yet, Team actually looks significantly simpler as it’s basically a list of remote procedure calls via a Web Service.
Basically, publishing is the vehicle for moving your build output from the source machine to the target. Generally, there are three methods for doing this: File share, FTP, FrontPage. Using a file share is clearly the easiest to program and the most straightforward. While it is possible to simply use XCOPY to move the site, I move the files one by one and build the directories as I go. This enables me to be able to control, via the Publish.xml file, which files and directories of the build actually get published.
FTP is a bit more complicated, but .NET makes it easier by using the
FtpWebRequest object. MSDN has plenty of examples on using this, but one thing I would like to point out is that in the case of the BIN directory, you always want to clear out the DLLs you publish. If you switch from a single DLL to a DLL per page, you don’t want your old DLL out there. Likewise, you always want to make sure you are publishing the concurrent versions of any dependencies in your project. The BIN directory’s Publish.XML is, by default, set to clear out all the files prior to publishing the new files.
FrontPage is by far the most difficult way to go from a development point of view. It is nice for deployment if you don’t mind the overhead associated with it because you can publish through firewalls and the like. FrontPage essentially turns each file into a byte array, and sends it through port 80 to one of the FrontPage extensions (DLLs in badly named folders) on the target website. These DLLs then invoke a specified procedure on the data stream. I like to use file share for speed (if you have to publish in an emergency, the faster it’s done, the better, and FrontPage is extremely slow) and for security (FrontPage is notoriously insecure). Having said that, we do use FrontPage so we can publish our sites at home via VPN, late at night, so we don’t affect our users as much. Many times, database changes also need to be made, so there will always be a little downtime, so late at night is the best answer for us.
The Result: MyPublisher
When the MyPublisher add-in is first opened for a web project, it will add a Publish.xml file to each directory of the website. This file itself does not get published, but will allow the developer to prevent individual files or whole directories from being published. While files and directories are still built, they simply are not copied to the target server.
On the first tab, you will notice that you can publish multiple websites to multiple locations. This was designed to work with our web farm. Also notice that three methods of publishing are supported: FrontPage, FTP, and file share.
On the second tab, all of the source control interaction takes place. When you publish, if your project is not controlled by source control, these options will be ignored.
On the third tab, the status of the deployment is shown. Probably one of the simplest things, but the most useful is the summary of the target and the source displayed prior to publishing. It is extremely important that you don’t accidentally push untested code to production, so it’s nice to have this summary before you pull the trigger.
The hope is that we will have a well documented SourceSafe and have less risk associated with our publishing. We are just starting to use this in our shop, so I would imagine version 1.1 is not too far in the distant future. But in the mean time, happy publishing!
- MyPublisher will not create FrontPage sites for you. You must create them and then release. Likewise, you must have the root folder for FTP publishing and file share publishing already created.
- Future versions will include VSTS integration.
- The Web Deployment project must be saved in the Build folder, which is a child folder from where your solution’s *.sln file is located.
- If you use FTP, the FTP username and password are properties in the application settings. I’ll build a UI for this in a later release.
- FrontPage publishing does not work through any port other than 80.
- I should note that the front page class is something I found from a Google search and modified. For the life of me, I can't remember where I got it although I feel it should be attributed. If I can figure it out, I will give credit where credit is due.