.Net application settings - c#

I want to implement application settings to have them update settings that wont be set in a file i manage. I have the following so far:
In settings I have a variable named valuesforcomparison of type nameValueCollection and the scope is user. Now when I do the following the variable isnt updated the next time the user runs the program.
public void UpdatePropertySettings(NameValueCollection settings)
{
Properties.Settings.Default.valuesforcomparison = new NameValueCollection();
for (int i = 0; i < settings.Count; i++)
{
Properties.Settings.Default.valuesforcomparison.Add(settings.GetKey(i), settings.GetValues(i)[0]);
}
Properties.Settings.Default.Save();
Properties.Settings.Default.Upgrade();
defVals = settings;
}

NameValueCollection isnt supported.

Related

Updating Counter in App.Config

I am creating a form-application using C#. This application should create certain files, and these files need to have a incrementing number. Therefor I thought I could store a Counter in app.config and increment it everytime a file is created.
I used wrote this code :
System.Configuration.Configuration _Config = null;
public Form1()
{
InitializeComponent();
_Config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
}
private void btnNew_Click(object sender, EventArgs e)
{
int lCount;
if (int.TryParse(ConfigurationManager.AppSettings["count"], out lCount))
{
_Config.AppSettings.Settings["count"].Value = lCount++.ToString();
_Config.Save(ConfigurationSaveMode.Modified);
MessageBox.Show(ConfigurationManager.AppSettings["count"].ToString());
}
else
{
throw new Exception("Count in Config file is no int");
}
}
It's not updating the value. Do I need to reload the config or does it not make any sense to store counter value in app.config anyways?
Thanks
you need to use lCount++; before toString();, otherwise the count always save the same value, you can try to add ConfigurationManager.RefreshSection method when you save your new data.
Here is a sample for your question.
int i = 0;
Console.WriteLine("i++:" + i++.ToString()); // will get 0
i = 0;
Console.WriteLine("(++i):"+(++i).ToString()); // will get 1
c# online sample
or you can use (++lCount).ToString() instead of lCount++.ToString()
_Config.AppSettings.Settings["count"].Value = (++lCount).ToString();
the code looks like this.
System.Configuration.Configuration _Config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
int lCount;
if (int.TryParse(ConfigurationManager.AppSettings["count"], out lCount))
{
lCount++;
_Config.AppSettings.Settings["count"].Value = lCount.ToString();
_Config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(_Config.AppSettings.SectionInformation.Name);
}
Note:
I will suggest you save the counter in DB instead of App.config.

Use Settings DefaultValue without knowing its Type beforehand

The short version
Settings settings = new Settings();
settings["name1"] = Settings.Default.Properties["name1"].DefaultValue;
fails. It seems that DefaultValue is always just a string.
The long version
I'm trying to create an application "Reset Settings" button, but I can't use the built-in Reset method because I don't want it committed until a user's OK. So I'm trying to "Clone" the Settings using the following code:
Settings settings = new Settings();
foreach (SettingsProperty p in Settings.Default.Properties)
settings[p.Name] = Settings.Default.Properties[p.Name].DefaultValue;
return settings;
but I get a "The settings property 'Setting1' is of a non-compatible type." error.
Though when I do a simple Clone using this code:
Settings settings = new Settings();
foreach (SettingsProperty p in input.Properties)
settings[p.Name] = input[p.Name];//Notice the absence of "Properties" after "input".
return settings;
it works fine.
So how do I "Clone" the default Settings?

How to Update (Add/Modify/Delete) keys in AppSettings section of web.config at runtime

I like to Update keys/Values defined in AppSettings section of Web.config at runtime. however I DO NOT want to actually save them to Web.config file.
I have a huge web application that have consists of many modules, DLLs and source code files. A bunch of critical information ranged from database configuration, encryption keys, username and passwords for webservices are saved in AppSettings section of the web.config file. Recent project requirement needs me to move these values out of web.config and keep in a secure storage.
I already secured these values in an external location and I can read them back when application starts.
here is the sample code.
Global.asax
public class Global: System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
Dictionary<string, string> secureConfig = new Dictionary<string,string>{};
// --------------------------------------------------------------------
// Here I read and decrypt keys and add them to secureConfig dictionary
// To test assume the following line is a key stored in secure sotrage.
//secureConfig = SecureConfig.LoadConfig();
secureConfig.Add("ACriticalKey","VeryCriticalValue");
// --------------------------------------------------------------------
foreach (KeyValuePair<string, string> item in secureConfig) {
ConfigurationManager.AppSettings.Add(item.Key, item.Value);
}
}
}
As you may noticed it is not feasible to change references to AppSettings in a massive code created by multiple programming teams to read their settings from my secureConfig dictionary and on the other hand I should not save these values in web.config file which is available to web administrators and operators, system admins and cloud admins.
To Make programmers life easier, I want to let them add their values to AppSettings section of web.config during development, but they will be removed from there and put to secure storage later during deployment, however these values should be available to program transparently as they are still in AppSettings section.
Question: how can I add values to AppSettings at runtime so program can read them using ConfigurationManager.AppSettings["ACriticalKey"] to get "VeryCriticalValue" without saving them in Web.Config?
Please note: ConfigurationManager.AppSettings.Add(item.Key, item.Value); gives me ConfigurationErrorsException with message The configuration is read only.
Please note: Preferably some settings should be able to stay in AppSettings as before
I know this is an old question, but I ran into the same problem and I found that Set works in the same way as Add, and does not throw an exception, so just replace Add with Set, like so:
ConfigurationManager.AppSettings.Set(item.Key, item.Value);
You need to make use of WebConfigurationManager.OpenWebConfiguration()
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("Variable");
config.AppSettings.Settings.Add("Variable", "valyue");
config.Save();
Perhaps this link will help. It references 2.0 but I believe the method is still valid in 4.0.
Also, the SO question on the same/similar topic here may be of interest.
Also, modifying the web.config at runtime should cause an application pool recycle each time. Not trying to tell you how to suck eggs, just thought I'd note it for anyone's prospective interest...Thx.
Thanks to nkvu which directed me to a his first link which in turn sent me to Williarob's post "Override Configuration Manager" I managed to find a solution to my question.
The mentioned blog post covers how to read settings from another XML file and it works with both windowed applications and web applications (with a little modification in config file name and path). Although this blog written on 2010 it is still working fine with .NET4 without problem.
However as I was going to read my configuration from a secure device, I simplified the class and here is how to use the classes provided by Williarob
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Internal;
using System.Linq;
using System.Reflection;
namespace Williablog.Core.Configuration {
public sealed class ConfigSystem: IInternalConfigSystem {
private static IInternalConfigSystem clientConfigSystem;
private object appsettings;
private object connectionStrings;
/// <summary>
/// Re-initializes the ConfigurationManager, allowing us to merge in the settings from Core.Config
/// </summary>
public static void Install() {
FieldInfo[] fiStateValues = null;
Type tInitState = typeof(System.Configuration.ConfigurationManager).GetNestedType("InitState", BindingFlags.NonPublic);
if (null != tInitState) {
fiStateValues = tInitState.GetFields();
}
FieldInfo fiInit = typeof(System.Configuration.ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static);
FieldInfo fiSystem = typeof(System.Configuration.ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static);
if (fiInit != null && fiSystem != null && null != fiStateValues) {
fiInit.SetValue(null, fiStateValues[1].GetValue(null));
fiSystem.SetValue(null, null);
}
ConfigSystem confSys = new ConfigSystem();
Type configFactoryType = Type.GetType("System.Configuration.Internal.InternalConfigSettingsFactory, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
IInternalConfigSettingsFactory configSettingsFactory = (IInternalConfigSettingsFactory) Activator.CreateInstance(configFactoryType, true);
configSettingsFactory.SetConfigurationSystem(confSys, false);
Type clientConfigSystemType = Type.GetType("System.Configuration.ClientConfigurationSystem, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
clientConfigSystem = (IInternalConfigSystem) Activator.CreateInstance(clientConfigSystemType, true);
}
#region IInternalConfigSystem Members
public object GetSection(string configKey) {
// get the section from the default location (web.config or app.config)
object section = clientConfigSystem.GetSection(configKey);
switch (configKey) {
case "appSettings":
// Return cached version if exists
if (this.appsettings != null) {
return this.appsettings;
}
// create a new collection because the underlying collection is read-only
var cfg = new NameValueCollection();
// If an AppSettings section exists in Web.config, read and add values from it
if (section is NameValueCollection) {
NameValueCollection localSettings = (NameValueCollection) section;
foreach (string key in localSettings) {
cfg.Add(key, localSettings[key]);
}
}
// --------------------------------------------------------------------
// Here I read and decrypt keys and add them to secureConfig dictionary
// To test assume the following line is a key stored in secure sotrage.
//secureConfig = SecureConfig.LoadConfig();
secureConfig.Add("ACriticalKey", "VeryCriticalValue");
// --------------------------------------------------------------------
foreach (KeyValuePair<string, string> item in secureConfig) {
if (cfg.AllKeys.Contains(item.Key)) {
cfg[item.Key] = item.Value;
} else {
cfg.Add(item.Key, item.Value);
}
}
// --------------------------------------------------------------------
// Cach the settings for future use
this.appsettings = cfg;
// return the merged version of the items from secure storage and appsettings
section = this.appsettings;
break;
case "connectionStrings":
// Return cached version if exists
if (this.connectionStrings != null) {
return this.connectionStrings;
}
// create a new collection because the underlying collection is read-only
ConnectionStringsSection connectionStringsSection = new ConnectionStringsSection();
// copy the existing connection strings into the new collection
foreach (ConnectionStringSettings connectionStringSetting in ((ConnectionStringsSection) section).ConnectionStrings) {
connectionStringsSection.ConnectionStrings.Add(connectionStringSetting);
}
// --------------------------------------------------------------------
// Again Load connection strings from secure storage and merge like below
// connectionStringsSection.ConnectionStrings.Add(connectionStringSetting);
// --------------------------------------------------------------------
// Cach the settings for future use
this.connectionStrings = connectionStringsSection;
// return the merged version of the items from secure storage and appsettings
section = this.connectionStrings;
break;
}
return section;
}
public void RefreshConfig(string sectionName) {
if (sectionName == "appSettings") {
this.appsettings = null;
}
if (sectionName == "connectionStrings") {
this.connectionStrings = null;
}
clientConfigSystem.RefreshConfig(sectionName);
}
public bool SupportsUserConfig { get { return clientConfigSystem.SupportsUserConfig; } }
#endregion
}
}
To install this (or original version of configuration override) add following line to
your Global. class (Global.asax.cs) in Application_Start
Williablog.Core.Configuration.ConfigSystem .Install();
like below:
public class Global: System.Web.HttpApplication {
//...
#region protected void Application_Start(...)
protected void Application_Start(object sender, EventArgs e) {
Williablog.Core.Configuration.ConfigSystem .Install();
//...
}
#endregion
//...
}

c# : Dynamically adding new User Settings to Settings.Default.Properties collection, and saving them once form is closed.

I'm a novice programmer using Visual C# 2010. I am trying to dynamically (during run time) create a new SettingsProperty and add it to the Settings.Default.Properties collection in my application (new settings). These properties are essentially user defined views (stored in a string) that I want to save for later reloading. I have tried using the code below but it doesn't seem to be working. When I close the application, the newly created and saved properties are gone.
private void button6_Click(object sender, EventArgs e)
{
string connectionText = maskedTextBox3.Text;
string vusipsText = maskedTextBox2.Text;
string chartText = maskedTextBox1.Text;
string[] settingsArray = { connectionText, chartText, vusipsText };
string saveSettings = String.Join(":", settingsArray);
//configure new property
SettingsProperty property = new SettingsProperty("kri");
property.DefaultValue = saveSettings;
property.IsReadOnly = false;
property.PropertyType = typeof(string);
property.Provider = Settings.Default.Providers["LocalFileSettingsProvider"];
property.Attributes.Add(typeof(System.Configuration.UserScopedSettingAttribute), new System.Configuration.UserScopedSettingAttribute());
Settings.Default.Properties.Add(property);
//Properties.Settings.Default.Reload();
Settings.Default.Save();
ActiveForm.Close();
}
How can I get around this issue?
Thanks
Your code looks fine, but the Settings doesn't know about your property next time you load the data. If you define your property again (at load time) the value should be available. This is a working sample out of a loop that I use to save enums:
If My.Settings.Properties(settingName) Is Nothing Then
Dim p = New Configuration.SettingsProperty(settingName)
p.Provider = My.Settings.Providers("LocalFileSettingsProvider")
p.Attributes.Add(GetType(Configuration.UserScopedSettingAttribute), _
New Configuration.UserScopedSettingAttribute())
p.PropertyType = GetType(SampleEnum)
My.Settings.Properties.Add(p)
If My.Settings(settingName) Is Nothing Then
My.Settings(settingName) = SampleEnum.DefaultValue
End If
End If
Always run the code at startup to create the property and for the first time to create the value, too.

Can I modify [appname].exe.config without having to manually read/write the XMl?

I have created some settings in a C# application using .NET 3.5 and Visual Studio 2008 Express. I have a number of application-scoped settings which I would like to be able to modify from within the application - I can access them through Properties.Settings.Default but they are read only as expected. I do not want to have to make these become user-scoped settings as they should be application-wide. Is this possible without loading the XML and reading/writing from/to it myself?
I have seen examples using System.Configuration.ConfigurationManager.OpenExeConfiguration, but the config xml looks to be in a different format to that which I am using (is this from an older version?)
Thanks
Edit
I worked out that I can modify the values doing this, but it seems like a ridiculous hack.
Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
SettingElementCollection settingElements = ((ClientSettingsSection)config.GetSectionGroup("applicationSettings").Sections[0]).Settings;
SettingElement element = settingElements.Get("SettingName");
element.Value.ValueXml.InnerText = "new value";
config.Save(ConfigurationSaveMode.Modified, true);
OpenExeConfiguration (or any of the other ConfigurationManager methods) is the preferred entry point for most modifications to configuration files. Once you have a Configuration instance you should get the section you wish to modify and after the modifications call any of the ConfigurationManager.Save methods. However, it is impossible to retrieve the applicationSettings section this way.
There is no API for changing settings from the applicationSettings section in your app.config file. Only user-scoped settings can be changed this way.
So actually changing these settings can only be done by directly manipulating the app.config XML file.
Some confusion may occur because the indexed property from Properties.Settings.Default is actually writable. The following is perfectly legal:
Properties.Settings.Default["MySetting"] = "New setting value";
Properties.Settings.Default.Save();
However, the setting will not be saved.
You could also use the Windows Registry to store app-specific state. There are per-user and per-machine keys in the registry - either or both are available to you . For example, some people use the registry to store the location and size of the app window upon exit. Then when the app is restarted, you can position and size the window according to its last known size. This is a small example of the sort of state you can store in the registry.
To do it you would use different APIs for storage and retrieval. Specifically the SetValue and GetValue calls on the Microsoft.Win32.RegistryKey class. There may be libraries that are helpful in persisting complex state to the registry. If you have simple cases ( a few strings and numbers) then it is easy to just do it yourself.
private static string _AppRegyPath = "Software\\Vendor Name\\Application Name";
public Microsoft.Win32.RegistryKey AppCuKey
{
get
{
if (_appCuKey == null)
{
_appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(_AppRegyPath, true);
if (_appCuKey == null)
_appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(_AppRegyPath);
}
return _appCuKey;
}
set { _appCuKey = null; }
}
private void RetrieveAndApplyState()
{
string s = (string)AppCuKey.GetValue("textbox1Value");
if (s != null) this.textbox1.Text = s;
s = (string)AppCuKey.GetValue("Geometry");
if (!String.IsNullOrEmpty(s))
{
int[] p = Array.ConvertAll<string, int>(s.Split(','),
new Converter<string, int>((t) => { return Int32.Parse(t); }));
if (p != null && p.Length == 4)
{
this.Bounds = ConstrainToScreen(new System.Drawing.Rectangle(p[0], p[1], p[2], p[3]));
}
}
}
private void SaveStateToRegistry()
{
AppCuKey.SetValue("textbox1Value", this.textbox1.Text);
int w = this.Bounds.Width;
int h = this.Bounds.Height;
int left = this.Location.X;
int top = this.Location.Y;
AppCuKey.SetValue("Geometry", String.Format("{0},{1},{2},{3}", left, top, w, h);
}
private System.Drawing.Rectangle ConstrainToScreen(System.Drawing.Rectangle bounds)
{
Screen screen = Screen.FromRectangle(bounds);
System.Drawing.Rectangle workingArea = screen.WorkingArea;
int width = Math.Min(bounds.Width, workingArea.Width);
int height = Math.Min(bounds.Height, workingArea.Height);
// mmm....minimax
int left = Math.Min(workingArea.Right - width, Math.Max(bounds.Left, workingArea.Left));
int top = Math.Min(workingArea.Bottom - height, Math.Max(bounds.Top, workingArea.Top));
return new System.Drawing.Rectangle(left, top, width, height);
}
That code uses Microsoft.Win32.Registry.CurrentUser, and so it sets and retrieves user-specific app settings. If you are setting or retrieving machine-wide state, you want Microsoft.Win32.Registry.LocalMachine.

Categories

Resources