So we have a build process that handles different development web.configs across different environments. We use the ConfigSource attribute and have Team City pick the appropriate file.
That's great, but what do I do when the developers have slightly different environments?
CI, can't help, because everyones getting it straight out of SVN (i.e. CI obviously doesn't build to each developers local machine).
I'll use the ConnectionStrings config section as an example:
<connectionStrings configSource=".\Config\ConnectionStrings.config">
</connectionStrings>
And we have:
configs\ConnectionStrings.config (the generic one)
But I might need to use:
configs\ConnectionStrings.dev1.config
configs\ConnectionStrings.dev2.config
configs\ConnectionStrings.dev3.config
depending on which developer is using the code at the moment.
Any ideas?
Have you tried looking into web.config transformations? They might be able to provide the functionality that you seek while still keeping everything in version control or needing any code changes. Plus it will work for more things than just connection strings, but also directories, etc.
One technique we've used in the past (I recall Ayende mentioning it on a web cast) is that each connection string is named with the developers machine name e.g.
<connectionStrings>
<add name="BobsPC" connectionString=""/>
<add name="JonsPC" connectionString=""/>
</connectionStrings>
When in debug we then look for a connection string name of the "current" machine name.
This saves having multiple connection string files. Instead we have one file with multiple connection strings.
We have a separate connection file just like you mentioned with the current machine name in it.
In the build event for the projects that need a connection string we've added a pre built event that deletes the connection.config file from the current project and in the post build event we copy connections.machine.config to connections.config in the current project folder.
In our web.config we have a so .NET will look in a separate file for the connection string information.
Web.config transformations can only be used when you actually deploy a project. The 'default' web.config will always be used on your local development machine so this is not an option for development environments.
You can extend this mechanism also to app settings and other config files by placing the machine specif ones in the solution folder and just copying them on build.
Related
Most of my previous web applications have built using the pyramid (python) framework. With pyramid, it is possible to run the application in either development or production mode. This is achieved by providing the location of a production.ini or a development.ini settings file as one of the start up arguments to the application.
This file contains settings relating to logging levels, error reporting and database connections. The equivalent of these files in the .net world would appear to be web.config files. I assume i can create different execution environments, by simply creating a new web.config, renaming it to something appropriate, and restarting the application.
My question is, how can i get my app to target the correct *.config file (hypothetically call them production.config and development.config)?
You may want to look at MSDeploy. I use this for similar situations and it's helped me establish a single parameters file (of what is to be replaced, regardless of if it's XML, a filepath, text file, etc.) and multiple set parameter files [you can read about declareParam and setParam here.
Without knowing too much of your structure you are basically going to do something to the effect of this.
msdeploy -verb:sync -source:contentPath=c:\pathtosite\root -dest:package=c:\package.zip -declareParamFile=c:\packageparameters.xml"
Create an associated parameters file for each environment such as
development.xml
staging.xml
production.xml
(Here is a good explanation of parameter file setup)
then for your deploy you would have something (depending on the providers you want to use)
msdeploy -verb:sync -source:package=c:\package.zip -dest:contentPath=c:\inetpub\production -setParamFile=c:\<environment>.xml
The # of providers is pretty extensive. Content Path is just an easy example, but you can pull directly from IIS, to IIS, etc. Pretty robust.
There's no way that I know of to specify a different web.config file. Since .NET 4.0, however, you can use something called web.config transforms, which modify your base web.config on build. You can have a Web.Debug.Config and Web.Release.Config, which get applied depending on which build configuration you're using. Keep in mind these aren't normal web.config files, but rather transform files that modify the base web.config.
For more info and a walkthrough of the basic idea involved, see here on MSDN. The basic example given of a web.config transform file is this, which modifies a connection string to use a different connection string for the release build:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="MyDB" connectionString="ReleaseSQLServer"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>
This might sound a bit dumb.
I always had this impression that web.config should store all settings which could be subject to change post-build and setting.settings should have the one which may change pre-build.
but I have seen projects which had like connection string in setting.settings. Connection Strings should always been in web.config, shouldn't it?
I am interested in a design perspective answer.
Just a bit of background:
My current scenario is that I am developing a web application with all the three tiers abstracted in three separate visual studio projects thus every tier has its own .settings and .config file.
Web.config is mostly meant for configuration, and it also stores the default values of your settings.
Settings.settings is just a convenience file for Visual Studio to provide a UI for editing your settings.
The .config comes in two different flavors: App.config for Windows applications, which will be named YourApplication.exe.config, and the Web.config for web applications. They share the same schema, syntax, and options.
You may notice that if you add a setting to Settings.settings, it gets added to the .config as well.
The .config must be deployed with apps, but Settings.settings doesn't need to.
Setting.settings is a class, it is not used to store the connection string as such, it is used to expose a specific connection string from web/app.config as a property on a class. VS does also tend to hard code a default value if the particular connnection string cannot be found.
I recently worked on an app in a very interesting environment. There was 6 or 7 parallel levels for this application and only the 1st 2 levels were able to be touched by developers. As part of the company policy all builds were done as Tivoli packages, and very complex to setup.
The final kicker was that no code changes are allowed past the 1st level or "Dev" servers so web.config contained multiple encrypted sections of environment variables. The application is built to sense what environment its on by path and variables set in IIS.
This is a beast to maintain so what is a simple or better architecture for this type of problem?
Hmm, (disclaimer: I'll talk about something I've written)
Your subject seems slightly different from the post, but I think I have an idea of what you mean. The tool I'm writing, dashy, lets you handle a single codebase, and lets you configure it for various enviroments. It doesn't, however, place security restrictions on these enviroments over the other. But, depending on your source control, and general system, it may be of interest. You should get a reasonable idea of the way it works from the picture on the homepage. Perhaps it's of interest, perhaps not, but it's what we use to manage deployment to different environments. It's a work in progress ("beta") at the moment, but the current version is suitable for testing.
The latest version of ASP.NET now supports web config transformations, allowing you to change specific settings within your project for deployment, testing or staging. Here's a great intro by Tom Hundley.
Have you tried using OpenExeConfiguration of the ConfigurationManager and explicitly load the proper configurations for the appropriate environments instead of just using the default web.config?
For more, check out OpenExeConfiguration on MSDN
You could include all configurations for all environments in the web config and prefix their keys with the machine name of the appropriate environment. Then, using Server.MachineName (or some other way to identify the server that the app is running on) you can access the right configuration.
<appSettings>
<add key="DEVMACHINENAME_baseURL" value="http://dev.foo.com" />
<add key="QAMACHINENAME_baseURL" value="http://qa.foo.com" />
</appSettings>
No one would have to go in and modify anything in the web.config since the application can look up information for itself.
Is it possible to configure an IIS site to read ASP.Net settings from a site OTHER than web.config?
We'd like to have three config files in our codebase -- web-dev.config, web-test.config, and web-prod.config. Each IIS instance would be configured to read from their specific file. This way we have version control them all next to each other (and one-click deploy the entire site) but know that each IIS instance will read the settings specific to itself.
I've found in IIS where it shows where the web.config is, but I can't see how to change the location.
I use the configSource property to specify an external config file for sections that need different values for dev and production.
<connectionStrings configSource="Config\ConnDev.config"/>
Then you only have to change one setting (manually or with a tool) to switch from Dev to Production configs.
The best solution right now is to use different configs for development and production. This however will change with .net 4 and VS 2010 which they have added Web.Debug.config, Web.Release.config, Web.Staging.config and Web.Testing.config which will then publish the config you need in relation to the environment.
At my company we just have our deployment tool set to copy the appropriate file to web.config depending on what kind of deployment we're doing.
I believe it has to be named web.config.
You are facing a common problem.
One solution that I have used that worked really well in a large organization was to set environment variables on the web servers. Such as DEV, QA, UAT, PROD. Then, in code, you can query the environment variable to see which machine you are on, and then choose the values of appSettings accordingly. For example, you could have a database connection string named DEVconnection, and another named UATconnection. If your code determines from the environment variable that you are on UAT, then it would use UATconnection.
This does assume that you have the ability to set environment variables on the web server. In this instance, the admins running the servers were the ones who suggested this solution.
What was sweet about this was that there was ever only one version of web.config.
I do not think we can make web.config declaratively so that we can specify different config file. One thing you can do you can split your configuration file and set for different environments.
Please go through this article
http://jetmathew.wordpress.com/2011/02/07/split-web-config-for-different-environment/
cheers
How can one specify the connection string in a config file of a class library and later modify this when used in a ASP.NET Web Application?
The Class library is a data access layer that has a Dataset connecting to a database based on a connection string specified in a config file (Settings.settings/app.config).
This class library is used in a web application where user inputs data and is written to the database using the DAL classes & methods exposed in the class library.
Now, I want to migrate this application from development environment to testing environment and later to production. The problem I'm facing is that after migrating to testing, the app in testing still connects to development database. I've changed the connection string mentioned in <class library>.dll.config file but this seems to have no impact.
Can someone explain the right way to achieve this? Thanks in advance for any help. Cheers.
With the .config files the name has to match the main executing assembly. For example I had a situation like yours, I needed a class library to have its settings in a .dll.config file. While it was able to reference it the actual application would not be able to read the config file because it was expecting .exe.config. Renaming the .dll.config to .exe.config fixed the problem.
In your case migrating your connection strings from .dll.config to web.config should fix your problem!
Good luck!
Joshua is partly right ... For posterity I would like to add a bit more to this answer as I have delt with the same problems on several occasions. First, one must consider their architecture. There are several issues you can run into with .config files in ASP.NET based on deployments.
Considering the architectural ramifications:
Single tier (one server):
A simple web application may be able to leverage a reference to the sites Web.config file and resolve your issues. This would be a fine solution for a single tier application. In the case of a windows application leveraged as a .exe file, the App.config will work too.
Multi-tier (more than one server):
Here is where things became a bit hairy for me the first time I was working with .config files across boundries. Remember the hierarchy of the config structure and keep this in mind (MSDN Article on .Config structure) - there is a machine.config at the root in the appropriate ASP.NET folder. These reside at each physical server. These are overridden by the site Web.config (or App.config) which are in turn overridden by subfolder .config files. If you have more than one .config file you may want to use one of the methods to pass the file path for the specific .config you want to use. More importantly, these files each may have connection information. ASP.NET's machine.config holds some for the framework ... so you should at least be senstive to the fact this is an "inheritance" chain. Second, any changes to the Web.config file once deployed will tell the application to restart. This will result in loss of state (bad if you have active users on the site). The way around this is to keep a separate .config file (e.g. connections.config) and put a reference to that file in the Web.config. This will allow you to change the connection information (e.g. password) without having to restart the application. Here is a link to more info: MSDN: Working with Configuration Files. This article lays out all the details you need to be aware of in a normal server / IIS deployed application. Keep in mind that the .config files are mainly intended for applications, not libraries. If you have several tiers, chances are you are using some communicaiton / messaging layer (e.g. WCF). This will have / allow its own Web.config. You can keep connection strings there (and encrypt them if needed), but better yet, put them in a second file referenced by the Web.config for manageability. One final point, if you are ever going to consider the cloud, .config files are wrapped for application deployments which in effect removes all of the benefits they offer in terms of "not having restart or redeploy". Azure deployments will want to consider this article to save themselves from nightmares of maintenance: Bill Lodin blog - Configuration files in Azul / Cloud. One other point on this article – great example on how to programmatically select configuration depending on deployment! Be sure to check that out if you want to add flexibility to deploy in or out of the cloud .
I hope these points saves all of you time and headaches. I know I lost a couple days of programming time dealing with these issues ... and it was hard to find all the reasons in one place why may app was not "implementing" its connection object. Hopefully this will save you all from the same fate I had.