If you have a solution consisting of many Web applications that currently use dynamic ports for debugging and now you want to modify them to be static, it will be tedious and extremely time-consuming to go in each project and change it. I developed an application to resolve this. For the future sake, I create a custom project template so that I don't have to go in the project properties and change it whenever a new Web application is created. Indeed, with my own project template, I can customize other things like libraries, references and macros I always use in a project.
Currently the application supports VS.2008. It takes the solution file (.sln) as an input to locate the project locations, and then goes in each indiviual project file (e.g., .csproj and .vbproj) to alter the setting. It only targets Web application including WCF. but not Website because the Web project properties for a Website is stored in .sln file.
The idea behind this application is very simple.- Define the settings
- Define data structure to contain the settings
- Define function to alter the settings
- Describe basic project file structure in Solution (.sln)
- Put everything together
- Request my application
Define the settings
First, I create a setting file called vs.xml. Currently the port is default to 2332. The text in light green background is similar to the text you may find in your Web project file.
<?xml version="1.0" encoding="utf-8" ?> <VisualStudio target="Visual Studio 2008 "> <SolutionFile version="10.00" desc="Microsoft Visual Studio Solution File, Format Version"> <Languages> <Langauge enabled="true"> <Type>CSharp</Type> <GUID>{FAE04EC0-301F-11d3-BF4B-00C04F79EFBC}</GUID> <extension>.csproj</extension> </Langauge> <Lanaguage enabled="true"> <Type>VisualBasic</Type> <GUID>{F184B08F-C81C-45f6-A57F-5ABD9991F28F}</GUID> <extension>.vbproj</extension> </Lanaguage> </Languages> </SolutionFile> <ProjectFile desc="Microsoft Visual Studio Project File"> <Web><!-- Begin Settings --> <ProjectExtensions> <VisualStudio> <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}"> <!-- Define Web Project Settings --> <WebProjectProperties> <UseIIS>False</UseIIS> <AutoAssignPort>False</AutoAssignPort> <DevelopmentServerPort>2332</DevelopmentServerPort> <DevelopmentServerVPath>/</DevelopmentServerVPath> <IISUrl> </IISUrl> <NTLMAuthentication>False</NTLMAuthentication> <UseCustomServer>False</UseCustomServer> <CustomServerUrl> </CustomServerUrl> <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> </WebProjectProperties> <!-- End of Web Project Settings --> </FlavorProperties> </VisualStudio> </ProjectExtensions> <!-- End of Settings -->
</Web> </ProjectFile> </VisualStudio>
The above vs.xml can be altered to support VS.2005. But I am going to describe the details here.
Define data structure to contain the settings
Create a data structure to contain all the Web properties; they are:
Key | Value |
---|---|
UseIIS | False |
AutoAssignPort | False |
DevelopmentServerPort | 2332 |
DevelopmentServerVPath | / |
IISUrl | |
NTLMAuthentication | False |
UseCustomServer | False |
CustomServerUrl | |
SaveServerSettingsInUserFile |
I use a Dictionary to capture this.
private Dictionary<String, String> props;When the application reads vs.xml, it will automatically load all the settings into this props Dictionary.
Function to alter the settings
The function SaveTo as shown below will update the settings into the project file based on the settings in props. Note that my current version is slightly different now.
/// <summary> /// Saves the settings to a specific file. /// The project file must have ProjectExtensions/VisualStudio/FlavorProperties/WebProjectProperties /// nodes in order to be qualified for process. /// If the required elements under WebProjectProeperties node are missing from the specific document, /// it will insert them. /// The original elments in the document under that node remain intact if they don't match. /// </summary> /// <param name="fileName">the exact full filename of the project file for save</param> public void SaveTo(String fileName) { String namespaceUri = null, prefix = null; bool hasNamespace = this.HasNamespace(fileName, out namespaceUri, out prefix); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(fileName); XPathNavigator navigator = xmlDoc.CreateNavigator(); XmlNamespaceManager namespaceManager = new XmlNamespaceManager(navigator.NameTable); if (hasNamespace) { SetupNamespaceEnv(prefix); namespaceManager.AddNamespace(prefix, namespaceUri); } XPathNavigator result = null; if (navigator.HasChildren) result = navigator.SelectSingleNode(GetTargetNodeXPathExpression(), namespaceManager); else throw new XmlException("Invalid file format, or it is not a Web project file."); if (result == null) throw new XmlException("It is not a Web project file.");The main purpose of this function does is to update the project settings:// up to here, "result" should be at node "WebProjectProperties" Dictionary
if (hasNamespace) { this.ReverseNamespaceEnv(); } }dup = this.CloneProperties(); if (result.MoveToFirstChild()) { do { result.SetValue(dup[result.Name]); dup.Remove(result.Name); } while (result.MoveToNext()); this.changed = false; // all properties updated. if (dup.Count > 0) { // Missing properties we need to save, do INSERT to file now...; result.MoveToParent(); // position back to "WebProjectProperties" node this.AppendChild(ref result, dup); } } else { // no child found at "WebProjectProperties" node this.AppendChild(ref result, dup); // add a child nod with all the needy settings } xmlDoc.Save(fileName); // Now is time to save to disk.
- First, it locates the <WebProjectProperties> node to begin the process.
<ProjectExtensions> <VisualStudio> <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}"> <WebProjectProperties> ... </WebProjectProperties> </FlavorProperties> </VisualStudio> </ProjectExtensions>
- When the node is found, the function will temper the settings accordingly. All settings
are stored inside the <WebProjectProperties> node. However,
- If there is empty inside the <WebProjectProperties> node, all settings will be appended into it.
- According to props, any missing setting(s) will be added accordingly.
- Any extra settings cannot be found in props will remain intact.
Describe basic project file structure in Solution (.sln)
If you use a text editor to open .sln file and view it, you will find that each project may contain the following structure.
Project("language_GUID") = "project_name", "project_location_or_file", "project_GUID"
ProjectSection(...) = ...
...
EndProjectSection
EndProrject
A regular Windows or Web project will not contain ProjectSection.
But if a Web project is type of Website, ProjectSection is used for storing
WebsiteProperties because it doesn't own a project file.
A WCF client may use WebsiteProperties for its
ProjectDependencies. In sum, most projects only contain two lines:
The first Project line and the EndProrject line.
For example,
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyTest", "Test\MyTest.csproj", "{7C0275FE-A91D-42E9-9EF1-5CCBC9D54C3C}"
EndProrject
Put everything together
All project locations registered with the solution are relative to the solution. Thus the location Test\MyTest.csproj in the above example is a relative path to its solution. As soon as the project location is found, convert it to the absolute path and then feed it to the function SaveTo, SaveTo will update the settings automatically.
In order to accomplish this, I create a Collection to contain all the
project data found in the solution file.
private Collection<ProjectIdentifier> projectCollection;Each project data is defined in the following class:
public class ProjectIdentifier { private String langGuid = null; private String name = null; private String location = null; private String guid = null; public ProjectIdentifier(String langGuid, String name, String location, String guid) { this.langGuid = langGuid; this.name = name; this.location = location; this.guid = guid; } ... }
When everything is ready, loop through the projectCollection to update the project files:
foreach (ProjectIdentifier project in c) {
...
if (System.IO.File.Exists(project.Location)) {
try {
...
if (project.IsWebProject()) {
...
this.Backup(project.Location, this.txtTag.Text.Trim());
propsBuilder.SaveTo(project.Location);
...
}
catch (Exception ex) {
String err = String.Format("Error occurs: {0}{1}{2}",
ex.Message, Environment.NewLine, ex.StackTrace);
...
}
}
else { // file not found or is not a file.
...
}
} // foreach
Request my application
Before execution, my application will first back up the project file by default while it traverses the project folder. You can override this setting if you don't like it. The backup files can be programmatically removed in a later time when you feel comfortable with the changes. I don't know how useful for you but it certainly helps me to resolve a lot of tedious tasks. Please feel free to leave me a message via the comment box for requesting this application if you think that it will be helpful to your issue. Don't forget to leave your email for response. All application requests will NOT be left on comment.
Update August 6, 2009
On or off there are people requesting it. Here are the links where I put for storage so I am no longer to manage and distribute them myself. Please feel free to download it yourself. The code has been changed since this post.
Download: [ Source ] [ Binary ]
Note that: if you request it, then you use it as your own risk. I am not responsible for any damages that may occur.
Update July 15, 2011
Sorry, this application is no longer to download. It is hard for me to ensure
that the files are still alive.