I'm reading values from an app.config file. After some changes have been made, I'm saving the configuration. Problem is that the changes are being written to a different file.
Values are being read from GeoBagHostingService.exe.config.
Changes are being written to GeoBagService.dll.config
My solution contains 2 projects: GeoBagHostingService and GeoBagService so that's probably where things get mixed up.
Functionally what I want to do is to replace a password value with an encrypted value. So if config contains a "password" key I replace it with a "encryptedPassword" key containing the encrypted password value.
The code I'm using is contained in a class in de GeoBAGService project.
To read, modify and save the configuration I use:
// Opening the configuration (GeoBagHostingService.exe.config)
Configuration configuration = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
var oraclePassword = ConfigurationManager.AppSettings["oraclePassword"];
if (!string.IsNullOrWhiteSpace(oraclePassword))
{
string encryptedPassword = EncryptString(oraclePassword, configPassword);
configuration.AppSettings.Settings.Remove("oraclePassword");
configuration.AppSettings.Settings.Remove("encryptedPassword");
configuration.AppSettings.Settings.Add("encryptedPassword", encryptedPassword);
// Writing back the changes (or so I thought)
// encryptedPassword is now in GeoBagService.dll.config
configuration.Save();
}
else
{
oraclePassword = DecryptString(ConfigurationManager.AppSettings["encryptedpassword"], configPassword);
}
What's happening here and how to write the changes to the same configuration as from where they are being read?
The result of Assembly.GetExecutingAssembly().Location depends on the place where you call it from.
If you call it in your main project (application), then it will return:
[MainProjectPath]\[MainProjectName].exe
If you call it from another project (class library), then it will return:
[LibProjectPath]\[LibProjectName].dll
That's why you're getting those results.
I want to set a cache limit for my C# program so I decided to use the Project Properties>Settings function of Visual Studio [2015] to do so.
I had some help and was told to enter this.
My settings I want are as follows:
Folder Path- C:\SysApp
Size Limit- 150MB
Amount to Delete- 149MB
For the sizeLimit and toDelete sections I need to know what unit (ie. bytes, megabytes, kilobytes...) they're in so I can convert them to what I listed above.
I was also told that
If you change the settings value in the program you need to save the new values before exiting the application. This is done with Properties.Settings.Default.Save();. This command creates a .config file with your values.
I need to know where in my coding to insert the Properties.Settings.Default.Save(); command.
Screenshots would be very helpful. Thanks.
The is no possibility to store metadata like units into default settings. You have to define the unit (kB, MB,...) the user should enter or store it as a string (e.g. 150MB) and parse it yourself.
The Save method must be called after setting the values (example):
Properties.Settings.Default.sizeLimit = 150000
Properties.Settings.Default.Save();
If you only want to read the settings (see comments below) change the scope of the settings from "User" to "Application" and read the settings in your program like this:
class Program {
void main(string args[]) {
String folderPath = Properties.Setings.Default.folder;
int folderSizeLimit = Properties.Setings.Default.sizeLimit;
int amountToDelete = Properties.Setings.Default.toDelete;
DeleteOldFilesIfOverFolderLimit(folderPath, folderSizeLimit, amountToDelete);
}
private private void DeleteOldFilesIfOverFolderLimit(string folderPath,
long folderSizeLimit,
long amountToDelete)
...... from other post .....
}
}
How can I setup support for per (roaming) user configuration settings for a particular plugin .DLL loaded from another application?
I have a .DLL that is loaded as add-in/plugin from another application, and want to persist configuration settings particular for this one independently of the main application that loads it, based on machine, .dll (=executable), roaming user or user profile.
I have found the System.Configuration.ExeConfigurationFileMap class that looks likely to provide what I need, but I can't figure out how to setup the right paths specific for my (plugin) application.
What code I have so far is:
public class MyConfigurationSettings : ConfigurationSection
{
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
string configFile = Assembly.GetAssembly(typeof(MyConfigurationSettings)).Location + ".config";
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = configFile;
configFileMap.LocalUserConfigFilename = <localUserConfigFile>; // ??? What filename to place here and how to get it based on the current environment ???
configFileMap.RoamingUserConfigFilename = <roamingUserConfigFile>; // ???;
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigLevel);
// ...
}
}
Can anyone point me into the right direction? The available documentation and search results are too confusing or insufficient for me to get this right. Sorry , if this seems to be a silly question, but my C# (.NET) skills are going to get rusty after 4+ years not using it for earning daily bread.
I also believe it's not primarily an issue about configuration settings management, but how to get paths for installation specific application instance configurations.
You set RoamingUserConfigFilename = RoamingName.config and put it under Roaming Profile:
%AppData%\[AppName]\[Vendor]\[CodedPath]\[Version]\RoamingName.config
Also you set LocalUserConfigFilename = LocalName.config and put it under Local Profile:
%LocalAppData%\[AppName]\[Vendor]\[CodedPath]\[Version]\LocalName.config
Now calling
ConfigurationManager.OpenMappedExeConfiguration(
exeMap,
ConfigurationUserLevel.PerUserRoamingAndLocal);
config will be read in the following order:
Source on MSDN blogs.
For samples search for User.config under c:\Users\[User]\AppData. Also see CP article.
Code Sample:
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
try
{
string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, #"MyCompany\MyPlugin\Default.config");
exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, #"MyCompany\MyPlugin\Roaming.config");
exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, #"MyCompany\MyPlugin\Local.config");
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel);
return (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings");
}
catch (Exception ex) {
// ...
}
return null; // or throw an appropriate exception
}
Generally load the configuration from the special folder where you put it in and put it into one of the roaming (i.e. non local) locations. The OS handles the rest as per roaming specifications.
The usage of ConfigSections is totally irrelevant unless there is a very very special need to use the config file for that. In any .NET project I have seen in the last 10 years this file was never used for user specific settings.
What approach do you recommend for persisting user settings in a WPF windows (desktop) application? Note that the idea is that the user can change their settings at run time, and then can close down the application, then when starting up the application later the application will use the current settings. Effectively then it will appear as if the application settings do not change.
Q1 - Database or other approach? I do have a sqlite database that I will be using anyway hence using a table in the database would be as good as any approach?
Q2 - If Database: What database table design? One table with columns for different data types that one might have (e.g. string, long, DateTime etc) OR just a table with a string for the value upon which you have to serialize and de-serialize the values? I'm thinking the first would be easier, and if there aren't many settings the overhead isn't much?
Q3 - Could Application Settings be used for this? If so are there any special tasks required to enable the persistence here? Also what would happen regarding usage of the "default" value in the Application Settings designer in this case? Would the default override any settings that were saved between running the application? (or would you need to NOT use the default value)
You can use Application Settings for this, using database is not the best option considering the time consumed to read and write the settings(specially if you use web services).
Here are few links which explains how to achieve this and use them in WPF -
User Settings in WPF
Quick WPF Tip: How to bind to WPF application resources and settings?
A Configurable Window for WPF
Update: Nowadays I would use JSON.
I also prefer to go with serialization to file. XML files fits mostly all requirements. You can use the ApplicationSettings build in but those have some restrictions and a defined but (for me) very strange behavior where they stored. I used them a lot and they work. But if you want to have full control how and where they stored I use another approach.
Make a class Somewhere with all your settings. I named it MySettings
Implement Save and Read for persistence
Use them in you application-code
Advantages:
Very Simple approach.
One Class for Settings. Load. Save.
All your Settings are type safe.
You can simplify or extend the logic to your needs (Versioning, many Profiles per User, etc.)
It works very well in any case (Database, WinForms, WPF, Service, etc...)
You can define where to store the XML files.
You can find them and manipulate them either by code or manual
It works for any deployment method I can imagine.
Disadvantages:
- You have to think about where to store your settings files. (But you can just use your installation folder)
Here is a simple example (not tested)-
public class MySettings
{
public string Setting1 { get; set; }
public List<string> Setting2 { get; set; }
public void Save(string filename)
{
using (StreamWriter sw = new StreamWriter(filename))
{
XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
xmls.Serialize(sw, this);
}
}
public MySettings Read(string filename)
{
using (StreamReader sw = new StreamReader(filename))
{
XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
return xmls.Deserialize(sw) as MySettings;
}
}
}
And here is how to use it. It's possible to load default values or override them with the user's settings by just checking if user settings exist:
public class MyApplicationLogic
{
public const string UserSettingsFilename = "settings.xml";
public string _DefaultSettingspath =
Assembly.GetEntryAssembly().Location +
"\\Settings\\" + UserSettingsFilename;
public string _UserSettingsPath =
Assembly.GetEntryAssembly().Location +
"\\Settings\\UserSettings\\" +
UserSettingsFilename;
public MyApplicationLogic()
{
// if default settings exist
if (File.Exists(_UserSettingsPath))
this.Settings = Settings.Read(_UserSettingsPath);
else
this.Settings = Settings.Read(_DefaultSettingspath);
}
public MySettings Settings { get; private set; }
public void SaveUserSettings()
{
Settings.Save(_UserSettingsPath);
}
}
maybe someone get's inspired by this approach. This is how I do it now for many years and I'm quite happy with that.
You can store your settings info as Strings of XML in the Settings.Default. Create some classes to store your configuration data and make sure they are [Serializable]. Then, with the following helpers, you can serialize instances of these objects--or List<T> (or arrays T[], etc.) of them--to String. Store each of these various strings in its own respective Settings.Default slot in your WPF application's Settings.
To recover the objects the next time the app starts, read the Settings string of interest and Deserialize to the expected type T (which this time must be explcitly specified as a type argument to Deserialize<T>).
public static String Serialize<T>(T t)
{
using (StringWriter sw = new StringWriter())
using (XmlWriter xw = XmlWriter.Create(sw))
{
new XmlSerializer(typeof(T)).Serialize(xw, t);
return sw.GetStringBuilder().ToString();
}
}
public static T Deserialize<T>(String s_xml)
{
using (XmlReader xw = XmlReader.Create(new StringReader(s_xml)))
return (T)new XmlSerializer(typeof(T)).Deserialize(xw);
}
The long running most typical approach to this question is: Isolated Storage.
Serialize your control state to XML or some other format (especially easily if you're saving Dependency Properties with WPF), then save the file to the user's isolated storage.
If you do want to go the app setting route, I tried something similar at one point myself...though the below approach could easily be adapted to use Isolated Storage:
class SettingsManager
{
public static void LoadSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
{
EnsureProperties(sender, savedElements);
foreach (FrameworkElement element in savedElements.Keys)
{
try
{
element.SetValue(savedElements[element], Properties.Settings.Default[sender.Name + "." + element.Name]);
}
catch (Exception ex) { }
}
}
public static void SaveSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
{
EnsureProperties(sender, savedElements);
foreach (FrameworkElement element in savedElements.Keys)
{
Properties.Settings.Default[sender.Name + "." + element.Name] = element.GetValue(savedElements[element]);
}
Properties.Settings.Default.Save();
}
public static void EnsureProperties(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
{
foreach (FrameworkElement element in savedElements.Keys)
{
bool hasProperty =
Properties.Settings.Default.Properties[sender.Name + "." + element.Name] != null;
if (!hasProperty)
{
SettingsAttributeDictionary attributes = new SettingsAttributeDictionary();
UserScopedSettingAttribute attribute = new UserScopedSettingAttribute();
attributes.Add(attribute.GetType(), attribute);
SettingsProperty property = new SettingsProperty(sender.Name + "." + element.Name,
savedElements[element].DefaultMetadata.DefaultValue.GetType(), Properties.Settings.Default.Providers["LocalFileSettingsProvider"], false, null, SettingsSerializeAs.String, attributes, true, true);
Properties.Settings.Default.Properties.Add(property);
}
}
Properties.Settings.Default.Reload();
}
}
.....and....
Dictionary<FrameworkElement, DependencyProperty> savedElements = new Dictionary<FrameworkElement, DependencyProperty>();
public Window_Load(object sender, EventArgs e) {
savedElements.Add(firstNameText, TextBox.TextProperty);
savedElements.Add(lastNameText, TextBox.TextProperty);
SettingsManager.LoadSettings(this, savedElements);
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
SettingsManager.SaveSettings(this, savedElements);
}
Apart from a database, you can also have following options to save user related settings
registry under HKEY_CURRENT_USER
in a file in AppData folder
using Settings file in WPF and by setting its scope as User
In my experience storing all the settings in a database table is the best solution. Don't even worry about performance. Today's databases are fast and can easily store thousands columns in a table. I learned this the hard way - before I was serilizing/deserializing - nightmare. Storing it in local file or registry has one big problem - if you have to support your app and computer is off - user is not in front of it - there is nothing you can do.... if setings are in DB - you can changed them and viola not to mention that you can compare the settings....
You can use SQLite, a small, fast, self-contained, full-featured, SQL database engine. I personally recommend it after trying settings file and XML file approach.
Install NuGet package System.Data.SQLite
which is an ADO.NET provider for SQLite.
The package includes support for LINQ and Entity Framework
Overall you can do many things with such supporting features to your settings window.
1.Install SQLite
2.Create your database file
3.Create tables to save your settings
4.Access database file in your application to read and edit settings.
I felt this approach very much helpful for application settings, since i can do adjustments to database and also take advantage of ADO.Net and LINQ features
I typically do this sort of thing by defining a custom [Serializable] settings class and simply serializing it to disk. In your case you could just as easily store it as a string blob in your SQLite database.
In all the places I've worked, database has been mandatory because of application support. As Adam said, the user might not be at his desk or the machine might be off, or you might want to quickly change someone's configuration or assign a new-joiner a default (or team member's) config.
If the settings are likely to grow as new versions of the application are released, you might want to store the data as blobs which can then be deserialized by the application. This is especially useful if you use something like Prism which discovers modules, as you can't know what settings a module will return.
The blobs could be keyed by username/machine composite key. That way you can have different settings for every machine.
I've not used the in-built Settings class much so I'll abstain from commenting. :)
I wanted to use an xml control file based on a class for my VB.net desktop WPF application. The above code to do this all in one is excellent and set me in the right direction. In case anyone is searching for a VB.net solution here is the class I built:
Imports System.IO
Imports System.Xml.Serialization
Public Class XControl
Private _person_ID As Integer
Private _person_UID As Guid
'load from file
Public Function XCRead(filename As String) As XControl
Using sr As StreamReader = New StreamReader(filename)
Dim xmls As New XmlSerializer(GetType(XControl))
Return CType(xmls.Deserialize(sr), XControl)
End Using
End Function
'save to file
Public Sub XCSave(filename As String)
Using sw As StreamWriter = New StreamWriter(filename)
Dim xmls As New XmlSerializer(GetType(XControl))
xmls.Serialize(sw, Me)
End Using
End Sub
'all the get/set is below here
Public Property Person_ID() As Integer
Get
Return _person_ID
End Get
Set(value As Integer)
_person_ID = value
End Set
End Property
Public Property Person_UID As Guid
Get
Return _person_UID
End Get
Set(value As Guid)
_person_UID = value
End Set
End Property
End Class
In my application, I need to change some value ("Environment") in appSetting of app.config at runtime.
I use AppSettingsReader
private static AppSettingsReader _settingReader;
public static AppSettingsReader SettingReader
{
get
{
if (_settingReader == null)
{
_settingReader = new AppSettingsReader();
}
return _settingReader;
}
}
Then at some stage I do this
config.AppSettings.Settings[AppSettingString.Environment.ToString()].Value = newEnvironment.ToString();
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
However, next time I try to read "Environment" like this
string environment = (string)SettingReader.GetValue(AppSettingString.Environment.ToString(), typeof(System.String));
I end up with the old value of Environment.
I noticed that I can fix this by doing
_settingReader = new AppSettingsReader();
before I read "Environment".
But I think creating a new instance is not the proper approach.
Maybe there is a way to let my SettingReader know, that the values have changed to use the same instance of it, but with refreshed values?
(Not a project-breaking question obviously, more of an educational one)
AppSettingsReader doesn't seem to have any method to reload from disk. It just derives from Object. Creating a new instance seems to be the only thing that would work... I may be wrong, but AppSettings are supposed to be read-only values for your app. More like configuration parameters for your application that can be tweaked before startup.
For read-write application settings, I think the Settings mechanism with IDE support (System.Configuration.ApplicationSettingsBase) would be the preferred approach. This has Save and Reload methods. The designer-gen class makes the code far more readable too..
Double click on the Properties Node under your Project in Solution Explorer. Find the Settings tab.
Instead of
sEnvironment = (string)SettingReader.GetValue(AppSettingString.Environment.ToString(), typeof(System.String));
you could have typed properties like
sEnvironment = Properties.Settings.Default.Environment;
The designer generated class exposes a synchronized singleton instance via the Default property.. which should mean you don't need to reload.. you'd always get the latest value within the application.
Upgrade is the function you are looking for
System.Configuration.ApplicationSettingsBase.Upgrade
System.Configuration.ApplicationSettingsBase.Reload