C# Modify Connection String that exists inside a library - c#

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)

Related

Visual Studio 2019 doesn't save the options of a form app [duplicate]

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.
Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.
I understand three options are available:
ConfigurationSettings file (appname.exe.config)
Registry
Custom XML file
I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.
Does this mean that I should use a custom XML file to save configuration settings?
If so, I would like to see code example of that (C#).
I have seen other discussions on this subject, but it is still not clear to me.
If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.
Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
This technique is applicable both for console, Windows Forms, and other project types.
Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.
Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs
If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.
You can use the app.config file to save application-level settings (that are the same for each user who uses your application).
I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.
Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.
The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.
You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.
I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.
The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.
Here's how you'd use it to keep track of a window's size and location:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.
With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.
Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.
It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property
Trust me, the library is top notch!
The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.
The following sample allows storage of an objects named properties to a file in isolated storage. Such as:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Properties may be recovered using:
AppSettings.Load(myobject, "myFile.jsn");
It is just a sample, not suggestive of best practices.
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.
Here is an example to store the position and size of a form.
The configuration dataobject is strongly typed and easy to use:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
A manager class for saving and loading:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
Now you can create an instance and use in your form's load and close events:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
And the produced XML file is also readable:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:
First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.
Both provide different ways of saving changes:
The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as: config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.
But there are a couple of other alternative options:
Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.
As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.
A 5th option is to store settings in the registry. How you can do it is described here.
Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use var myValue = Environment.GetEnvironmentVariable("MyVariable");. Note that your application usually needs to be restarted to get the updated environment settings.
If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.
And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:
var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);
You can use assemblyDirectory as base directory to store your files.
I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.
"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.
For instance, if a configuration file is like that
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
We can retrieve values like this
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.
Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig
Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.
If you use .NET 4.0 dynamic, this library is really easy to use
(serialize, deserialize, nested objects support and ordering output
as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
For .NET YAML configuration library... I haven't found one that is as
easy to use as JsonConfig
You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)
Sample for getting path of special folder: C# getting the path of
%AppData%
If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.
As far as I can tell, .NET does support persisting settings using the built-in application settings facility:
The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.
I can imagine two good options:
The strongly typed version and
The object oriented version.
The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.
With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.
You can find the code of both fully functional implementations HERE.
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}

Best practice for saving Persistent Settings in C# [duplicate]

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.
Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.
I understand three options are available:
ConfigurationSettings file (appname.exe.config)
Registry
Custom XML file
I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.
Does this mean that I should use a custom XML file to save configuration settings?
If so, I would like to see code example of that (C#).
I have seen other discussions on this subject, but it is still not clear to me.
If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.
Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
This technique is applicable both for console, Windows Forms, and other project types.
Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.
Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs
If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.
You can use the app.config file to save application-level settings (that are the same for each user who uses your application).
I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.
Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.
The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.
You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.
I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.
The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.
Here's how you'd use it to keep track of a window's size and location:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.
With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.
Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.
It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property
Trust me, the library is top notch!
The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.
The following sample allows storage of an objects named properties to a file in isolated storage. Such as:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Properties may be recovered using:
AppSettings.Load(myobject, "myFile.jsn");
It is just a sample, not suggestive of best practices.
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.
Here is an example to store the position and size of a form.
The configuration dataobject is strongly typed and easy to use:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
A manager class for saving and loading:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
Now you can create an instance and use in your form's load and close events:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
And the produced XML file is also readable:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:
First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.
Both provide different ways of saving changes:
The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as: config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.
But there are a couple of other alternative options:
Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.
As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.
A 5th option is to store settings in the registry. How you can do it is described here.
Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use var myValue = Environment.GetEnvironmentVariable("MyVariable");. Note that your application usually needs to be restarted to get the updated environment settings.
If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.
And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:
var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);
You can use assemblyDirectory as base directory to store your files.
I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.
"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.
For instance, if a configuration file is like that
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
We can retrieve values like this
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.
Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig
Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.
If you use .NET 4.0 dynamic, this library is really easy to use
(serialize, deserialize, nested objects support and ordering output
as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
For .NET YAML configuration library... I haven't found one that is as
easy to use as JsonConfig
You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)
Sample for getting path of special folder: C# getting the path of
%AppData%
If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.
As far as I can tell, .NET does support persisting settings using the built-in application settings facility:
The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.
I can imagine two good options:
The strongly typed version and
The object oriented version.
The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.
With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.
You can find the code of both fully functional implementations HERE.
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}

How do I add appSettings from C# code? [duplicate]

What I want to achieve is very simple: I have a Windows Forms (.NET 3.5) application that uses a path for reading information. This path can be modified by the user, by using the options form I provide.
Now, I want to save the path value to a file for later use. This would be one of the many settings saved to this file. This file would sit directly in the application folder.
I understand three options are available:
ConfigurationSettings file (appname.exe.config)
Registry
Custom XML file
I read that the .NET configuration file is not foreseen for saving values back to it. As for the registry, I would like to get as far away from it as possible.
Does this mean that I should use a custom XML file to save configuration settings?
If so, I would like to see code example of that (C#).
I have seen other discussions on this subject, but it is still not clear to me.
If you work with Visual Studio then it is pretty easy to get persistable settings. Right click on the project in Solution Explorer and choose Properties. Select the Settings tab and click on the hyperlink if settings doesn't exist.
Use the Settings tab to create application settings. Visual Studio creates the files Settings.settings and Settings.Designer.settings that contain the singleton class Settings inherited from ApplicationSettingsBase. You can access this class from your code to read/write application settings:
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
This technique is applicable both for console, Windows Forms, and other project types.
Note that you need to set the scope property of your settings. If you select Application scope then Settings.Default.<your property> will be read-only.
Reference: How To: Write User Settings at Run Time with C# - Microsoft Docs
If you are planning on saving to a file within the same directory as your executable, here's a nice solution that uses the JSON format:
using System;
using System.IO;
using System.Web.Script.Serialization;
namespace MiscConsole
{
class Program
{
static void Main(string[] args)
{
MySettings settings = MySettings.Load();
Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
Console.WriteLine("Incrementing 'myInteger'...");
settings.myInteger++;
Console.WriteLine("Saving settings...");
settings.Save();
Console.WriteLine("Done.");
Console.ReadKey();
}
class MySettings : AppSettings<MySettings>
{
public string myString = "Hello World";
public int myInteger = 1;
}
}
public class AppSettings<T> where T : new()
{
private const string DEFAULT_FILENAME = "settings.json";
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
}
public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
}
public static T Load(string fileName = DEFAULT_FILENAME)
{
T t = new T();
if(File.Exists(fileName))
t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
return t;
}
}
}
The registry is a no-go. You're not sure whether the user which uses your application, has sufficient rights to write to the registry.
You can use the app.config file to save application-level settings (that are the same for each user who uses your application).
I would store user-specific settings in an XML file, which would be saved in Isolated Storage or in the SpecialFolder.ApplicationData directory.
Next to that, as from .NET 2.0, it is possible to store values back to the app.config file.
The ApplicationSettings class doesn't support saving settings to the app.config file. That's very much by design; applications that run with a properly secured user account (think Vista UAC) do not have write access to the program's installation folder.
You can fight the system with the ConfigurationManager class. But the trivial workaround is to go into the Settings designer and change the setting's scope to User. If that causes hardships (say, the setting is relevant to every user), you should put your Options feature in a separate program so you can ask for the privilege elevation prompt. Or forego using a setting.
I wanted to share a library I've built for this. It's a tiny library, but a big improvement (IMHO) over .settings files.
The library is called Jot (GitHub). Here is an old The Code Project article I wrote about it.
Here's how you'd use it to keep track of a window's size and location:
public MainWindow()
{
InitializeComponent();
_stateTracker.Configure(this)
.IdentifyAs("MyMainWindow")
.AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
.RegisterPersistTrigger(nameof(Closed))
.Apply();
}
The benefit compared to .settings files: There's considerably less code, and it's a lot less error-prone since you only need to mention each property once.
With a settings files you need to mention each property five times: once when you explicitly create the property and an additional four times in the code that copies the values back and forth.
Storage, serialization, etc. are completely configurable. When the target objects are created by an IoC container, you can [hook it up][] so that it applies tracking automatically to all objects it resolves, so that all you need to do to make a property persistent is slap a [Trackable] attribute on it.
It's highly configurable, and you can configure:
- when data is persisted and applied globally or for each tracked object
- how it's serialized
- where it's stored (e.g. file, database, online, isolated storage, registry)
- rules that can cancel applying/persisting data for a property
Trust me, the library is top notch!
The registry/configurationSettings/XML argument still seems very active. I've used them all, as the technology has progressed, but my favourite is based on Threed's system combined with Isolated Storage.
The following sample allows storage of an objects named properties to a file in isolated storage. Such as:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Properties may be recovered using:
AppSettings.Load(myobject, "myFile.jsn");
It is just a sample, not suggestive of best practices.
internal static class AppSettings
{
internal static void Save(object src, string targ, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = src.GetType();
string[] paramList = targ.Split(new char[] { ',' });
foreach (string paramName in paramList)
items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));
try
{
// GetUserStoreForApplication doesn't work - can't identify.
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write((new JavaScriptSerializer()).Serialize(items));
}
}
catch (Exception) { } // If fails - just don't use preferences
}
internal static void Load(object tar, string fileName)
{
Dictionary<string, object> items = new Dictionary<string, object>();
Type type = tar.GetType();
try
{
// GetUserStoreForApplication doesn't work - can't identify
// application unless published by ClickOnce or Silverlight
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
}
}
catch (Exception) { return; } // If fails - just don't use preferences.
foreach (KeyValuePair<string, object> obj in items)
{
try
{
tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
}
catch (Exception) { }
}
}
}
A simple way is to use a configuration data object, save it as an XML file with the name of the application in the local Folder and on startup read it back.
Here is an example to store the position and size of a form.
The configuration dataobject is strongly typed and easy to use:
[Serializable()]
public class CConfigDO
{
private System.Drawing.Point m_oStartPos;
private System.Drawing.Size m_oStartSize;
public System.Drawing.Point StartPos
{
get { return m_oStartPos; }
set { m_oStartPos = value; }
}
public System.Drawing.Size StartSize
{
get { return m_oStartSize; }
set { m_oStartSize = value; }
}
}
A manager class for saving and loading:
public class CConfigMng
{
private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
private CConfigDO m_oConfig = new CConfigDO();
public CConfigDO Config
{
get { return m_oConfig; }
set { m_oConfig = value; }
}
// Load configuration file
public void LoadConfig()
{
if (System.IO.File.Exists(m_sConfigFileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
m_oConfig = (CConfigDO)oData;
srReader.Close();
}
}
// Save configuration file
public void SaveConfig()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
Type tType = m_oConfig.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, m_oConfig);
swWriter.Close();
}
}
}
Now you can create an instance and use in your form's load and close events:
private CConfigMng oConfigMng = new CConfigMng();
private void Form1_Load(object sender, EventArgs e)
{
// Load configuration
oConfigMng.LoadConfig();
if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
{
Location = oConfigMng.Config.StartPos;
Size = oConfigMng.Config.StartSize;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Save configuration
oConfigMng.Config.StartPos = Location;
oConfigMng.Config.StartSize = Size;
oConfigMng.SaveConfig();
}
And the produced XML file is also readable:
<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<StartPos>
<X>70</X>
<Y>278</Y>
</StartPos>
<StartSize>
<Width>253</Width>
<Height>229</Height>
</StartSize>
</CConfigDO>
Yes, it is possible to save the configuration - but it pretty much depends on the way you choose to do it. Let me describe the technical differences so you can understand the options you have:
First, you need to distinguish, whether you want to use applicationSettings or AppSettings in your *.exe.config(aka App.config in Visual Studio) file - there are fundamental differences, being described here.
Both provide different ways of saving changes:
The AppSettings allow you to read and write directly into the config file via config.Save(ConfigurationSaveMode.Modified);, where config is defined as: config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
The applicationSettings allow to read, but if you write changes (via Properties.Settings.Default.Save();) it will be written on a per-user basis, stored in a special place (e.g. C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0). As Hans Passant mentioned in his answer, this is because a user usually has restricted rights to Program Files and cannot write to it without invoking the UAC prompt. A disadvantage is if you're adding configuration keys in the future you need to synchronize them with every user profile.
But there are a couple of other alternative options:
Since .NET Core (and .NET 5 and 6) a 3rd option is the appsettings.json file which uses Microsoft's configuration abstraction (and also the secrets.json file which is stored in your user profile rather than in the assemblies directories). But usually WinForms isn't using it, so I am mentioning it just for completeness. However, here are some references how to read and write the values. Alternatively you can use Newtonsoft JSON to read and write the appsettings.json file, but it is not limited to that: you can also create your own json files with that method.
As mentioned in the question, there is a 4th option: If you treat the configuration file as XML document, you can load, modify and save it by using the System.Xml.Linq.XDocument class. It is not required to use a custom XML file, you can read the existing config file; for querying elements, you can even use Linq queries. I have given an example here, check out the function GetApplicationSetting there in the answer.
A 5th option is to store settings in the registry. How you can do it is described here.
Last not least, there is a 6th option: You can store values in the environment (system environment or environment of your account). In Windows settings (the cogwheel in the Windows menu), type in "environment" in the search bar and add or edit them there. To read them, use var myValue = Environment.GetEnvironmentVariable("MyVariable");. Note that your application usually needs to be restarted to get the updated environment settings.
If you require encryption to protect your values, check out this answer. It describes how to use Microsoft's DPAPI to store values encrypted.
And if you want to support your own files, whether XML or JSON, it might be useful to know the directory of the assembly running:
var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);
You can use assemblyDirectory as base directory to store your files.
I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.
"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.
For instance, if a configuration file is like that
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
We can retrieve values like this
var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];
string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;
It is compatible with .NET 2.0 and higher. We can create configuration files on the fly and we can save it later.
Source: http://sharpconfig.net/
GitHub: https://github.com/cemdervis/SharpConfig
Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.
If you use .NET 4.0 dynamic, this library is really easy to use
(serialize, deserialize, nested objects support and ordering output
as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
For .NET YAML configuration library... I haven't found one that is as
easy to use as JsonConfig
You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)
Sample for getting path of special folder: C# getting the path of
%AppData%
If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.
As far as I can tell, .NET does support persisting settings using the built-in application settings facility:
The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving.
- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.
I can imagine two good options:
The strongly typed version and
The object oriented version.
The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.
With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.
You can find the code of both fully functional implementations HERE.
public static class SettingsExtensions
{
public static bool TryGetValue<T>(this Settings settings, string key, out T value)
{
if (settings.Properties[key] != null)
{
value = (T) settings[key];
return true;
}
value = default(T);
return false;
}
public static bool ContainsKey(this Settings settings, string key)
{
return settings.Properties[key] != null;
}
public static void SetValue<T>(this Settings settings, string key, T value)
{
if (settings.Properties[key] == null)
{
var p = new SettingsProperty(key)
{
PropertyType = typeof(T),
Provider = settings.Providers["LocalFileSettingsProvider"],
SerializeAs = SettingsSerializeAs.Xml
};
p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
var v = new SettingsPropertyValue(p);
settings.Properties.Add(p);
settings.Reload();
}
settings[key] = value;
settings.Save();
}
}

Class Library Connection String Confusion

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");

Get and Set values in local resource file

I have put 2 strings in the built-in resource file of my main project (not sure how I define this properly). How can I access these values? How would I change them? The resource is public so that the user can change them.
eg:
Project1.Resources.Get("string1").Value();
and
Project1.Resources.Set("string1") = "whatever";
This is pseudo code.
Resources are not intended to be changed at runtime. You should consider using user settings instead. For details, see Using Application Settings and User Settings on MSDN.
This will allow you to use the designer to build the settings, and write:
string string1 = Properties.Settings.Default.String1;
And:
Properties.Settings.Default.String1 = "whatever";
Properties.Settings.Default.Save();
You can get resource by writing the following piece of code
Project1.Resources.String1
You can not change it at runtime.

Categories

Resources