The dreadful SUO file and ASP.NET Web Projects in VisualStudio .NET 2002/2003

The .SUO (Solution User Options) file is used by VisualStudio .NET to store user-specific settings. The source control integration package in VisualStudio uses same file to store enlistment translation table for web projects, the offline statuses of projects, and other settings used for project bindings.

Why does VisualStudio needs the enlistment translation table for webs?

Let's assume next scenario:
- John creates a solution containing the web project http://JohnsMachine/WebProject1/WebProject1.vbproj
- John adds the solution to source control
- Tim, his coworker wants to work on the same project as John
- Tim opens the solution from source control and is prompted with a SetProjectLocation dialog
- Tim needs to pick a location where his own copy of the project will be stored. He chooses http://TimsMachine/MyProjects/WebProject1
- Let's assume this location maps on Tim's machine to D:\Inetpub\wwwroot\MyProjects\WebProject1\ - VisualStudio will copy there the project files, and Tim can contine working on the project

When Tim opens the solution from source control, setting a new project location is required because Tim shouldn't work on the same files as John does. (In fact, this is what the Web Projects' Isolated Model is about)
Note that after enlisting in the web project, the solution file (.sln) contains the original web location (http://JohnsMachine/WebProject1/WebProject1.vbproj)
The information about Tim's location of the web project needed to be saved somewhere. Of course, the solution file cannot be changed to reflect this location, because the solution is shared between John and Tim, and any change Tim will make to the sln file will affect John.

To solve this problem, VisualStudio reused the .suo file and saved there the web project translation.
Perhaps this was not the best choice, because the suo file is hard (if not impossible) to be modified should the translation need to be modified at a later time.

What does the translation table contain?

For each web project that is part of the solution (and for each the enlisting via SetProjectLocation was successful) VisualStudio stores in the suo file next information:
- The original web project path (the web project path for the user who added the solution to source control, in the above case http://JohnsMachine/WebProject1/WebProject1.vbproj)
- The current user's HTTP enlistment (in the above case http://TimsMachine/MyProjects/WebProject1/WebProject1.vbproj)
- The UNC location of the web project (in the above case D:\Inetpub\wwwroot\MyProjects\WebProject1\WebProject1.vbproj)

The source control integration uses the HTTP enlistment path to instruct VisualStudio to open the current user's enlistment instead of the path stored in the solution file and the UNC location when interacting with the source control provider (e.g. SourceSafe) to get, checkout, checkin the files.

The good thing about translation table:

- This is the base of the isolation model: each user has its own web project enlistment, the solution file remains unchanged and shared across users working on the same solution
- Once a web project is added to source control, the original machine can be recycled (e.g. when the user leaves the company)

The bad:

- If the suo file is deleted by mistake or by users who want to "reset" some user specific settings, the web projects will lose their enlistment information
- The translation table cannot be easily modified
- If the web project is moved on disk, and the http path is changed in IIS to target the new disk location, the web project will stil not open, because of the UNC path saved in the suo
- Rolling build machine scenario has problems with web projects (see below)

What is the rolling build machine scenario?

If you have good working procedures then you must have a build machine to test nightly what the developers are changing during the day...
How this works? Well, you have a dedicated machine that once a day or often gets the latest version of your solution's sources from the source control database. Then it kicks a build in order to identify possible build breaks since the last build. Or simply this is used to create and label a daily build.
All these are very nice, but when the solution contains web projects, things become hairy...
In general a build machine is an automated process that gets sources using command line. A solution got this way from source control won't have a matching SUO file (see below for possible issues). A correct solution would be to automate VisualStudio to open from source control and let it create the suo file and correct enlistments. But this solution is whether hard to implement (because it's hard to drive provider-specific dialogs like SourceSafe's SelectProject dialog), or you simply don't want to create a new enlistment on the build machine each day.

What happens if the .suo file is missing?

Missing the SUO file is always bad for web projects integration.

When using command line to build projects, if the SUO file is missing from disk, then VisualStudio will use the original web project (as stored in the sln file).
In some cases, it may appear things are working normal, but if you managed to open and build a website be aware that what you're building may be another user's enlistment! You may be building an out of date enlistment, and not what you expected to build if you manually got the web project files in a specific place on disk and assumed VisualStudio will reuse it...
In some other cases, the build will simply break if the original web project path cannot be accessed (e.g. it's on a machine that doesn't exist anymore).

When using the VisualStudio UI to open such solution containing controlled web projects but without suo file you will be prompted with SetProjectLocation dialog to create new enlistments. If you manually got the web project files from source control and created virtual folders in IIS to point to the local projects, then VisualStudio will not recognize the pre-existing locations as current enlistments and will prompt you to create new ones. The result is that you'll end up with two copy of the project files on disk.

How can I fix the build machine scenario for SourceSafe?

Well, this depends on your web projects configuration. I'll give you a couple of possible ideas.

Idea 1
Let VisualStudio to create an suo file and enlistments, then reuse the enlistments:
On the build machine, use VisualStudio UI (DevEnv) to open the solution from source control. Set correct paths in SetProjectLocation and finish opening from source control. Then close VisualStudio. The rolling build needs to reuse the local paths created by VisualStudio in previous step (the current web enlistments) when getting the web project files, always overwriting the local files, and never trashing the suo file. VisualStudio will use the paths saved in suo when working from command line or if the solution is reopened later in UI.
Caveats: When a new web project is added to the solution, you'll have to open first the solution in VS and do a Get (so you can establish the translation for the new web) before letting the rolling build to do the Get.

Idea 2
Reuse a pre-created suo file:
On a machine, use VisualStudio UI (DevEnv) to open the solution from source control. Set correct paths in SetProjectLocation and finish opening from source control. Then close VisualStudio. Save the suo created this way. On the build machine you can start from scratch everytime. Get the solution files using SourceSafe command line. Create a folder on disk to match the UNC path that was saved in the pre-created suo file and get the web projects files there. Create a virtual folder in IIS to point to the location on disk from the pre-created SUO, and to match the web project http path from the pre-created SUO. Copy the pre-created suo in the solution folder. VisualStudio will use the paths saved in the pre-created suo when working from command line or if the solution is reopened later in UI.
Caveats: When a new web project is added to the solution, you'll have to open first the solution in VS and do a Get (so you can establish the translation for the new web) before letting the rolling build to do the Get.

Idea 3
On the build machine work without suo:
Get the solution files using SourceSafe command line. Create a folder on disk and get the web projects files there. Create a virtual folder in IIS to point to the location on disk where the project files were got, and to match the web project http path as stored in the sln file. The build machine will simply build the solution from command line, and VisualStudio will use the path stored in the sln file to open the project.
This works best when the project file has a localhost path, and if the machine is not used by regular users to work on the same project (such that path stored in the solution file will only identify the build machine web enlistment in the local IIS).
Caveats: Do not open the solution in VisualStudio as VS will not recognize the virtual folder as the current enlistment and you'll be prompted to create a new enlistment for that web.

Idea 4
On the build machine work without suo, and alter the solution to point to the current enlistment:
Get the solution files using SourceSafe command line. Create a folder on disk and get the web projects files there. Create a virtual folder in IIS to point to the location on disk where the project files were got. Flip the read-only attribute on the solution file. Replace the original web project path in the solution file with the virtual folder created earlier in IIS.
Caveats: Do not open the solution in VisualStudio as you'll be prompted to create a new enlistment. Do no not open the web project alone (unless you change the vbproj.vspscc file as well). Do not checkin the modified solution file or you'll break other users' integration.

Idea 5
On the build machine work without suo, and manually unbind the project from scc:
I'm not going to enter in details here because you really must know what you're doing if you choose this path. Get the solution files using SourceSafe command line. Create a folder on disk and get the web projects files there. Create a virtual folder in IIS to point to the location on disk where the project files were got. Alter the sln file to point to current path in IIS. Alter the SourceControl section in suo file to unbind the web project. Alter the SourceControl section in the web project file to unbind the web project. Delete the vbproj.vspscc file. In extremis you can manually unbind all projects...
Caveats: You can easily break source control integration if you don't know what you're doing. The web project will not be controlled on the build machine if you're choosing this scenario. Do not checkin the modified solution file or you'll break other users' integration.

(Back to SourceSafe and source control integration page)