views:

1087

answers:

7

I'm sure everyone has to deal with these situations, we check in our solution to source control and each dev machine will have its own resources for debugging, building and testing..

The most common being:

  • Web server (IIS)
  • Database (SQL)

The web server is easy to handle, each dev machine will have its own proj.user file to specify different debug information.

But connection strings for the app are stored in the web.config (which is under source control), ideally we don't want the web.config to be 'aware', so having to do config sections where we delegate them to other config files (not under sc) wouldn't be the best solution..

asp.net (.net?) already supports a model to have web.config inheritance, which would be an ideal scenario.. however this only works for directories.

It would be great if we could have

  • web.config <-- under version control
  • web.machine.config <-- not under version control

Of course I'm open for better suggestions of how people solve this problem.

Like.. maybe having:

  • web.base.config <-- under version control
  • web.machine.config <-- not under version control

And having a build script that creates a web.config by merging them?

Thanks in advance, Stephen.


edit

Looks like the next vs may have a way to handle this:

http://blogs.msdn.com/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx


edit edit

Possibly do'able with xml mass update today:

http://blogs.microsoft.co.il/blogs/dorony/archive/2008/01/18/easy-configuration-deployment-with-msbuild-and-the-xmlmassupdate-task.aspx


edit edit edit

Well its certainly possible to do with a simple xslt build task and a small transform that copied everything and intercepts certain properties.. just tried a proof of concept and this will save us lots of frustration, but the transformation file may be more than people are willing to accept.

Basically we store a Web.base.config in version control, and run it through the transform to generate the Web.config on a build event.

Seems like vs2010 will really help in terms of having a much more friendly version of this.

A: 

In my projects I have a web.svn.config under version control, whereas web.config is not, since every developer needs to have their own config file.

Changes to the developer's web.config (apart from connection string) are copied manually to the svn-based config. I don't know of a tool that would merge to web.configs.

devio
This is basically what we do today, only we use the web.config in source control.. try and avoid environmental differences and have an ugly system of whenever theres a environmental setting, we keep each devs setting there commented out.. so that the first thing you do from a web.config change is to go and find your specific settings and uncomment them.. which really seems no different than your scenario, only its slightly inverse..This is problematic, it potentially requires increasingly more changes as the app grows and is a serious drag for the devs.
meandmycode
A: 

We don't store environment settings in the web.config. They're stored in a database.

This enables us to do xcopy deploys, and to store the web.config file in our version control system.

Access to the database is via one registry key.

Bravax
I think this would impact apps quite a bit, for example- we might want to configure our service locator slightly different per machine.. all of which would require us to make our app aware of needing to go and find settings from a database.. vs config via its configuration files, plus this would be problematic in that it doesn't well solve our problem of a base 'app' config, and overriden 'machine' config settings.
meandmycode
Sure, I quite understand. For us we have different databases for each developer, then one common one each for dev, test and live.As everything has been designed that way from the start it's fine, but it would take quite a bit of work to convert to that.
Bravax
+3  A: 

One approach that I sometimes use is to break out environment-specific section into separate config file, that are usually excluded from deployment (except for the first time or if their structure change):

Example for connection strings: In web.config:

<connectionStrings configSource="connections.config"></connectionStrings>

The connections.config file (that is typically not included in the deployment; so it is unchanged):

<?xml version="1.0"?>
<connectionStrings>
    <add name="connectionName" connectionString="[connection string goes here]"/>
</connectionStrings>

Like that we have created an "incapsulation" of the information, and can easily deal with issues like source control, deployment and such of that information.

Fredrik Mörk
This is certainly a better way than what we currently do, but still has some problems, for example- with our service locator the base config might register 100 services.. and each dev machine might want to override perhaps only 5 of these.. having to delegate an entire config section out would mean each dev has a copy of that 100 services registered with their specific changes.. and if the base config changes (to add more services), the dev needs to be aware.. I'm looking for something that removes as many 'GAH!' moments as possible, thats why config inheritance would be perfect...*cont*
meandmycode
.. also, the transformations concept should work just as well if it is rich enough to let us do xpath like filters to override very specific parts if needed.. the slight complexity of writing these transform attributed per-machine config parts would be absoletely fine with us.
meandmycode
A: 

The configuration of an application can be split into two categories.

  1. Application specific
  2. Deployment specific

Application specific configuration includes things like caching implementation, business rules implementation, and will apply to every deployment of the application. This should go into the web.config file that is part of the application directory structure and is checked into source control.

Deployment specific configuration includes things like connection strings, timeout periods, etc, and may differ from one deployment to another. This should be entered as part of the configuration of the IIS instance that is involved in the deployment and preserved by whatever backup strategy is in place for the machine in question.

As far as I can tell, this is exactly what the hierarchical nature of the web.config files was designed to handle.

The advantages of such an arrangement are...

  1. No need to worry about which developer's version of the settings end up in source control, because none of them do.
  2. Every deployment uses the same binary, so deployment issues are more likely to involve the deployment configuration.
  3. Subsequent deployments should need no deployment specific configuration changes, because they are already in place.
belugabob
Thanks belugabob, and yes I agree that configuration data contains constant app parts, and environmental parts.. the inheritance model of web.config files was more designed so grouped applications (apps on the server, and apps in a website) can share environmental settings, rather than this being a debugging feature.As I say, I'd love to harness the web.config inheritance model but.. how?I have two places where I can make changes: the entire iis machine.. (not good, each dev machine may be working on multiple projects, iis isn't dedicated to just the one).. of the web.config .. *cont*
meandmycode
.. and I can't change the web.config as thats under source control.. the closest I can think of to doing this is to have a directory (or app directory) configured under the site, stick a web.config in there to override settings- and also stick something like URL rewriting in there to route the requests BACK to the root whilst staying in context of the current app.. not even sure if thats possible..
meandmycode
There shouldn't be a problem with putting the setting on the iis machine, as you can avoid clashes across applications by applying 'namespaces' to the properties. Call them something like 'AppName.properties.settings.connectionString', and they can all co-exist happily.
belugabob
Not always possible, remember this isn't JUST about connection strings or app settings.. in my 3rd edit I've noted how this is possible today with an xslt transform- it works well as long as you can stand writing a bit of xslt.. this is better than config inheritance also because you can target for example- just changing a single attribute value etc, rather than having to override an entire section.
meandmycode
A: 

What you're describing sounds a lot like using a Machine.config file to store connection strings. I haven't seen this mentioned yet, so have you tried it? It looks like you can use a global Web.config that sits beside your Machine.config as well.

A few links:

ASP.NET Configuration File Hierarchy and Inheritance

Difference between Web.config and Machine.config

Ryan Versaw
Its good but its machine wide settings, and given we have multiple solutions it wouldn't really work.
meandmycode
+1  A: 

Whilst there are certainly plenty of solutions, none of them really give you a huge amount of control over the generated configuration, one solution that I noted in my edit where you get a huge amount of control but with the overhead of having to write an xslt file, was using an xslt build task to use the template web.config/app.config from source control (which I personally name web.base.config/app.base.config), and use an xslt file to transform the version controlled config file at build time, and generate a web.config/app.config.

Here is an example of an xslt build task (although you may want to write it to your own coding standards), and an example of a mundane xslt transform that will change the value of a connection string and copy everything else in the config:

<?xml version="1.0" encoding="utf-8"?>  
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">  
  <xsl:output method="xml" indent="yes"/>  

  <!-- Copy all. -->  
  <xsl:template match="@* | node()">  
      <xsl:copy>  
          <xsl:apply-templates select="@* | node()"/>  
      </xsl:copy>  
  </xsl:template>  

  <!-- Swap connection string. -->
  <xsl:template match="/configuration/connectionStrings/add[@name='my_connection_string_name']">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:attribute name="connectionString">my replacement connection string value</xsl:attribute>
    </xsl:copy>  
  </xsl:template>

</xsl:stylesheet>

This is a mediocre example, but you can imagine you can completely transform entire sections where you previously would struggle with an inheritance based scenario.

meandmycode
This does work, but it has one drawback. You are unable to cleanly version web.config. This means that you miss whatever magic VS does to that file. WCF configuration comes to mind, where VS magically adds a ton of default config information to app/web config. Ideally, this transform would occur at run-time, not compile-time.
Robert Jeppesen
+1  A: 

VS 2010 will provide you with a lot of control to manage web.config files for various configurations... Please check out http://tinyurl.com/webconfigtransform

Thanks, Vishal

Vishal R. Joshi
Just a pity they didn't throw in an app.config transformation tool as well...
Darren Oster