I can't modify the app.config file - c#

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]

Related

Update app.config after installation usng Wix#

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.

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.

How to add a field in my quartz configuration dynamically?

I have a quartz configuration section in my web.config, and I want to add a key value field to it. (I know I can just go to the web.config and add it manually but that defeats the purpose)
I tried using this way
var config = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
config.Add("quartz.dataSource.quartzDS.connectionString", "data source =..");
but it failed because collection is read only and can't be modified. Any tip to how to do this?
Edit: I ended up copying the config to a nameValueCollection and then copying it to another one (for the readonly properties) add the key values I want and passing it to the function I needed.
var oldConfig = (NameValueCollection)WebConfigurationManager.GetSection("quartz");
var config = Test(oldConfig);
var connectionString = unitOfWork.GetConnectionStringByTenantIdentifier(tenantId);
config.Add("quartz.dataSource.quartzDS.connectionString", connectionString);
await unitOfWork.GetService<SchedulerService>().StartScheduler(config, tenantId);
this way I will have the custom configuration for every tenant the way I want it. Sorry if my question wasn't clear.
You can actually do this in two ways.
One way is to set your dynamic connection string in the standard AppSettings section and then create a new Quartz Scheduler with a new set of XML properties (an example is provided in Quartz.NET distribution, so I will cut this short)
var properties = new NameValueCollection
{
["quartz.scheduler.instanceName"] = "XmlConfiguredInstance",
["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz",
... etc.
};
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = await sf.GetScheduler();
Then you can save your non-const string in the AppSettings and get it form there.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings.Add("quartz.dataSource.quartzDS.connectionString", connstring);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
Or you can read your whole settings file as XML, as previously answered, BUT you have to make sure that any edits are done before you initialize the default Quartz Scheduler, as it's properties become read-only, and to change them you will have to create a new ISchedulerFactory anyway, which kinda beats the purpose.
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
xmlDoc.SelectSingleNode("//quartz/add[#key='quartz.dataSource.quartzDS.connectionString']").Attributes["value"].Value = "...";
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("quartz");
But I advise you not to edit your main config file at runtime at all, and instead use an ISchedulerFactory XmlConfiguredInstance while getting and saving the connstring into a UAC-compatible location in any format you like (to prevent Modifying app.config at runtime throws exception from happening)
Still if you want to use the config file you can use this tutorial from Yi Zeng for further reading
You can try using XmlDocument classes to go to a lower level.
Make sure the user of your app has write permissions to the config file
public static void WriteKey(String configFileName, String key, String value)
{
XmlDocument doc = new XmlDocument();
doc.Load(configFileName);
XmlNode node = doc.SelectSingleNode("//quartz");
if (node == null)
{
throw new InvalidOperationException("quartz section not found in config file.");
}
try
{
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
if ((elem != null))
{
elem.SetAttribute("value", value);
}
else
{
elem = doc.CreateElement("add");
elem.SetAttribute("key", key);
elem.SetAttribute("value", value);
node.AppendChild(elem);
}
doc.Save(configFileName);
}
catch
{
throw new InvalidOperationException("Error writing config file");
}
}

How to Create New User Setting in app.config at Run Time

I have an Editable ComboBox. The user enters text and presses a Save button. Their text is turned into a string.
I need it at Run Time to Create a new User Setting to the app.config with the name of their string. (I think this part works now).
Then another ComboBox's Selected Item is saved to the Setting. (Object reference not set error).
This is to create a custom preset that will save each control state, checkboxes, textboxes, etc. in the program.
// Control State to be Saved to Setting
Object comboBox2Item = ComboBox2.SelectedItem;
// User Custom Text
string customText = ComboBox1.Text;
// Create New User Setting
var propertyCustom = new SettingsProperty(customText);
propertyCustom.Name = customText;
propertyCustom.PropertyType = typeof(string);
Settings.Default.Properties.Add(propertyCustom);
// Add a Control State (string) to the Setting
Settings.Default[customText] = (string)comboBox2Item;
At this part I get an error.
Settings.Default[customText] = (string)comboBox2Item;
Exception:Thrown: "Object reference not set to an instance of an object."
I have tried setting ComboBox1.Text to an Object instead of string, with same error. The text and string is also not null.
Object customText = ComboBox1.Text;
Here's a visual of what I'm trying to do
Original Answer:
I haven't tried adding a new setting to the file but i have had to update it. Here is some code that I use to save and retrieve the saved changes to the file. I know it doesn't directly answer the question but should point you in the right direction as to what classes to look at and use.
I'll try to update to directly answer this question once I get some breathing time.
public static void UpdateConfig(string setting, string value, bool isUserSetting = false)
{
var assemblyPath = AppDomain.CurrentDomain.BaseDirectory;
var assemblyName = "AssemblyName";
//need to modify the configuration file, launch the server with those settings.
var config =
ConfigurationManager.OpenExeConfiguration(string.Format("{0}\\{1}.exe", assemblyPath, "AssemblyName"));
//config.AppSettings.Settings["Setting"].Value = "false";
var getSection = config.GetSection("applicationSettings");
Console.WriteLine(getSection);
var settingsGroup = isUserSetting
? config.SectionGroups["userSettings"]
: config.SectionGroups["applicationSettings"];
var settings =
settingsGroup.Sections[string.Format("{0}.Properties.Settings", assemblyName)] as ClientSettingsSection;
var settingsElement = settings.Settings.Get(setting);
settings.Settings.Remove(settingsElement);
settingsElement.Value.ValueXml.InnerText = value;
settings.Settings.Add(settingsElement);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
Edited Answer:
I did a quick google search and found an accepted answer on the MSDN forum.MSDN question. You have to call save on the properties class in order for the add to take affect. Think of a database transaction, until you call commit, it doesn't take effect.
So what appears to be missing in your code is: Properties.Settings.Default.Save(); which should be the very next line after your Settings.Default.Properties.Add(propertyCustom);

ConfigurationManager.AppSettings.Settings.Add() appends value on each run

I have the following piece of code. Every time, I run the C# project the values for the app settings key gets appended.
var configSettings = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
configSettings.AppSettings.Settings.Add("Key", "Value");
configSettings.Save(ConfigurationSaveMode.Full, true);
ConfigurationManager.RefreshSection("appSettings");
1st run:
Key: Value
2nd run:
Key, Value, Value
Why are the values getting appended? I need it to start on a clean plate on each run.
You need to check if the AppSetting already exists. If it exists, you have to update the value. If it doesn't you have to add the value.
var configSettings = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configSettings.AppSettings.Settings;
if (settings["Key"] == null)
{
settings.Add("Key", "Value");
}
else
{
settings["Key"].Value = "NewValue";
}
configSettings.Save(ConfigurationSaveMode.Full, true);
ConfigurationManager.RefreshSection("appSettings");
AppSettings.Settings is basically a collection of key/value pairs.
Check the below MSDN documentation for more details.
https://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.appsettings(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.configuration.appsettingssection.settings(v=vs.110).aspx

Categories

Resources