86

I have two applications one a console application and the other an ASP.NET app. They both need to know the same appSettings and connectionStrings. So ideally I would like to use the configSource property of app.config/web.config files to point that to a central location. For example

<connectionStrings configSource="D:\connectionStrings.config"/>
<appSettings configSource="D:\appSettings.config"/>

That however fails with an error:

The configSource attribute is invalid.: The configSource 'D:\appSettings.config' is invalid. It must refer to a file in the same directory or in a subdirectory as the configuration file.

Is there anyway to still use the configuration managers appSettings/connectionStrings and get the values from an external location?
I'm happy with having to add code to do it, but I don't want to have to replace the entire configuration manager system.

Robert MacLean
  • 38,975
  • 25
  • 98
  • 152

11 Answers11

107

Another solution is simply to add the configuration file in all your projects as a link instead of actually copying the file to your projects. Then set the "Build Action" of the file to "Content" and "Copy to Output Directory" to "Copy if newer" and when you compile the project you will have the file in the output directory.

To add the file as a link in the "Add Existing Item" dialog box, there is an Add button with a dropdown. Choose "Add as link" from the dropdown on the Add button to complete the process.

Community
  • 1
  • 1
  • nice - much easier for people to understand than my way – Robert MacLean Mar 30 '09 at 07:24
  • 10
    hello, I like this answer and have tried to apply it to my own project, and everything seems to work fine when I "publish" my app (db.config is copied to the webroot as you said), but not when debugging through VS & Cassini. Instead I get an "Unable to open configSource file 'db.config'" exception. Is there something I'm missing in order to be able to do this? Thanks! – Funka Jun 16 '10 at 21:08
  • 17
    Of course only right after I decide to break down and post a comment asking for help do I then figure it out right afterward. I noticed my db.config is _also_ copied to the /bin/ folder, so I've updated my web.config to prepend this path in its `configSource` and all seems well. Thanks again! – Funka Jun 16 '10 at 21:37
  • 1
    @Funka - Check if you are having the problem because the "Build Action" property of your db.config is set to "None" instead of "Content" like the default web.config. I believe the settings should be "Build Action" = "Content" and "Copy to Output Directory" = "Do not copy." – bopapa_1979 Apr 19 '13 at 20:17
  • 1
    This doesn't seem to be working when debugging in VS 2013. I've tried Erics solution and this also didn't work. – Chris Nevill Jul 30 '14 at 10:13
35

Under appSettings you can use file= instead of configSource=

  • 1
    Excellent find for me! Thanks!! With this, I can override select keys in AppSettings as shown at http://weblogs.asp.net/pwilson/archive/2003/04/09/5261.aspx – Saurabh Kumar Feb 18 '12 at 16:59
15

It seems that's that is the way it is. configSource must be in the same folder or deeper.

You could, although I'm not sure you should, use an NTFS hardlink. [mad grin]

Iain M Norman
  • 2,075
  • 15
  • 30
10

Visual Studio 2015

If you are having this issue with Web.Config the accepted answer is correct but just to expand since this had me giving myself the face-palm:

When you add a .config file to your project using 'Add As Link' and then set the link's Copy property to 'Copy If Newer' or 'Copy Always', then the physical file will be copied to the /bin folder.

Thus, when you have a config section defined in Web.Config like this:

 <section name="mySpecialConfig" type="System.Configuration.AppSettingsSection" requirePermission="false" />

then you must define the related config element like this:

  <mySpecialConfig configSource="bin\MySpecialConfig.config">
  </mySpecialConfig>

such that the configSource points to the physical bin\MySpecialConfig.config file not to the link Also, note that the path is a relative physical path.

That may seem ridiculously obvious but if you haven't done this before the physical file is not yet in the \bin folder so it may not click right away.

Serexx
  • 1,232
  • 1
  • 15
  • 32
8

You can load configuration from an arbitrary location, but it won't be available via the static properties of ConfigurationManager:

Configuration myConfig = ConfigurationManager.OpenExeConfiguration(path)

(There is an overload that allows multuple files to be specified, to support default/user-roaming/user-local hierarchy.)

Losing the static properties means all the code needs to be aware of the different configuration.

Richard
  • 106,783
  • 21
  • 203
  • 265
  • This requires that the entire config file be loaded. I only need the appSettings & connectionStrings to be the same, the rest of the file is different for each app so it doesn't solve the issue. – Robert MacLean Feb 20 '09 at 11:19
  • The whole config is loaded by the normal (static) properties anyway so this makes no real difference. – Richard Feb 20 '09 at 11:33
  • Also, you could just use your own XML format and add its name to the applications' configuration files and read it directly. – Richard Feb 20 '09 at 12:02
5

In the case of connection strings, it is indeed possible to point to a shared file. If the shared file is on a network UNC, it requires administrative privileges on the machine where the app will be hosted.

Solution: In your web.config, use configSource to point to a local config file. Due to .Net restrictions, this must be at or below the level of the root config file. I just point to a file in the app folder itself:

<connectionStrings configSource="ConnectionStrings.config" />

In a shared location that is accessible by the application pool user, add the config file containing shared connection strings. This file must not contain any xml other than the connectionStrings section itself. The shared file, ConnectionStrings.config, looks like this:

<connectionStrings>
    <clear/>
    <add name="connString1" connectionString="connString1 info goes here"/>
    <add name="connString2" connectionString="connString2 info goes here"/>
</connectionStrings>  

Now the trick. Create a Windows symbolic link in your app folder pointing to the external, shared config file. You will need admin privileges to do this:

mklink ConnectionStrings.config \\someServer\someShare\someFolder\ConnectionStrings.config

We have just outsmarted .Net. The Configuration system will use the configSource setting to find connection strings in a local file called ConnectionStrings.config. The symbolic link looks like a file to .Net, and the symbolic link resolves to the shared configuration file.

Caveats: Changes to the shared file do not automatically trigger an app restart in .Net. In the case of IIS, the web site or app pool will need to be restarted manually.

Due to the need for administrative privileges to create the symbolic link, this approach may not work for everybody. There are two related alternatives that may work if the shared file is on the same logical drive - hard links and junctions. See this discussion and this discussion for more information.

Community
  • 1
  • 1
Scott
  • 153
  • 4
  • 7
3

You can place both settings in the machine.config and then they are available for all you applications on the server.

freggel
  • 552
  • 2
  • 6
  • 13
  • It's an option but I don't want (need) the settings available to other applications on the machine. Worry is the connection strings, they have pretty generic names which may conflict with other applications. – Robert MacLean Feb 20 '09 at 11:14
2

I had quite a struggle with this issue, but I found a good solution for it here: test run with external config

(You can direct the test run to copy files and directories into the test run directory by editing the .testrunconfig file.)

Although why the unit test type project can get config settings from its own app.config, but not be able to load referenced config files like a normal app.config is kind of baffling to me. I'd call it a bug because you would expect a test project app.config to behave the same way that the application's app.config behaves, but it doesn't.

Community
  • 1
  • 1
marcel_g
  • 1,980
  • 2
  • 17
  • 19
2

The solution I found worked best was to put the "shared" config files in a central files and then use a pre-build event in Visual Studio to copy them to a relative folder of each project which needed it.

Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
1

You can use the file attribute rather than configSource

There's a good article here on it

This allows you to specify a relative path like so

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings file="..\..\..\..\..\..\ExternalFile.config"></appSettings>
</configuration>

The path is relative to the output directory.

Then in ExternalFile.config you just add the appSettings section

<appSettings>
    <add key="SomeKey" value="alue"/>
</appSettings>
alexs
  • 1,507
  • 18
  • 17
0

If you have multiple projects that need to share same connection string, put the connection string config file you want to share between different projects in the class library project. And then from the project that needs to use the connection string, do this:

  1. If it's a Console project or Unit Test project:

In Console or Unit Test projects, do this in app.config: <connectionStrings configSource="connectionString.config"/>

That's it.

Why there is no link needed at all? Answer: when you build the project, connectionString.config gets copied to the output folder. The other projects' app.config files also get copied to the output folder. So when you run the start up project, the app.config of the start up project IS in the same folder as connectionString.config. That's why there's no link needed.

  1. If it's a Web project:

In web config do this: <connectionStrings configSource="bin\connectionString.config"/>

Note that if you set connectionString.config file to Copy If Newer, sometimes Visual Studio 2019 doesn't detect the change. So you can just set it to Copy Always.

bobt
  • 324
  • 3
  • 3