9

I'm not sure if this is the correct medium for this question, so if it's not please inform me and I will correct.

As an example to illustrate my point, let's say I have 30 .NET applications that are published to 2-3 different web servers. Now, these applications are Intranet based, so I have a C# library that I reference in each of those applications. This library is comprised of methods that I use in each application to find out employee information if necessary. Now, the library has one connection string, but then I have to also reference that same connection string in all of the 30 applications... so if the database changes that the library is referencing, then I have to remember all 30 applications and change each of them individually.

Is there a way to put the connection string in some sort of file (text file, or something), and have each web.config in each of the 30 applications reference that specific file, so if the connection string needs to be changed, I can just change it in the file and then all 30 applications are still okay, or is there not something like that?

UPDATE

Okay, I now know how to reference a text file for connection string purposes.. but, it seems as though I only can do one of two options... either reference my primary connection string and library connection string individually within the web.config like so:

OPTION ONE

<connectionStrings>
  <add name="PrimaryCS" // more data />
  <add name="LibraryCS" // more data />
</connectionStrings>

This option would require me to change the LibraryCS connection string in each of the 30 applications if it were ever to be changed (NOT WHAT I WANT)

OPTION TWO

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

This option forces me to put both connection strings in the MyConfig.config file and not just the LibraryCS file.. so this would result in me having to change the LibraryCS connection string in every MyConfig.config file for each of the 30 applications (AGAIN, NOT WHAT I WANT).

WHAT I'M LOOKING FOR

I am looking for a mixture of the two options, but it seems this can't be done, so I'm hoping someone on this medium knows a work-around

<connectionStrings configSource="MyConfig.config">
  <add name="PrimaryCS" // more data />
</connectionStrings>

I want the MyConfig.config file to only hold the LibraryCS connection string and then have the main PrimaryCS connection string be separate.. so that if the LibraryCS connection string were ever needed to be changed, then I only have to do it in one place.

Grizzly
  • 5,873
  • 8
  • 56
  • 109
  • If the application are on the same machine, you could read it from a file. It is a string only and it is not necessary that in resides in web.config. You only have to restart the web application after editing this file. Changing web.config would cause a restart automatically by IIS. – H.G. Sandhagen Nov 30 '18 at 20:14
  • 1
    These applications are published to 2-3 different web servers, so what about creating the same file on each different machine? – Grizzly Nov 30 '18 at 20:16
  • Then you need one file per server or a file share. – H.G. Sandhagen Nov 30 '18 at 20:17
  • 1
    Make a file. Add it to the project references. Set its build action to "copy to compilation directory". https://andrewlock.net/including-linked-files-from-outside-the-project-directory-in-asp-net-core/ It is not that usual to put stuff like this into the programm direectory anymore. But it is a option at least. – Christopher Nov 30 '18 at 20:18
  • Understood. Where can I find a tutorial or walk-through on how to reference a connection string from a specific file? – Grizzly Nov 30 '18 at 20:19
  • @Christopher thank you for the link. Is there anything specific I should know (like what type of file I need .json, etc)? Then how do I reference such file in my web.config? – Grizzly Nov 30 '18 at 20:28
  • @M12Bennett You should pick a format the server will not hand out. An old trick from my PHP days was to make a small php script file that declared soem variable. Even if someone would manage to guess the filename, there was no output oders in it. He would jsut see nothing. – Christopher Nov 30 '18 at 20:32
  • How do I find out about such formats? For now, I just want to try and see if it works with one application. – Grizzly Nov 30 '18 at 20:33
  • Are all the applications on the same server? Are the applications grouped on several servers or ist each application on a server on its own? Are you using IIS for hosting? – Georgi Georgiev Dec 06 '18 at 06:41
  • If you are concerned about server IP, use a DNS name instead. If you are concerned about username and password, run your applications under a domain user and use Windows authentication to connect to db server. – Reza Aghaei Dec 09 '18 at 16:01
  • Another option is handling the situation using a deployment scenario, for example by sharing the config file as link in VS or by writing a pre/post deployment script to do that for you. – Reza Aghaei Dec 09 '18 at 16:03

5 Answers5

6

Microsoft has an amazing documentation about it. Hopefully that helps.

To store connection strings in an external configuration file, create a separate file that contains only the connectionStrings section. Do not include any additional elements, sections, or attributes. This example shows the syntax for an external configuration file.

<connectionStrings>  
  <add name="Name"   
   providerName="System.Data.ProviderName"   
   connectionString="Valid Connection String;" />  
</connectionStrings>

In the main application configuration file, you use the configSource attribute to specify the fully qualified name and location of the external file. This example refers to an external configuration file named connections.config.

<?xml version='1.0' encoding='utf-8'?>  
<configuration>  
    <connectionStrings configSource="connections.config"/>  
</configuration>

Source : https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-strings-and-configuration-files

Ayberk
  • 536
  • 2
  • 12
  • I have done this.. but my goal is to only use one connection string in the config.file.. and then have a separate connection string in the web.config file of the application. – Grizzly Dec 04 '18 at 13:28
1

One solution I came up with is to create a shared connection string file and reference it in the web.config of multiple web application projects.

So in my web configs I have this:

<connectionStrings configSource="configs\connectionStrings.local.config">

This file just contains the 'connectionStrings' portion of the config.

And I copy in the connectionStrings.local.config file into the configs folder on build of the project from a common solution folder (the config file is added to the solution as a solution item.

Other alternatives would be to use an environment variable on the servers to store the connection string or as people are mentioning a common file (just read the file as you would any text file).

MikeS
  • 1,734
  • 1
  • 9
  • 13
  • Thank you. Is there any chance to show some pictures of how you accomplished this? Easier for me to follow along. Be sure to comment out your connection string properties if you do. – Grizzly Nov 30 '18 at 20:31
1

Have you considered using Apache Zookeeper? Your use case seems to fit its' definition:

ZooKeeper is a centralized service for maintaining configuration information...

You can start a ZooKeeper instance somewhere and keep in it your configuration settings. Your settings will be organized in a structure similar to a file system structure. It may look like this (using zkCli.sh that comes with ZooKeeper to create the configuration, as an example):

create /common-settings
create /common-settings/connectionString 1.1.1.1:123
...
create /app-1-settings
create /app-1-settings/app-specific-setting myArbitrarySetting 

You can then set up your apps to include a ZooKeeper client, so that they are able to read the configuration you stored. For .NET, I have found https://github.com/shayhatsor/zookeeper, which seems to meticulously mimic the Java client: https://github.com/ewhauser/zookeeper.
I haven't used it extensively, but I got the following working (note C# 7.1+, due to async Main()):

using System;
using System.Text;
using System.Threading.Tasks;
using org.apache.zookeeper; // NuGet: ZooKeeperNetEx

namespace Example 
{
    // Watcher will notify us of events we get from ZooKeeper
    class MyWatcher : Watcher 
    {
        public override async Task process(WatchedEvent @event)
        {
            Console.WriteLine($"Process event: {@event}");
        }
    }   

    class Program 
    {
        async static Task Main()
        {
            // Create a new ZK client.
            var zookeeper = new ZooKeeper("<zookeeper-url>", sessionTimeout: 3000, new MyWatcher());
            // Use it to request a config setting.
            var connectionData = await zookeeper.getDataAsync("/common-settings/connectionString");
            // Convert the received data from bytes to string.
            var connectionString = Encoding.UTF8.GetString(connectionData.Data);

            Console.WriteLine($"Got connectionString '{connectionString}'."); // Got connectionString '1.1.1.1:123'
            Console.Read();
        }
    }
}

I'm sure that with little effort you can adapt it to your specific needs.
To get started with ZooKeeper, you could look into their Getting Started.
There's lots of info on the Internet too, of course.

Seva
  • 1,631
  • 2
  • 18
  • 23
0

A nifty solution is adding config file shortcuts in other projects so you only update one file: enter image description here

It's similar to Sharing Assembly Files (demo'd in answer #2: https://stackoverflow.com/a/15319582/495455)

If you need more environments use Transforms:

enter image description here

I know this is a short answer, I like the really simple solutions. Let me know if you have any questions.

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
  • This doesn't address the distribution problem, which seems to be the OPs core problem. – H H Dec 04 '18 at 06:17
  • @HenkHolterman why not? I thought it was a central config question. – Jeremy Thompson Dec 04 '18 at 07:11
  • 1
    Your answer with `machine.config` is good. But IMO you shouldn't use it in IDE and I'm wary of changing the main machine.config.It then affects every other .Net app and if your change is reused, which it will be, then people will be scratching their heads going WTF - potentially on PROD issues. – Jeremy Thompson Dec 04 '18 at 07:28
0

Don't know if this is what you are searching for, but when you overload the constructor of your ApplicationDbContext you can specify which connectionstring it should use:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base(GetConnectionStringName(), throwIfV1Schema: false)
    {
    }

    static string GetConnectionStringName()
    {
         // Your logic for the connectionstring, I use the Request.Url here.
         return HttpContext.Current.Request.Url.Authority.ToLower().Split(new char[] { ':' }).FirstOrDefault().Replace("www.", "");
    }
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
ikwillem
  • 1,044
  • 1
  • 12
  • 24