+2  A: 

How are you deploying your builds. In my environment, this used to be a pain point too, but now we use cruisecontrol.net and script our builds in nant. In our script, we detect the environment and have different versions of the config settings for each environment. See: http://www.mattwrock.com/post/2009/10/22/The-Perfect-Build-Part-3-Continuous-Integration-with-CruiseControlnet-and-NANT-for-Visual-Studio-Projects.aspx for my blogpost onthe subject of using cruisecontrol.net for build management. Skip to the end fora brief description of how we handle config versions.

Matt Wrock
A: 
  1. Keep web.config out of Source Control (everybody has it's own where can mess up, etc)
  2. Person responsible for deployment adds changes to web.config (f.eks. one who has overwritten web.config last time ;) )
  3. Keep track on changes in web.config in wiki/bugtracker/txt document/whatever

At least it works for team made of 12 devs and 4 analysts.

Rafal Ziolkowski
Hmm, yeah, this is what happens a lot of the time. But there's got to be a way of achieving ultimate safety by making it automated. I don't like the idea of not checking in the web.config file
Paul
This advice sounds dubious!
Paul Suart
Interesting in theory, but I disagree - fundamentally there are only two issues: 1) Differences between test and live (debug settings mostly) and 2) Instance specific config. You deal with the latter by moving it out of web.config and the former using appropriate build tools.
Murph
Terrible advice. Promotes exactly the human error the questioner is concerned about and doesn't address the question.
Pete Montgomery
A: 

I don't think you can 100% avoid this.

The last years of work ever and ever shows: where human worked, there are fails.

So, here are 3 ideas from my last company, not the best maybe, but better then nothing:

  1. Write an batch file or an C#.Net Application that change your web.config on a doubleclick
  2. Write a "ToDo on Release"-List
  3. Do pair-realesing (== pair programming while realease :))
Kovu
Terrible advice. Promotes exactly the human error the questioner is concerned about and doesn't address the question.
Pete Montgomery
+2  A: 

Visual Studio 2010 supports something like this. Check it out here.

Tim S. Van Haren
Very cool! Thank you.
Kovu
Yes. Microsoft are finally giving us a supported, standardised solution which I intend to hungrily lap up.
Pete Montgomery
+5  A: 
this. __curious_geek
Giving this one a go now...looks very good
Paul
This is copying the project files from the main web project, into the deployed code output. Is there a way to stop this?
Paul
It compiles your asp.net project code-behind files into single assembly and prepares them for deployment - which is a good thing. All code-behind classes are compiled into assemblies and merged them into one final single output assembly. You can delay-sign the final output assembly. Checkout Output Assembly option in the web deployment projects.
this. __curious_geek
Fantastic, this is working very well. It's replacing sections in my web.config just as I needed. The only thing that doesn't appear to be working the merge - it's pulling across dlls in my bin folder, but just copying them straight to the output folder...
Paul
For your reference I've added another screen-shot. It shows you how to merge the output assemblies into one final single assembly.
this. __curious_geek
Hmm, how bizarre. That's definitely checked for, was the first place I started. Not to worry, it does what I need anyway
Paul
+1  A: 

In my most recent project I wrote a PowerShell script which loaded the web.config file, modified the necessary XML elements, and saved the file back out again. A bit like this:

param($mode, $src)
$ErrorActionPreference = "stop"
$config = [xml](Get-Content $src)

if ($mode -eq "Production")
{
    $config.SelectSingleNode("/configuration/system.web/compilation").SetAttribute("debug", "false")
    $config.SelectSingleNode("/configuration/system.web/customErrors").SetAttribute("mode", "off")
    $config.SelectSingleNode("/configuration/system.net/mailSettings/smtp/network").SetAttribute("host", "live.mail.server")
    $config.SelectSingleNode("/configuration/connectionStrings/add[@name='myConnectionString']").SetAttribute("connectionString", "Server=SQL; Database=Live")
}
elseif ($mode -eq "Testing")
{
    # etc.
}

$config.Save($src)

This script overwrites the input file with the modifications, but it should be easy to modify it to save to a different file if needed. I have a build script that uses web deployment projects to build the web app, outputting the binaries minus the source code to a different folder - then the build script runs this script to rewrite web.config. The result is a folder containing all the files ready to be placed on the production server.

Richard Downer