tags:

views:

49

answers:

2

I am trying to change the connectionString in my web.config using MSBUILD on a Teamcity server. Previously I have use the attribute in a target that called this:

<PropertyGroup>
<UpdateWebConfigCode>
 <![CDATA[
  public static void ScriptMain()
  {
   XmlDocument wcXml = new XmlDocument();
   wcXml.Load(@"TCM.MVC.UI\Web.config");

   XmlElement root = wcXml.DocumentElement;
   XmlNodeList connList = root.SelectNodes("//connectionStrings/add");
   XmlElement elem;

   foreach (XmlNode node in connList)
   {
    elem = (XmlElement)node;

    switch (elem.GetAttribute("name"))
    {
     case "TCMBaseConnectionString":
      elem.SetAttribute("connectionString", "Data Source=server-name;Initial Catalog=TCMCentral;User ID=user;Password=something");
      break;

    }
   }

   wcXml.Save(@"TCM.MVC.UI\Web.config");          

  }
 ]]>
</UpdateWebConfigCode>

I would then call it in the target:

<Target Name="UpdateWebConfig">         
   <Script Language="C#" Code="$(UpdateWebConfigCode)" Imports="System.Xml" /> 
</Target>

But this keeps throwing an error. I realise this is probably a bit out of date but can't find anything to replace it .... any suggestions?

+3  A: 

I do this with a custom task, which does much the same as your code, but the MSBuidl becomes:

<UpdateConnectionString ConfigFile ="path\to\web.config"
         ConnectionStringName="MyConnectionStringName"
         ConnectionString="connection-string-here"/>

The code for such a task is

public class UpdateConnectionString : Task
    {
        [Required]
        public string ConfigFile { get; set; }
        [Required]
        public string ConnectionStringName { get; set; }
        [Required]
        public string ConnectionString { get; set; }

        public override bool Execute()
        {
            try
            {
                var fi = new FileInfo(ConfigFile);
                if(!fi.Exists)
                {
                    Log.LogError("File {0} does not exist");
                    return false;
                }
                fi.IsReadOnly = false;
                XDocument doc = XDocument.Load(ConfigFile);
                var confignode = doc.Descendants("configuration").Single();
                var connectionStrings = confignode.Descendants("connectionStrings").SingleOrDefault();
                if(connectionStrings == null)
                {
                    connectionStrings = new XElement("connectionStrings");
                    confignode.Add(connectionStrings);
                }
                var connectionElement = connectionStrings.Descendants("add").SingleOrDefault(
                    e => e.Attribute("name") != null &&
                         string.Compare(e.Attribute("name").Value, ConnectionStringName,
                                        StringComparison.OrdinalIgnoreCase) == 0);
                if (connectionElement == null)
                {
                    connectionElement = new XElement("add", new XAttribute("name", ConnectionStringName));
                    connectionStrings.Add(connectionElement);
                }

                connectionElement.SetAttributeValue("connectionString", ConnectionString);
                doc.Save(ConfigFile);
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex, true);
                return false;
            }   
            return true;
        }
    }

Note that this code will also add a connection string if its not present, this is probably more complexity than you need right now.

Jamiec
Jamie, Thanks for the help. I ended up using the XmlUpdate attribute in MSBuildCommunityTasks. See my answer below. Thanks again. Andrew
abarr
A: 

I ended up using the MSBuildCommunityTasks XmlUpdate attribute. Below is my target:

<Target Name="UpdateWebConfig">        
    <XmlUpdate XmlFileName="C:\TCM.NET\Current\TCM.MVC.UI\web.config" XPath="configuration/connectionStrings/add[@name='TCMBaseConnectionString']/@connectionString" Value="Data Source=server-name;Initial Catalog=TCMCentral;User ID=user;Password=something" />
</Target>

This works great for me.

abarr
Good choice, I have also began to change to a more generic "UpdateXml" type task, albeit one of my own authoring rather than MSBuildCommunity.
Jamiec