Showing posts with label VS.2008. Show all posts
Showing posts with label VS.2008. Show all posts

Sunday, May 31, 2009

Programmatically change Web project settings from dynamic port to static

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

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:

KeyValue
UseIISFalse
AutoAssignPortFalse
DevelopmentServerPort2332
DevelopmentServerVPath/
IISUrl
NTLMAuthenticationFalse
UseCustomServerFalse
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.");
      

// up to here, "result" should be at node "WebProjectProperties" Dictionary 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.

if (hasNamespace) { this.ReverseNamespaceEnv(); } }

The main purpose of this function does is to update the project settings:
  • 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.

Additional notes for exporting project template


Template Directory Setting

The default location on XP for VS.2008 for template storage is at
      %USERPROFILE%\My Documents\Visual Studio 2008\Templates

You can change this setting at the VS.2008 menu bar: Tools --> Options.
Projects and Solutions

Export Template and Location

Create a blank project, edit it, import and reference your vital libraries.  When you're done, go File menu to choose Export Template.... Follow the wizard to complete the rest.

A project template is always exported to the default output folder where you cannot change:
      %USERPROFILE%\My Documents\Visual Studio 2008\My Exported Templates

The location you set at Projects and Solutions is primarily for the IDE to locate and load your custom templates.

If you accept the default setting Automatically import the template into Visual Studio when you export the template, IDE will automatically save a copy under that template folder where Projects and Solutions specifies.

Additional Template Folders

Project Templates Location
For the first time project template creation, three (3) additional folders will be automatically created for your template organization:
  • Visual Basic
  • Visual C#
  • Visual Web Developer
And your template file will stay with them at the same directory level. In my example, it is MyC#WebApplication.zip.

I won't bother to put the template into one of those folders. You can drag the zip file into them if you want to organize it. As long as the template is under the template folder, the IDE is smart enough to loop through its sub-folders and find your template.

Edit Template Project Description

If you want to display a descriptive name on the IDE, go to the designated project templates folder and then do the editing. In my case, it is locate at H:\dev\Visual Studio 2008\Templates\ProjectTemplates.
  • Extract MyTemplate.vstemplate from the zip file and then open it for edit.
  • Locate <Name> and give descriptive name, e.g., My ASP.NET Web Application in C#
    <VSTemplate Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
      <TemplateData>
        <Name>My ASP.NET Web Application in C#</Name>
        <Description>A C# Web Application with a specific port (.NET Framework 3.5)</Description>
        <ProjectType>CSharp</ProjectType>
        ...
    
  • Save it and then zip it back to the original zip file.
Now try to add a new project, you will see the new template shown under My Templates. Add New Template

Sunday, April 12, 2009

How to attach MDF without LDF into SQL 2005

SQL 2005 does not support DBCC REBUILD_LOG. Thus, you cannot use it to rebuild the LDF. Here is how I do to attach a database only using MDF without LDF present.

If you are only interested in attaching MDF to the SQL 2005 server without data extraction and replication, please see my part 2, which works without Visual Studio installed.

I use VS.2008 to do the trick. VS.2005 doesn't have this ability. This method probably may work in Visual Web Developer 2008 Express Edition.

Open VS.2008 and do the followings:
  1. New a Web site or use the existing one.
  2. Add the file to the project's App_Data folder.
  3. Right click this folder in the Solution Explorer and select Add Existing Item...
  4. Locate the MDF file you want to use.
  5. Then click Add.
  6. Double-click on the MDF file that you just added; it will open Server Explorer for you.
  7. Locate and right-click the MDF file data connection on Server Explorer.
  8. Select Publish to provider...
  9. Go through the wizard; when the wizard asks you where to publish, I select Script to file. It will generate a SQL file that contains all the database schema and its data.
On the SQL 2005 Server (mine is Express version),
  1. Create a database with the same name as your MDF.
  2. Run the SQL file you just created by Server Explorer in VS.2008.
Your database should be revived now!