Dear reader of Juri's TechBlog,
I moved my blog to a new domain and a new hosting solution as well. I'm now blogging on juristr.com.

Best practices: Deploying webapps (contd.)

Some time ago I've written a post about best practices in deploying web applications by mentioning the different environments

  • Development environment
  • Testing environment
  • Production environment

Since the three different environments must be completely separated (no references between them to the DB or whatever), you have to have different connections strings in your web.config file (for each connection to the according development-/test- and production-DB).
In my last post I addressed this problem by suggesting as a possible solution to not let the web.config file being copied automatically when the web application is published.
So a possible solution is to do not automatically deploy your web.config file. When your application is first published to some environment you copy your web.config file manually and immediately update the connection string s.t. it points to the right environment. On all subsequent deployments, your web.config file won't be touched which avoids to run into troubles. The disadvantage: of course if you modify other parts on your web.config file beside the connection string, you have to manually copy it on the other web.config files on the different environments. But that shouldn't be a big deal.
To avoid that you web.config file is automatically copied when you click on "Publish...", you have to open the properties of the web.config file and set the properties "Build Action" to "None" and "Copy to Output Directory" to "Do not copy" (see figure).
Well this is not really the most elegant solution because it may still happen that you have to change or add some new entries to the web.config file during the development. In this case you have to remember to copy those changes manually to the web.config file when you again deploy your application. This may be error prone because you have to remember those changes.

So a better solution is to externalize the critical part of the web.config file. In this specific case we have to externalize the connection strings from the web.config but potentially there could be also other settings where it would make sense. The following piece shows this section, where [DATASOURCE_HERE] etc.. has to be replaced with the right values of course.

Original web.config file
<?xml version="1.0"?>
...
<connectionStrings>
  <add name="MasterOracle" connectionString="Data Source=[DATASOURCE_HERE];User ID=[USER_ID_HERE];Password=[PASSWORD_HERE]" providerName="System.Data.OracleClient" />
</connectionStrings>
...
What can be done now is to create a new file in the same folder as the original web.config file and give it a meaningful name, i.e. "DBConnectionStrings.config" or "ConnectionStrings.config" etc. What's important is to use the ".config" file extension since this prevents that the file can be browsed over the web. Then the part of the connection strings in the original web.config file can be extracted and placed into the newly created file:

DBConnectionStrings.config
<?xml version="1.0"?>
<connectionStrings>
  <add name="MasterOracle" connectionString="Data Source=[DATASOURCE_HERE];User ID=[USER_ID_HERE];Password=[PASSWORD_HERE]" providerName="System.Data.OracleClient" />
</connectionStrings>

The orginal web.config file has to be modified to point to the new external configuration file:

Modified web.config file
...
<connectionStrings configSource="DBConnectionStrings.config"/>
...
Now I think my strategy should be evident. You can now let your web.config file be copied on each publish as usual but you prevent the copying of the external DBConnectionString.config by setting the properties "Build Action" to "None" and "Copy to Output Directory" to "Do not copy" . So the first time you setup your different environments you copy your DBConnectionString.config to each of the different locations and apply the necessary corrections such that the connection string points to the correct DB.

This is much a cleaner and more elegant solution as you do the setup once and then you don't have to remember on each publish to eventually also copy the new changes of the web.config file manually to each of the deploy environment.

Posts you might also be interested in..

Credits: Hoctro | Jack Book

2 Comments:

Peter Gfader said...

We are using this approach for our connection strings as well. But we have to many different other settings between dev, staging and production...
So we still have 3 web.config files. But we need to deploy manual steps only if we change something in them.

What would you suggest if you have a lot of different settings?

E.g. Move all of these in separate file?
<setting name="DefaultFromAddress" serializeAs="String">
<value>X@X.com</value>
</setting>
<setting name="CloseDate" serializeAs="String">
<value>03/31/2009 23:59:00</value>
</setting>
<setting name="OpenDate" serializeAs="String">
<value>03/02/2009 23:59:00</value>
</setting>
<setting name="NRMABCCAddress" serializeAs="String">
<value>XX.XX@X.com.au</value>
</setting>
<setting name="GlobalExceptionMailTo" serializeAs="String">
<value>xxxxx@ssw.com.au</value>
</setting>
<setting name="ReportService"
serializeAs="String">
<value>http://XXXX:80/ReportServer/xx.asmx</value>
</setting>
<setting name="GlobalExceptionMailToAdditional" serializeAs="String">
<value>xxxxx@ssw.com.au</value>
</setting>

What I don't like about that, If I open web.config I want to see immediately whats going on, without opening other files.

Juri Strumpflohner said...

Hi,
I see your point. Well in principle I would say that if these settings are related to the environment where the application resides (e.g. dev, staging, production) then it would also make sense to have them in a different file.
But of course I completely agree with you when you say that if you open the web.config that you immediately want to see all of the configuration at a glance and not follow links to references setting files. Also having different configuration files is somewhat dangerous since it quickly may become nasty and difficult to maintain. The less config files you have the better it is.
The risk you have with the single, "manually managed" web.config is just that you may make changes locally, commit it to the repository, but then your team colleague publishes the app the next morning, without having recognized your changes..

From a "correctness" point of view I would say that having environment-related settings in different files would make sense, however I think it also very much depends on ones specific needs and also preferences.

Post a Comment