I have managed to confuse myself... not difficult, I know, and am looking for some guidance...
I have written a dll which I am now starting to use in my Winforms UI.
This is a follow on question to this:
Class Libray Connection String - How to change?
As told in that post, I have added the identical connection string settings from the app.config in the dll to my App.config in my UI.
In my UI, I have a text box where the user can enter the connection string and hit "Save", which runs the following code:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings["TPAPI.Properties.Settings.TruePotentialConnectionString"].ConnectionString = txtConnectionString.Text;
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");
Which seems to update the string in the file correctly.
But, and this is where the previous posting confuses me...
That setting only gets read when the software starts. Somehow I need to change the setting which Belogix has explained I should do like this:
var connectionString = "Data Source=MegaServer;Initial Catalog=MyDb; .. etc ..";
using (var db = new MyDataContext(connectionString))
{
// This will connect to MegaServer...
}
But, I am calling functions in my dll like this:
List<Page> pages = Database.getlistOfPagesToScan();
How do I tell that call to start using the newly saved connection string from the UI's App.config?
Can anyone shed any light?
Thanks
You should get the connection string from the settings in the dll. Your answer is actually in the question you post.
Use this:
var connectionString = config.ConnectionStrings.ConnectionStrings["TPAPI.Properties.Settings.TruePotentialConnectionString"].ConnectionString;
You can also use this:
string s = Properties.Settings.Default.ConnectionStr;
Console.WriteLine("Connection string from main app: " + s);
//
// When setting access modifier on Class library to `public`
//
s = ClassLibrary1.Properties.Settings.Default.ConnectionStr;
Console.WriteLine("Connection string from dll: " + s);
Assuming you are using ConfigurationManager to retrieve the application connection strings, try:
ConfigurationManager.RefreshSection("connectionStrings");
Related
I am trying to set connectionstring at runtime. What I need is set datasource at runtime and restart application. I found some approaches in google but the problem is app.config backs to default value after Application.Restart();
I tried to save connectionstring in settings.cs and app.config both but it doesn't work for me.
this is my code:
public void setConnectionString()
{
try
{
string str = string.Empty;
str = string.Format(#"Data Source={0}; Initial Catalog=CRM01_DB; UID= {1}; PWD={2}", Default.DataSource, Default.UID, Default.UPass);
this["CRM01_DBConnectionString"] = str;
Default.Save();
Thread.Sleep(100);
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings["CRM01_DBConnectionString"].ConnectionString = str;
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
Thread.Sleep(100);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
I didn't get any errors but when application starts the connectionstrig has default value
If you testing this code from VS it might not work (and probably won't).
When running from VS the actually program that is executed is <your_program>.vshost.exe and the corresponding .config file is named <your_program>.vshost.exe.config and you should check your changes there.
But..
VS keep the original .config and .vshost.exe.config synchronized so you don't see your changes.
To test if the code works try it from outside VS or uncheck Enabled the Visual Studio hosting process (Properties -> Debug) (keep in mind that it has implications)
When I try to access configuration section that is encrypted and cannot be decrypted properly (for example, someone just grabbed config file from another machine blindly) - Configuration class is throwing an exception. I want to catch that situation and rewrite the section completely in such case.
I've tried to remove and add back the section in question, but it seems that removal is ignored - second statement in 'catch' throws another exception about such section already exists:
try
{
// this getter might throw an exception - e.g. if encrypted on another machine
var connStrings = config.ConnectionStrings;
}
catch (ConfigurationException)
{
config.Sections.Remove("connectionStrings");
config.Sections.Add("connectionStrings", new ConnectionStringsSection());
}
It might be related to the fact I have connectionStrings section residing in separate file, i.e. my config file has something like <connectionStrings configSource="connections.config"/>, while actual encrypted content is in the connections.config file.
Is it possible to do what I need without falling back to direct XML manipulations, by using .NET Configuration classes only?
I'm pretty sure this will do what you want. In my case, I just included a bogus connectionString setting:
<connectionStrings>
<add connectionString="foo"/>
</connectionStrings>
I didn't include a "name" property, so trying to read ConnectionStrings will blow up, just like in your case:
try {
var x = ConfigurationManager.ConnectionStrings; //blows up
}
catch {
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.Sections.Remove("connectionStrings");
config.Save(); //Now save the changes
ConfigurationManager.RefreshSection("connectionStrings"); //and reload the section
var x = ConfigurationManager.ConnectionStrings; //can now read!
}
You still won't be able to do this:
config.Sections.Add("connectionStrings", new ConnectionStringsSection());
Because (at least on my machine), it's picking up connectionStrings from the Machine.config.
I suspect though that in your case that's fine. You are now at a point where if you want to, you can add your own connection strings and you don't really need to completely blow away the connection string section.
I first had this SQLite version: 1.0.77.0 (sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.77.0)
and everything was working fine.
After updating my System.Data.SQLite.dll to version 1.0.82.0 (sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.82.0) I now receive this:
Unable to open database. Connection string: 'datetimeformat=ISO8601;synchronous=Off;uri="file://C:/Users/username/Documents/data/test.db";version=3;journal mode=Truncate;default isolationlevel=ReadCommitted;pooling=True'; Error: 'System.InvalidOperationException: Invalid connection string: invalid URI
I've also tried file:/// instead of file:// without any luck.
Could anybody tell me what is wrong with my URI, why it doesn't work anymore in v1.0.82.0 but worked in v1.0.77.0?
http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
(1.0.82.0 == 3.7.14)
The best way to get correct connection string is to always use the SQLiteConnectionStringBuilder class to generate them.
SQLiteConnectionStringBuilder conn_builder = new SQLiteConnectionStringBuilder
{
DateTimeFormat = SQLiteDateFormats.ISO8601,
SyncMode = SynchronizationModes.Off,
Version = 3,
JournalMode = SQLiteJournalModeEnum.Truncate,
DefaultIsolationLevel = System.Data.IsolationLevel.ReadCommitted,
Pooling = true,
Uri = new Uri(#"c:\tmp\db.sqlite").AbsoluteUri
};
string conn_str = conn_builder.ConnectionString;
if Uri is not working, try setting DataSource instead (if you are using a local file).
A quick check shows that DataSource is evaluated before Uri in SQLiteConnection.cs and takes precedence over it, so if there is a bug in the Uri handling, using DataSource may help bypassing it.
According to the docs starting from the version 1.0.82.0 it was changed:
Add support for URI file names via the new FullUri connection string
property.
Example:
var connection = new SQLiteConnection("FullUri=file:mydb.sqlite?cache=shared");
following works for me, for following example you can't not use Data Source
FullUri=file::memory:?cache=shared
See these URI filename examples, but your URI (with three slashes) looks correct.
I think you should try to strip down your connection string to the basics and then add the options.
Take a look at this site for example SQLite connection string options.
http://www.connectionstrings.com/sqlite
The 3 /// is only valid when you are trying to escape out the spaces in the uri, I would also say that you should try moving the db out of the users folder to the root on c:\ in case the access permissions are not valid for it to access the DB and it also means a simpler connection string for you to try.
Good luck
I have a Class Library, which inside just has a DataSet (MySQL connector) and a Connector class.
I use this class in multiple projects to connect to the database, and I always had the password embedded in the connection string but now I need to be able to modify this string(for security purposes) so I can have the user connect using their own account.
How can I modify this connection string.
I have tried the following
Properties.Settings.Default.DataBaseConnectionString = "String";
But it seems that the connection string is readonly becase it doesn't appear to have a setter value.
I also tried the following with no luck
Properties.Settings.Default.DatabaseConnectionString.Insert(
Properties.Settings.Default.DatabaseConnectionConnectionString.Length - 1,
"Password=dbpassword;");
You can modify them like this:
Properties.Settings.Default["MyConnectionString"] = newCnnStr;
For a full solution that also saves the new value to the file, you need to do something like this:
private static void ModifyConnectionStrings()
{
// Change the value in the config file first
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
const string newCnnStr = "server=(local);database=MyDb;user id=user;password=secret";
config.ConnectionStrings.ConnectionStrings["MyProject.Properties.Settings.MyConnectionString"].ConnectionString = newCnnStr;
config.Save(ConfigurationSaveMode.Modified, true);
// Now edit the in-memory values to match
Properties.Settings.Default["MyConnectionString"] = newCnnStr;
}
If your dataset is in another assembly, you can still do this providing you make the settings for that assembly public. To do this:
Right-click the project in the solution explorer and click Properties
Click the Settings tab.
Change the Access Modifier dropdown to "Public", save, and close.
Then you can do this (assuming the other project is called "MyProject.DataLayer"):
private static void ModifyConnectionStrings()
{
// Change the value in the config file first
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
const string newCnnStr = "server=(local);database=MyDb;user id=user;password=secret";
config.ConnectionStrings.ConnectionStrings["MyProject.Properties.Settings.MyConnectionString"].ConnectionString = newCnnStr;
config.ConnectionStrings.ConnectionStrings["MyProject.DataLayer.Properties.Settings.MyConnectionString"].ConnectionString = newCnnStr;
config.Save(ConfigurationSaveMode.Modified, true);
// Now edit the in-memory values to match
Properties.Settings.Default["MyConnectionString"] = newCnnStr;
MyProject.DataLayer.Properties.Settings.Default["MyConnectionString"] = newCnnStr;
}
Don't you have the source code of that class?
Also, but a little more complicated method, would be to patch the assembly using Reflector with the Reflexil AddIn.
I think you're asking how you can change connectionstring properties at runtime depending on who is using the application. Hope this helps.
In the past I have done this by making my connection string contain parameters that I can provide using string.Format.
<connectionStrings>
<add name="SomeDB" connectionString="("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Jet OLEDB:Database Password={1}"" />
</connectionStrings>
string connectionString = string.Format(ConfigurationManager.ConnectionStrings["SomeDB"].ConnectionString, location, password);
It looks like you are loading the connection string from the config file, you should be able to change it from there. Once built it will be a file named the same as your compiled form plus .config. (For example application.exe.config)
Has anyone got this working in a web application?
No matter what I do it seems that my appSettings section (redirected from web.config using appSettings file=".\Site\site.config") does not get reloaded.
Am I doomed to the case of having to just restart the application? I was hoping this method would lead me to a more performant solution.
Update:
By 'reloading' I mean refreshing ConfigurationManager.AppSettings without having to completely restart my ASP.NET application and having to incur the usual startup latency.
Make sure you are passing the correct case sensitive value to RefreshSection, i.e.
ConfigurationManager.RefreshSection("appSettings");
This seems to be a flaw (maybe a bug) when using an external config file for your appSettings. I've tried it using the configSource attribute and RefreshSection simply never works, I'm assuming this is the same when using the file attribute.
If you move your appSettings back inside your web.config RefreshSection will work perfectly but otherwise I'm afraid you're doomed.
For some reason ConfigurationManager.RefreshSection("appSettings") wasn't working for me. Reloading the Web.Config into a Configuration object seems to work correctly. The following code assumes the Web.Config file is one directory below the executing (bin) folder.
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
Uri uriAssemblyFolder = new Uri(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
string appPath = uriAssemblyFolder.LocalPath;
configMap.ExeConfigFilename = appPath + #"\..\" + "Web.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
And is used like:
string webConfigVariable = config.AppSettings.Settings["webConfigVariable"].Value;
.RefreshSection() does not work when the appSettings is external.
You can however use the following to change a value:
ConfigurationManager.AppSettings.Set(key, value)
This will NOT change the setting on file, only the loaded value in memory.
So instead of using RefreshSection I did the following:
string configFile="path to your config file";
XmlDocument xml = new XmlDocument();
xml.Load(configFile);
foreach (XmlNode node in xml.SelectNodes("/appSettings/add"))
{
string key = node.Attributes["key"].Value;
string value= node.Attributes["value"].Value;
ConfigurationManager.AppSettings.Set(key, value);
}
Any subsequent calls to AppSettings.Get will contain the updated value.
The appSettings will then be updated without needing to restart the application.
As an alternative you could write your own ConfigSection and set restartOnExternalChanges="false".
Then, when reading the section with ConfigurationManager.GetSection("yourSection") the settings will be auto-refreshed without an application restart.
And you could implement your settings strongly typed or as NameValueCollection.
Yes. you are stuck with iis restarting.
There is a feature with asp.net 4.0 and iis 7.5 where the initial startup is removed.
I am not sure if this is possible in a web app, but it works in a desktop app. Try using ConfigurationSettings rather than ConfigurationManager (it will yell at you for using outdated classes...), then reading all the data into a class. When you wish to refresh, simply create a new instance and drop all references to the old instance. My theory for why this works (might be wrong): when you don't directly access the app.config file the entire time you are running, the file lock is dropped by the application. Then, edits can be made when you are not accessing the file.
The App.Config settings are cached in memory when the application starts. For this reason, I don't think you'll be able to change those settings without restarting your application. One alternative that should be pretty straight forward would be to create a separate, simple XML configuration file, and handle loading/caching/reloading it yourself.
To write, call it this way:
Dim config As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
Return AddOrUpdateAppSetting(config, "YourSettingKey", "YourValueForTheKey")
To read and be sure you get the values in file, instead of those in cache, read it this way:
Dim config As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Return config.AppSettings.Settings("TheKeyYouWantTheValue").Value
Full example:
Protected Shared Function AddOrUpdateAppSetting( _
ByVal Config As System.Configuration.Configuration _
, ByVal TheKey As String _
, ByVal TheValue As String _
) As Boolean</p>
Dim retval As Boolean = True
Dim Itm As System.Configuration.KeyValueConfigurationElement = _
Config.AppSettings.Settings.Item(TheKey)
If Itm Is Nothing Then
If Config.AppSettings.Settings.IsReadOnly Then
retval = False
Else
Config.AppSettings.Settings.Add(TheKey, TheValue)
End If
Else
' config.AppSettings.Settings(thekey).Value = thevalue
If Itm.IsReadOnly Then
retval = False
Else
Itm.Value = TheValue
End If
End If
If retval Then
Try
Config.Save(ConfigurationSaveMode.Modified)
Catch ex As Exception
retval = False
End Try
End If
Return retval
End Function
Have you tried storing your AppSettings in its own external file?
From app.config/web.config:
<appSettings configSource="appSettings.config"></appSettings>
appSettings.config:
<?xml version="1.0"?>
<appSettings>
<add key="SomeKey" value="SomeValue" />
</appSettings>
Changes made to appSettings.config should be reflected instantly.
More info:
http://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.configsource.aspx