Modify custom app.config config section and save it - c#

I'm developing a C# WPF MVVM application with .NET Framework 4.6.1 and I have a custom section in App.config:
<configuration>
<configSections>
<section name="SpeedSection" type="System.Configuration.NameValueSectionHandler" />
</configSections>
<SpeedSection>
<add key="PrinterSpeed" value="150" />
<add key="CameraSpeed" value="150" />
</SpeedSection>
</configuration>
I want to modify PrinterSpeed and CameraSpeed from my app. I have tried this code:
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}
But it doesn't work because I'm not modifying AppSettings section.
How can I modify those values?

System.Configuration.NameValueSectionHandler is hard to work with. You can replace it with System.Configuration.AppSettingsSection without touching anything else:
<configuration>
<configSections>
<section name="SpeedSection" type="System.Configuration.AppSettingsSection" />
</configSections>
<SpeedSection>
<add key="PrinterSpeed" value="150" />
<add key="CameraSpeed" value="150" />
</SpeedSection>
</configuration>
And then change your method as follows:
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = ((AppSettingsSection) configFile.GetSection("SpeedSection")).Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}

You should use ConfigurationSection class. This tutorial could help: https://msdn.microsoft.com/en-us/library/2tw134k3.aspx

Related

how to read encrypted app.config appSettings in win console application?

EDIT: This question made no sense. I mixed .vshost.config with exe.config. What to do with this?
Program.cs main:
databaseName = System.Configuration.ConfigurationManager.AppSettings["DatabaseName"];
databaseUser = System.Configuration.ConfigurationManager.AppSettings["DatabaseUser"];
databasePwd = System.Configuration.ConfigurationManager.AppSettings["DatabasePassword"];
port = System.Configuration.ConfigurationManager.AppSettings["Port"];
logDirectory = System.Configuration.ConfigurationManager.AppSettings["LogDirectory"];
strLogLevel = System.Configuration.ConfigurationManager.AppSettings["LogLevel"];
EncryptConfigSection("appSettings");
This is how I encrypt the file:
private static void EncryptConfigSection(string sectionKey)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection(sectionKey);
if (section != null)
{
if (!section.SectionInformation.IsProtected)
{
if (!section.ElementInformation.IsLocked)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
}
}
}
The file gets duplicated and encrypted just like in the examples I found in web:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAvsQ9Wtc58EC5EZCEq91EogQAAAACAAAAAAADZgAAwAAAABAAAClVHhpR5xAw4KFNyrANtavAAAAAASAAACgAAAAEAAAABHkhg2ztiY3bdWhTG9iy6twAAAAF5mAHt7oDQWCgc1iLL2hYUJZgmquU8XsojjqXVQdV1CaW3XEBXBDhN30DEZizP3F5rGGMCjL9CVjHfsPAfvVYyRHCcup22BoByb5y/MDujaASpaWZYcdxSxLijT/Zq3zB8hiWyWPruY0G7emYEOq/xQAAADkgStCMABwo3oZx/VXHD41wrsjXg==</CipherValue>
</CipherData>
</EncryptedData>
</appSettings>
</configuration>
But next time I start it, I can't read it. All read values are null. I naturally removed the original, unencrypted file from the folder.
You can use the KeyValueConfigurationCollection for the appSettings key and the ConnectionStringSettingsCollection for the connectionStrings key.
This encrypts when not encrypted and decrypts and prints out values when encrypted:
private static void CryptConfig (string[] sectionKeys)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
foreach (string sectionKey in sectionKeys)
{
ConfigurationSection section = config.GetSection(sectionKey);
if (section != null)
{
if (section.ElementInformation.IsLocked)
{
Console.WriteLine("Section: {0} is locked", sectionKey);
}
else
{
if (!section.SectionInformation.IsProtected)
{
//%windir%\system32\Microsoft\Protect\S-1-5-18
section.SectionInformation.ProtectSection(DPCP);
section.SectionInformation.ForceSave = true;
Console.WriteLine("Encrypting: {0} {1}", section.SectionInformation.Name, section.SectionInformation.SectionName);
}
else
{ // display values for current config application name value pairs
foreach (KeyValueConfigurationElement x in config.AppSettings.Settings)
{
Console.WriteLine("Key: {0} Value:{1}", x.Key, x.Value);
}
foreach (ConnectionStringSettings x in config.ConnectionStrings.ConnectionStrings)
{
Console.WriteLine("Name: {0} Provider:{1} Cs:{2}", x.Name, x.ProviderName, x.ConnectionString);
}
//
section.SectionInformation.UnprotectSection();
section.SectionInformation.ForceSave = true;
Console.WriteLine("Decrypting: {0} {1}", section.SectionInformation.Name, section.SectionInformation.SectionName);
}
}
}
else
{
Console.WriteLine("Section: {0} is null", sectionKey);
}
}
//
config.Save(ConfigurationSaveMode.Full);
Console.WriteLine("Saving file: {0}", config.FilePath);
}
App.config used:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatabaseName" value="databaseName"/>
<add key="DatabaseUser" value="databaseUser"/>
<add key="DatabasePassword" value="databasePwd"/>
<add key="Port" value="port"/>
<add key="LogDirectory" value="logDirectory"/>
<add key="LogLevel" value="strLogLevel"/>
</appSettings>
<connectionStrings>
<add name="SecurePassDataBase" connectionString="Data Source=D-xxxx;Initial Catalog=DEMO;User ID=sa;Password=******" />
</connectionStrings>
</configuration>
here is a very simple code you can use
RsaProtectedConfigurationProvider Sample
Made some small modifications...
static public void ProtectSection()
{
// Get the current configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
// Get the section.
ConfigurationSection section = config.GetSection("appSettings");
// Protect (encrypt)the section.
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
// Save the encrypted section.
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
// Display decrypted configuration
// section. Note, the system
// uses the Rsa provider to decrypt
// the section transparently.
string sectionXml = section.SectionInformation.GetRawXml();
Console.WriteLine("Decrypted section:");
Console.WriteLine(sectionXml);
}
Try this & you'll get what you want :
Console.WriteLine(ConfigurationManager.OpenExeConfiguration(Path.GetFileName(Assembly.GetExecutingAssembly().CodeBase).ToString()).FilePath.ToString());
string[] readText = File.ReadAllLines(ConfigurationManager.OpenExeConfiguration(Path.GetFileName(Assembly.GetExecutingAssembly().CodeBase).ToString()).FilePath.ToString());
foreach (string s in readText)
{
Console.WriteLine(s);
}

Can not read Config File

I have a config file in my project, which I am not able to read in for some reason. Similar code has worked for me in the past. I am not sure what am I doing wrong here. I was wondering if someone would be able to have a look and let me know if I am doing something wrong. Please help...
Here's my code:
KeyValueConfigurationCollection settings;
Configuration config;
ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = "myProject.exe.config";
config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
settings = config.AppSettings.Settings;
this.logFilePath = settings["logFilePath"].Value;
this.logFilePath = settings["logFileName"].Value;
Here's my Config File:
<?xml version="1.0"?/>
<configuration>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
</configuration>
Thanks in advance,
Harit
harit, try amending your structure to:
<?xml version="1.0"?/>
<configuration>
<appSettings>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
<appSettings>
</configuration>
Using the ConfigurationManager creates the requirement for this exact structure to be present. it should work as planned with the above change.
The AppSettings Collection is missing from your configuration. You only have the root-level of configured. But you are requesting in your code.
Your configuration should be
<configuration>
<appSettings>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
</appSettings>
</configuration>
Read values from different web.config:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = AppDomain.CurrentDomain.BaseDirectory + #"second.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap,ConfigurationUserLevel.None);
ConfigurationSection mySection = config.GetSection("countoffiles");
if (config.AppSettings.Settings.Count > 0)
{
System.Configuration.KeyValueConfigurationElement customSetting =
config.AppSettings.Settings["countoffiles"];
if (customSetting != null)
{
Response.Write(customSetting.Value);
}
else
{
Console.WriteLine("No countoffiles application string");
}
}

Write to just one XML attribute without affecting the rest

I have the following but its not working for me:
static void SaveVersion(string configFile, string Version)
{
XmlDocument config = new XmlDocument();
config.Load(configFile);
XmlNode appSettings = config.SelectSingleNode("configuration/appSettings");
XmlNodeList appKids = appSettings.ChildNodes;
foreach (XmlNode setting in appKids)
{
if (setting.Attributes["key"].Value == "AgentVersion")
setting.Attributes["value"].Value = Version;
}
config.Save(configFile);
}
The config file i'm loading up on config.Load(configFile) is the following:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v2.0.50727" />
</startup>
<appSettings>
<add key="AgentVersion" value="2.0.5" />
<add key="ServerHostName" value="" />
<add key="ServerIpAddress" value="127.0.0.1" />
<add key="ServerPort" value="9001" />
</appSettings>
</configuration>
Am I missing something? I figured it would edit just that particular attribute AgentVersion but its not really doing anything.
Are you aware of the ConfigurationManager class? You can use it to manipulate your app.config file without doing anything manually. I don't think you should reinvent the wheel unless you have a good reason to:
static void SaveVersion(string configFile, string version)
{
var myConfig = ConfigurationManager.OpenExeConfiguration(configFile);
myConfig.AppSettings.Settings["AgentVersion"].Value = version;
myConfig.Save();
}
Try this:
static void SaveVersion(string configFile, string Version)
{
var config = new XmlDocument();
config.Load(configFile);
var agentVersionElement = config.DocumentElement.SelectSingleNode("configuration/appSettings/add[#key = 'AgentVersion']") as XmlElement;
if (agentVersionElement != null)
agentVersionElement.SetAttribute("value", version);
config.Save(configFile);
}
Note that I'm doing the SelectSingleNode from the DocumentElement, not from the XmlDocument itself.

An error occurred creating the configuration section handler

I have a dot.NET 4.0 web application with a custom section defined:
<configuration>
<configSections>
<section name="registrations" type="System.Configuration.IgnoreSectionHandler, System.Configuration, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>
....
at the end of the web.config file I have the respective section:
....
<registrations>
.....
</registrations>
</configuration>
Every time I call System.Configuration.ConfigurationManager.GetSection("registrations"); I get the following exception:
An error occurred creating the configuration section handler for registrations: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047) (C:\...\web.config line 13)
I'm also using Unity but don't know if that's in any way related to the error.
Have you faced this error before? How can I fix it? Do I need to replace the IgnoreSectionHandler with something else?
Given this app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="registrations" type="MyApp.MyConfigurationSection, MyApp" />
</configSections>
<registrations myValue="Hello World" />
</configuration>
Then try using this:
namespace MyApp
{
class Program
{
static void Main(string[] args) {
var config = ConfigurationManager.GetSection(MyConfigurationSection.SectionName) as MyConfigurationSection ?? new MyConfigurationSection();
Console.WriteLine(config.MyValue);
Console.ReadLine();
}
}
public class MyConfigurationSection : ConfigurationSection
{
public const String SectionName = "registrations";
[ConfigurationProperty("myValue")]
public String MyValue {
get { return (String)this["myValue"]; }
set { this["myValue"] = value; }
}
}
}
You are missing the Namespace in the type attribute of your section in App.Config. Infact you dont need the full assembly info in there either. only the namespace is enough
Updated 1
yourcustomconfigclass config =(yourcustomconfigclass)System.Configuration.ConfigurationManager.GetSection(
"registrations");
and in config file only write
<section name="registrations" type="System.Configuration.IgnoreSectionHandler" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>

How to get the values of a ConfigurationSection of type NameValueSectionHandler

I'm working with C#, Framework 3.5 (VS 2008).
I'm using the ConfigurationManager to load a config (not the default app.config file) into a Configuration object.
Using the Configuration class, I was able to get a ConfigurationSection, but I could not find a way to get the values of that section.
In the config, the ConfigurationSection is of type System.Configuration.NameValueSectionHandler.
For what it worth, when I used the method GetSection of the ConfigurationManager (works only when it was on my default app.config file), I received an object type, that I could cast into collection of pairs of key-value, and I just received the value like a Dictionary. I could not do such cast when I received ConfigurationSection class from the Configuration class however.
EDIT:
Example of the config file:
<configuration>
<configSections>
<section name="MyParams"
type="System.Configuration.NameValueSectionHandler" />
</configSections>
<MyParams>
<add key="FirstParam" value="One"/>
<add key="SecondParam" value="Two"/>
</MyParams>
</configuration>
Example of the way i was able to use it when it was on app.config (the "GetSection" method is for the default app.config only):
NameValueCollection myParamsCollection =
(NameValueCollection)ConfigurationManager.GetSection("MyParams");
Console.WriteLine(myParamsCollection["FirstParam"]);
Console.WriteLine(myParamsCollection["SecondParam"]);
Suffered from exact issue. Problem was because of NameValueSectionHandler in .config file. You should use AppSettingsSection instead:
<configuration>
<configSections>
<section name="DEV" type="System.Configuration.AppSettingsSection" />
<section name="TEST" type="System.Configuration.AppSettingsSection" />
</configSections>
<TEST>
<add key="key" value="value1" />
</TEST>
<DEV>
<add key="key" value="value2" />
</DEV>
</configuration>
then in C# code:
AppSettingsSection section = (AppSettingsSection)ConfigurationManager.GetSection("TEST");
btw NameValueSectionHandler is not supported any more in 2.0.
Here's a good post that shows how to do it.
If you want to read the values from a file other than the app.config, you need to load it into the ConfigurationManager.
Try this method: ConfigurationManager.OpenMappedExeConfiguration()
There's an example of how to use it in the MSDN article.
Try using an AppSettingsSection instead of a NameValueCollection. Something like this:
var section = (AppSettingsSection)config.GetSection(sectionName);
string results = section.Settings[key].Value;
Source:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d5079420-40cb-4255-9b3b-f9a41a1f7ad2/
The only way I can get this to work is to manually instantiate the section handler type, pass the raw XML to it, and cast the resulting object.
Seems pretty inefficient, but there you go.
I wrote an extension method to encapsulate this:
public static class ConfigurationSectionExtensions
{
public static T GetAs<T>(this ConfigurationSection section)
{
var sectionInformation = section.SectionInformation;
var sectionHandlerType = Type.GetType(sectionInformation.Type);
if (sectionHandlerType == null)
{
throw new InvalidOperationException(string.Format("Unable to find section handler type '{0}'.", sectionInformation.Type));
}
IConfigurationSectionHandler sectionHandler;
try
{
sectionHandler = (IConfigurationSectionHandler)Activator.CreateInstance(sectionHandlerType);
}
catch (InvalidCastException ex)
{
throw new InvalidOperationException(string.Format("Section handler type '{0}' does not implement IConfigurationSectionHandler.", sectionInformation.Type), ex);
}
var rawXml = sectionInformation.GetRawXml();
if (rawXml == null)
{
return default(T);
}
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(rawXml);
return (T)sectionHandler.Create(null, null, xmlDocument.DocumentElement);
}
}
The way you would call it in your example is:
var map = new ExeConfigurationFileMap
{
ExeConfigFilename = #"c:\\foo.config"
};
var configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var myParamsSection = configuration.GetSection("MyParams");
var myParamsCollection = myParamsSection.GetAs<NameValueCollection>();
This is an old question, but I use the following class to do the job. It's based on Scott Dorman's blog:
public class NameValueCollectionConfigurationSection : ConfigurationSection
{
private const string COLLECTION_PROP_NAME = "";
public IEnumerable<KeyValuePair<string, string>> GetNameValueItems()
{
foreach ( string key in this.ConfigurationCollection.AllKeys )
{
NameValueConfigurationElement confElement = this.ConfigurationCollection[key];
yield return new KeyValuePair<string, string>
(confElement.Name, confElement.Value);
}
}
[ConfigurationProperty(COLLECTION_PROP_NAME, IsDefaultCollection = true)]
protected NameValueConfigurationCollection ConfCollection
{
get
{
return (NameValueConfigurationCollection) base[COLLECTION_PROP_NAME];
}
}
The usage is straightforward:
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
NameValueCollectionConfigurationSection config =
(NameValueCollectionConfigurationSection) configuration.GetSection("MyParams");
NameValueCollection myParamsCollection = new NameValueCollection();
config.GetNameValueItems().ToList().ForEach(kvp => myParamsCollection.Add(kvp));
Here are some examples from this blog mentioned earlier:
<configuration>
<Database>
<add key="ConnectionString" value="data source=.;initial catalog=NorthWind;integrated security=SSPI"/>
</Database>
</configuration>
get values:
NameValueCollection db = (NameValueCollection)ConfigurationSettings.GetConfig("Database");
labelConnection2.Text = db["ConnectionString"];
-
Another example:
<Locations
ImportDirectory="C:\Import\Inbox"
ProcessedDirectory ="C:\Import\Processed"
RejectedDirectory ="C:\Import\Rejected"
/>
get value:
Hashtable loc = (Hashtable)ConfigurationSettings.GetConfig("Locations");
labelImport2.Text = loc["ImportDirectory"].ToString();
labelProcessed2.Text = loc["ProcessedDirectory"].ToString();
Try this;
Credit: https://www.limilabs.com/blog/read-system-net-mailsettings-smtp-settings-web-config
SmtpSection section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp");
string from = section.From;
string host = section.Network.Host;
int port = section.Network.Port;
bool enableSsl = section.Network.EnableSsl;
string user = section.Network.UserName;
string password = section.Network.Password;
This works like a charm
dynamic configSection = ConfigurationManager.GetSection("MyParams");
var theValue = configSection["FirstParam"];

Categories

Resources