Introduction
IPublisher 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 web site. This article will cover existing Visual studio publishing mechanisms and their short comings. It will go on to describe the goals of the IPublisher project and how those goals are implemented.
Publishing web sites
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…
For Staging:
1. Save
2. Get Latest from Source Control
3. Rebuild
4. If no errors then check-in and label as Release Candidate 1
5. Push site to staging server for testing (robotic or manual)
For Production:
1. Save
2. Get Label that passed testing
3. Rebuild
4. If no errors then label (nothing should be checked out) as Final
5. 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 dll’s 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 web sites 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 DLL’s. It will take your code and spread it out across several DLL’s 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 web site 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 IPublisher
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, IPublisher 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 (WDP’s). You can learn a lot about WDP’s 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 web site and selecting Web deployment project: pretty straight forward so far. For IPublisher to find these you must put them in a Build folder off of your solution’s *.sln file. This is because there is not 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 web sites as actual web sites 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);
switch (d.ProviderName)
{
case "MSSCCI:Microsoft Visual SourceSafe":
return (ISourceControl)new SourceSafe(d);
break;
default:
return (ISourceControl)new VSTS(d);
}
This is the constructor to the SourceSafe object…
public SourceSafe(SourceControlBindings Bindings)
{
DirectoryInfo di = new DirectoryInfo(Bindings.ServerName);
msFileName = Bindings.ServerBinding.Split(',')[0];
msFileName = msFileName.Substring(msFileName.IndexOf("$"));
msFileName = msFileName.Split('\"')[0];
vssDB.Open(di.FullName "file://srcsafe.ini/", Environment.UserName, string.Empty);
}
The rest of the object is pretty straight forward. 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.
Publishing
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 straight forward. 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 dll’s 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 you 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 (dll’s in badly named folders) on the target web site. These dll’s 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 we do use FrontPage so we can publish our site’s 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: IPublisher
When the IPublisher add-in is first opened for a web project it will add a Publish.xml file to each directory of the web site. This file itself does not get published but will allow the developer to prevent individual files or whole directory 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 web sites 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 show. 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.
Conclusion
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!