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.
Related
I am totally new to Wix and wix#, I am trying to update the app.config after the installation is finished.
I am able to achieve it by using the Wix Util extension util:XmlFile, but I want it to be done by wix# CustomDialog UI.
Below is the code which I had tried
var project = new ManagedProject("MyProduct",
new Dir(#"%ProgramFiles%\My Company\My Product",
new File("Program.cs"),
new File(#"myPath\App.config")),
new ElevatedManagedAction(CustomActions.OnInstall, Return.check, When.After, Step.InstallFiles, Condition.NOT_Installed)
{
UsesProperties = "CONFIG_FILE=[INSTALLDIR]App.config"
});
project.Load += Msi_Load;
project.BeforeInstall += Msi_BeforeInstall;
project.AfterInstall += Msi_AfterInstall;
Created a CustomDialog and set its value to a session variable after next
void next_Click(object sender, EventArgs e)
{
MsiRuntime.Session["NAME"] = name.Text;
Shell.GoNext();
}
I am able to retrieve session value in Msi_BeforeInstall but here app.config path is getting null as it is not copied to the INSTALLDIR and when I tried to perform it on Msi_AfterInstall here I am not getting the session variable property
I also tried to do it by CustomAction after installation
[CustomAction]
public static ActionResult OnInstall(Session session)
{
return session.HandleErrors(() =>
{
string configFile = session.Property("INSTALLDIR") + "App.config";
string userName = session.Property("NAME");
UpdateAsAppConfig(configFile, userName);
});
}
static public void UpdateAsAppConfig(string configFile,string name)
{
var config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = configFile }, ConfigurationUserLevel.None);
config.AppSettings.Settings["MyName"].Value = name;
config.Save();
}
But not getting the session variable property.
I am really new to it, any help would be appreciated. Please help me if I am doing it wrong or how can I update my app.config after installation.
Thanks.
I know your problem, AfterInstall event works with dead session it's unaccessable at this moment. If you need some properties in AfterInstall moment you can do use SetupEventArgs.Data property:
private void OnBeforeInstall(SetupEventArgs arguments)
{
//....
arguments.Data["MyName"] = arguments.Session["MyName"];
}
private void OnAfterInstall(SetupEventArgs arguments)
{
var propertyValue = arguments.Data["MyName"];
}
Also Data property can be used in your UI forms shown AFTER ProgressBarForm. Hope it help to you, let me know your feedback.
This question already has answers here:
How can I save application settings in a Windows Forms application?
(14 answers)
Closed 7 years ago.
what is the best way to save configuration data in c# application?
note that those data maybe changed dynamically.
as i know, ConfigurationManager class can be used. but i heard that this is not good way to do that.
A simple way is to use a config data object, save it as 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 config 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 configfile
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 configfile
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 use it in your form in the load and close events:
private void Form1_Load(object sender, EventArgs e)
{
// Load config
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 config
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>
Very simple, or what so you think?
Use the built-in settings mechanism. But leave the configuration manager alone and use your settings like
Properties.Settings.Default.x
There is nothing wrong in using the ConfigurationManager (web.config/app.config).
For different types of configuration data, I recommend the following;
Never-changing read-only configuration data
Hardcode in application or use (assembly-level) attributes. This
requires a recompile/re-installation of app when configuration-data
changes.
Almost never-changing read-only configuration data
Use the <appSettings>, <connectionStrings> or other sections in web.config/app.config (Often requires a restart of app when changed, especially when configuration-data is read only during startup)
Server-side writable configuration data maintained in application
Use a database or a file in C:\ProgramData\<name of your company>\<name of your app>
Client-side writeable configuration data maintained in application (desktop-apps)
Use a file in C:\Users\<clients login name>\AppData\Local\<name of your company>\<name of your app>\. If you need configuration data to be available on other computers (using the same AD domain), use the LocalRoaming folder under AppData instead (don't place too much configuration data in files placed here, tho because they need to be transferred between computers)
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
//...
}
What's wrong with the following code:
private static void UpdateAppSettings(string settingName, string settingValue)
{
if (settingName == null) throw new ArgumentNullException("settingName");
if (settingValue == null) throw new ArgumentNullException("settingValue");
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var appSettings = config.AppSettings;
var setting = appSettings.Settings[settingName];
setting.Value = settingValue;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("AppSettings");
}
I don't know why it doesn't save the new settings. It first opens the app.config file. After going to appsetting area. It then finds a specific key as settingName and changes the value to settingValue. Afterwards, it saves the file and refreshes it. It almost works; up to config.Save(...). But after that I don't know what happens.
This question seems to be the same as what you are asking.
The answer looks to be this:
config.AppSettings[settingName] = settingValue;
EDIT:
This question has the answer I think
config.AppSettings.Settings[settingName]
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.