save multiple key/value pairs to app.config - c#

I'm working on an winform application, where I store some setting (username, email, zipcode) in the app.config file.
public static void Set(string key, string value)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var entry = config.AppSettings.Settings[key];
if (entry == null)
config.AppSettings.Settings.Add(key, value);
else
config.AppSettings.Settings[key].Value = value;
config.Save(ConfigurationSaveMode.Modified);
}
I'd like to save the settings to the app.config file. So I have this code.
Problem is: I can only use the variable key once.... So i can't saven the email and zipcode.
I was thinking of working with an array, but I have no idea on how to implement this. Any suggestions?
private void button_savesettings_Click(object sender, EventArgs e)
{
string key = "username";
string username = textBox_user.Text;
Set(key, username);
}
Many thanks!

A simple loop will solve the problem
void SetAppSettingsValues(Dictionary<string, string> dict)
{
// bit of validation
if (dict == null || !dict.Any())
return;
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
foreach (var key in dict.Keys)
{
var configItem = config.AppSettings.Settings[key];
if (configItem == null)
config.AppSettings.Settings.Add(key, dict[key].Value);
else
config.AppSettings.Settings[key].Value = dict[key].Value;
}
config.Save(ConfigurationSaveMode.Modified);
}

The better way is to use SQLite for Winform.
Saving things to app.config could be messy when your data variable grows bigger.

Related

Is there a way to call registry ONLY one time and extract various keys values

I am basically reading below registry path,
SOFTWARE\\WOW6432Node\\Microsoft
But I have different sub keys and keys to read.
example
Version under SOFTWARE\\WOW6432Node\\Microsoft\\DataAccess
NodePath9 under SOFTWARE\\WOW6432Node\\Microsoft\\ENROLLMENTS\\ValidNodePaths
etc.
Currently I am able to read it one-by-one, but what are the ways so that I need to go the registry ONLY one time and I can do all other manipulation in C# code?
Can I read all information at once (so that ONLY one call to registry) till SOFTWARE\\WOW6432Node\\Microsoft and do rest work in C# code?
var X1 = GetRegistryValue("SOFTWARE\\WOW6432Node\\Microsoft\\DataAccess", "Version");
var X2 = GetRegistryValue("SOFTWARE\\WOW6432Node\\Microsoft\\ENROLLMENTS\\ValidNodePaths", "NodePath9");
private static string GetRegistryValue(string subKey, string keyName)
{
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(subKey))
{
if (key != null)
{
if (key.GetValue(keyName) != null)
{
return (string)key.GetValue(keyName);
}
}
return null;
}
}
The OpenSubKey() method returns a registry key, so you could create a common one first and then pass it into the GetRegistryValue()...
private static RegistryKey GetCommonKey(string subKey)
{
return Registry.LocalMachine.OpenSubKey(subKey);
}
private static string GetRegistryValue(RegistryKey commonKey, string subKey, string keyName)
{
using (commonKey.OpenSubKey(subKey))
{
if (key != null)
{
if (key.GetValue(keyName) != null)
{
return (string)key.GetValue(keyName);
}
}
return null;
}
}
// usage
var commonKey = GetCommonKey("SOFTWARE\\WOW6432Node\\Microsoft");
var version = GetRegistryValue(commonKey, "DataAccess", "Version");
var nodePath = GetRegistryValue(commonKey, "ENROLLMENTS\\ValidNodePaths", "Version");

ConfigurationErrorsException- The process cannot access the file 'c:\eventlog.config' because it is being used by another process

Team,
I have this piece of code which invariably ties up itself in a sort of race condition especially when two or more resources are trying to write to eventlog.config file simultaneously. I have googling out several channels but not able to solve this error out. Can anyone help me to modify this code so that i can remove the race condition.
private void UpdateLastEventId(IList<EventLogEntry> entries)
{
if (entries.Count > 0)
{
EventLogEntry lastEntry = entries[entries.Count - 1];
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var configSettings = config.AppSettings.Settings;
string key = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", _eventLogFilter.EventLog, _eventLogFilter.MD5Hash);
if (configSettings[key] == null)
{
configSettings.Add(key, lastEntry.Index.ToString(CultureInfo.InvariantCulture));
}
else
{
configSettings[key].Value = lastEntry.Index.ToString(CultureInfo.InvariantCulture);
}
config.Save(ConfigurationSaveMode.Modified);//Error seems to happen here
}
}
private static readonly object _configLogLock = new object();
private void UpdateLastEventId(IList<EventLogEntry> entries)
{
if (entries.Count > 0)
{
EventLogEntry lastEntry = entries[entries.Count - 1];
lock (_configLogLock)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var configSettings = config.AppSettings.Settings;
string key = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", _eventLogFilter.EventLog, _eventLogFilter.MD5Hash);
if (configSettings[key] == null)
{
configSettings.Add(key, lastEntry.Index.ToString(CultureInfo.InvariantCulture));
}
else
{
configSettings[key].Value = lastEntry.Index.ToString(CultureInfo.InvariantCulture);
}
config.Save(ConfigurationSaveMode.Modified);//Error seems to happen here
}
}
}

change entity connection on the fly

I am using C# 4.0. (Winform Application)
I have a code like this:
private bool ChangeEFConnectionString(string connStringName, string newValue)
{
try
{
//CreateXDocument and load configuration file
XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
//Find all connection strings
var query1 = from p in doc.Descendants("connectionStrings").Descendants()
select p;
//Go throught each connection string elements find atribute specified by argument and replace its value with newVAlue
foreach (var child in query1)
{
foreach (var atr in child.Attributes())
{
if (atr.Name.LocalName == "name" && atr.Value == connStringName)
if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
{
// Create the EF connection string from existing
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder(atr.NextAttribute.Value);
//change hte provide conn string
entityBuilder.ProviderConnectionString = newValue;
//back the full connection string to the configuration fiel
atr.NextAttribute.Value = entityBuilder.ToString();
}
}
}
doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
It works well, but somehow it not work any more.
As I debug it : entityBuilder.ProviderConnectionString = newValue; had the right value
but it still not change the connectionstring.
Use ConfigurationManager for reading and updating connection strings:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings[connStringName].ConnectionString = newValue;
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");
I think all you need is, after the Save, a:
ConfigurationManager.RefreshSection("connectionStrings");
Have you considered giving EF the whole connection string instead of the name? That would keep you from having to modify what the name means at run time.

Get Connection String Without Password Value in C#

I try create method for get the connection string value but without value for password, or show password like * character. I need used it in logging.
I use ConnectionStringBuilder for Oracle, SqlServer.
Anyway, another way -better- to implement it ? Maybe more generic . And what it happens it ProviderName is empty...
public static string GetConnectionStringWithouPassword(this ConnectionStringSettings cs)
{
if (cs == null || string.IsNullOrEmpty(cs.ConnectionString)) return null;
if (cs.ProviderName.ToLower().Equals("Oracle.DataAccess.Client".ToLower()))
{
var builderOra = new Oracle.DataAccess.Client.OracleConnectionStringBuilder(cs.ConnectionString);
return "";
}
if (cs.ProviderName.ToLower().Equals("System.Data.SqlClient".ToLower()))
{
var builderSql = new SqlConnectionStringBuilder(cs.ConnectionString);
return "";
}
return null;
}
//
public static string ObtenerCadenasConexion()
{
var sb = new StringBuilder();
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
if (settings != null)
{
foreach (ConnectionStringSettings cs in settings)
{
sb.AppendLine("Name: " + cs.Name);
sb.AppendLine("ProviderName: " + cs.ProviderName);
sb.AppendLine("ConnectionString: " + cs.GetConnectionStringWithouPassword() + Environment.NewLine);
}
}
return sb.ToString();
}
check this one: DbConnectionStringBuilder Class
you can use the Remove method, no magic parsing required:
for example, from that MSDN page:
static void Main()
{
DbConnectionStringBuilder builder = new
DbConnectionStringBuilder();
builder.ConnectionString =
#"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Demo.mdb;" +
"Jet OLEDB:System Database=system.mdw;";
// Try to remove an existing item.
TryRemove(builder, "Provider");
// Try to remove a nonexistent item.
TryRemove(builder, "User ID");
// Try to remove an existing item,
// demonstrating that the search isn't
// case sensitive.
TryRemove(builder, "DATA SOURCE");
Console.ReadLine();
}
static void TryRemove(DbConnectionStringBuilder builder, string itemToRemove)
{
if (builder.Remove(itemToRemove))
{
Console.WriteLine(#"Removed '{0}'", itemToRemove);
}
else
{
Console.WriteLine(#"Unable to remove '{0}'", itemToRemove);
}
Console.WriteLine(builder.ConnectionString);
}
Check the Connection.PersistSecurityInfo property, you may drop this information as soon as the connection is created automatically.

Iterate through registry entries

As suggested here, I need to iterate through entries in
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
to find out the installed path of my application. How to iterate so that I can find out the
InstallLocation value given the DisplayName. How to do it efficiently in C#.
Below is code to achieve your goal:
using Microsoft.Win32;
class Program
{
static void Main(string[] args)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
foreach (var v in key.GetSubKeyNames())
{
Console.WriteLine(v);
RegistryKey productKey = key.OpenSubKey(v);
if (productKey != null)
{
foreach (var value in productKey.GetValueNames())
{
Console.WriteLine("\tValue:" + value);
// Check for the publisher to ensure it's our product
string keyValue = Convert.ToString(productKey.GetValue("Publisher"));
if (!keyValue.Equals("MyPublisherCompanyName", StringComparison.OrdinalIgnoreCase))
continue;
string productName = Convert.ToString(productKey.GetValue("DisplayName"));
if (!productName.Equals("MyProductName", StringComparison.OrdinalIgnoreCase))
return;
string uninstallPath = Convert.ToString(productKey.GetValue("InstallSource"));
// Do something with this valuable information
}
}
}
Console.ReadLine();
}
}
Edit: See this method for a more comprehensive way to find an Applications Install Path, it demonstrates the using disposing as suggested in the comments.
https://stackoverflow.com/a/26686738/495455
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(#"Whater\The\Key"))
{
if (key != null)
{
foreach (string ValueOfName in key.GetValueNames())
{
try
{
bool Value = bool.Parse((string)key.GetValue(ValueOfName));
}
catch (Exception ex) {}
}
}
}
With a bool cast :D - so the string is expected to be True or False.
For the user registry hive use Registry.CurrentUser instead of Registry.LocalMachine

Categories