Reputation: 1769
Is it possible to change the connection string within the app.config file and have Entity Framework start using the new values?
I have a multi-threaded app with one thread acting as the dispatcher. This thread has the ability to receive a message telling it to change all or part of the connection string data (such as a password change). It then updates the config file to include the new connection information and clears any pooled database connections. This part is all working correctly.
The problem is, when the dispatcher launches a new thread and this thread creates a new database context the database connection is created with the old connection string values. It appears Entity Framework is keeping a cached copy of this information somewhere. If I completely shutdown and restart the app it works correctly because it, obviously, has to read the new values from the config file.
I have seen other proposed solutions involving keeping the connection string as a variable and passing it to the context constructor. But since the dispatcher thread has no internal knowledge of the "job" threads it creates (some may not even require database access) this won't really work for me. At least not without a lot of code changes and special requirements of my job interface.
This is the code I'm using to update the file. As I said, this part is working. Is there something else I need to do to tell Entity Framework about the change?
// Create new connection string
SqlConnectionStringBuilder connectionBuilder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings[CONNECTION_STRING_NAME].ConnectionString);
connectionBuilder.DataSource = server;
connectionBuilder.InitialCatalog = database;
connectionBuilder.UserID = user;
connectionBuilder.Password = password;
// Update connection string within config file
Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
ConnectionStringsSection section = (ConnectionStringsSection)config.GetSection("connectionStrings");
section.ConnectionStrings[CONNECTION_STRING_NAME].ConnectionString = connectionBuilder.ToString();
// Save changes
ConfigurationManager.RefreshSection("connectionStrings");
config.Save();
Upvotes: 2
Views: 1116
Reputation: 205629
The documentation for ConfigurationManager.RefreshSection
method does say (emphasis is mine):
Refreshes the named section so the next time that it is retrieved it will be re-read from disk.
The problem is that EF6 caches the ConfigurationManager.ConnectionStrings
in an internal class static property, so it never gets refreshed.
Unfortunately there is no "official" way to refresh it. Following is a brute force hack using reflection, so use it on your own risk:
static readonly Type EF6AppConfigType = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.AppConfig");
static readonly PropertyInfo EF6DefaultAppConfig = EF6AppConfigType.GetProperty("DefaultInstance", BindingFlags.Public | BindingFlags.Static);
static readonly FieldInfo EF6ConnectionStrings = EF6AppConfigType.GetField("_connectionStrings", BindingFlags.NonPublic | BindingFlags.Instance);
static void RefreshEF6ConnectionStrings()
{
EF6ConnectionStrings.SetValue(
EF6DefaultAppConfig.GetValue(null),
ConfigurationManager.ConnectionStrings
);
}
Just call it after saving the changes:
config.Save();
RefreshEF6ConnectionStrings();
Upvotes: 3