unable to save settings in app.exe.config - c#

i am facing one problem.
i want to save settings in app.config file
i wrote separate class and defined section in config file..
but when i run the application. it does not save the given values into config file
here is SettingsClass
public class MySetting:ConfigurationSection
{
private static MySetting settings = ConfigurationManager.GetSection("MySetting") as MySetting;
public override bool IsReadOnly()
{
return false;
}
public static MySetting Settings
{
get
{
return settings;
}
}
[ConfigurationProperty("CustomerName")]
public String CustomerName
{
get
{
return settings["CustomerName"].ToString();
}
set
{
settings["CustomerName"] = value;
}
}
[ConfigurationProperty("EmailAddress")]
public String EmailAddress
{
get
{
return settings["EmailAddress"].ToString();
}
set
{
settings["EmailAddress"] = value;
}
}
public static bool Save()
{
try
{
System.Configuration.Configuration configFile = Utility.GetConfigFile();
MySetting mySetting = (MySetting )configFile.Sections["MySetting "];
if (null != mySetting )
{
mySetting .CustomerName = settings["CustomerName"] as string;
mySetting .EmailAddress = settings["EmailAddress"] as string;
configFile.Save(ConfigurationSaveMode.Full);
return true;
}
return false;
}
catch
{
return false;
}
}
}
and this is the code from where i am saving the information in config file
private void SaveCustomerInfoToConfig(String name, String emailAddress)
{
MySetting .Settings.CustomerName = name;
MySetting .Settings.EmailAddress = emailAddress
MySetting .Save();
}
and this is app.config
<configuration>
<configSections>
<section name="MySettings" type="TestApp.MySettings, TestApp"/>
</configSections>
<MySettings CustomerName="" EmailAddress="" />
</configuration>
can u tell me where is the error.. i tried alot and read from internet. but still unable to save information in config file..
i ran the application by double clicking on exe file also.

According to the MSDN: ConfigurationManager.GetSection Method,
The ConfigurationManager.GetSection method accesses run-time configuration information that it cannot change. To change the configuration, you use the Configuration.GetSection method on the configuration file that you obtain by using one of the following Open methods:
OpenExeConfiguration
OpenMachineConfiguration
OpenMappedExeConfiguration
However, if you want to update app.config file, I would read it as an xml document and manipulate it as a normal xml document.
Please see the following example:
Note: this sample is just for proof-of-concept. Should not be used in production as it is.
using System;
using System.Linq;
using System.Xml.Linq;
namespace ChangeAppConfig
{
class Program
{
static void Main(string[] args)
{
MyConfigSetting.CustomerName = "MyCustomer";
MyConfigSetting.EmailAddress = "MyCustomer#Company.com";
MyConfigSetting.TimeStamp = DateTime.Now;
MyConfigSetting.Save();
}
}
//Note: This is a proof-of-concept sample and
//should not be used in production as it is.
// For example, this is not thread-safe.
public class MyConfigSetting
{
private static string _CustomerName;
public static string CustomerName
{
get { return _CustomerName; }
set
{
_CustomerName = value;
}
}
private static string _EmailAddress;
public static string EmailAddress
{
get { return _EmailAddress; }
set
{
_EmailAddress = value;
}
}
private static DateTime _TimeStamp;
public static DateTime TimeStamp
{
get { return _TimeStamp; }
set
{
_TimeStamp = value;
}
}
public static void Save()
{
XElement myAppConfigFile = XElement.Load(Utility.GetConfigFileName());
var mySetting = (from p in myAppConfigFile.Elements("MySettings")
select p).FirstOrDefault();
mySetting.Attribute("CustomerName").Value = CustomerName;
mySetting.Attribute("EmailAddress").Value = EmailAddress;
mySetting.Attribute("TimeStamp").Value = TimeStamp.ToString();
myAppConfigFile.Save(Utility.GetConfigFileName());
}
}
class Utility
{
//Note: This is a proof-of-concept and very naive code.
//Shouldn't be used in production as it is.
//For example, no null reference checking, no file existence checking and etc.
public static string GetConfigFileName()
{
const string STR_Vshostexe = ".vshost.exe";
string appName = Environment.GetCommandLineArgs()[0];
//In case this is running under debugger.
if (appName.EndsWith(STR_Vshostexe))
{
appName = appName.Remove(appName.LastIndexOf(STR_Vshostexe), STR_Vshostexe.Length) + ".exe";
}
return appName + ".config";
}
}
}
I also added "TimeStamp" attribute to MySettings in app.config to check the result easily.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="MySettings" type="TestApp.MySettings, TestApp"/>
</configSections>
<MySettings CustomerName="" EmailAddress="" TimeStamp=""/>
</configuration>

In many cases (in a restricted user scenario) the user do not have write access directly to the application config file. To come around this, you need to use the usersettings.
If you right-click your project and select the tab named "Settings", you can make a list of settings that are stored with the config file. If you select the "Scope" to be "User", the setting are automatically stored in the config file using a type that will automatically store the settings under the users AppData area, where the user allways has write access. The settings are also automatically provided as properties created in the Properties\Settings.Designer.cs code file, and are accessible in your code in Properties.Settings.Default .
Example:
Let's say you add a user setting called CustomerName:
On loading the app, you would want to retreive the value from the stored setting ( either default value as it is in the app config, or if it is stored for this user, the config file for the user):
string value = Properties.Settings.Default.CustomerName;
When you want to change the value, just write to it:
Properties.Settings.Default.CustomerName = "John Doe";
When you want to save all the settings, just call Save:
Properties.Settings.Default.Save();
Note that when you develop, the user file will occationally be reset to the default, but this only happens when building the app. When you just run the app, the settings you store will be read from the user-config file for the app.
If you still want to create your own handling of the settings, you can try this once, and look at what VisualStudio has automatically created for you to get an idea of what you need to get this working.

In order to actually update the config file, you'll need to call .Save() on the Configuration object - not just your config section object.
You should check out Jon Rista's three-part series on .NET 2.0 configuration up on CodeProject.
Unraveling the mysteries of .NET 2.0 configuration
Decoding the mysteries of .NET 2.0 configuration
Cracking the mysteries of .NET 2.0 configuration
Highly recommended, well written and extremely helpful! It shows all the ins and outs of dealing with .NET 2.0 and up configuration, and helped me very much getting a grasp on the subject.
Marc

Be aware that the appname.vshost.exe.Config is reverted to it's the original state at the end of the debugging session. So you might be saving to the file (you can check by using Notepad during execution), then losing the saved contents when the debugging stops.

Related

C# - Storing struct(s) in setting file

I only wanted to store some main configuration in a settings file, since the configuration may change any time.
The users of my application will be able to manage some stuff in several environments.
Each environment has its own configuration (Paths to network locations basicly).
I built an struct for each environment, but now we have to add some more environments, so it is helpful to store that configuration outside of the source code.
So, let me give you some code. I built two structs to describe each environment:
public struct env_conf
{
string title;
string path_to_xml;
string path_to_sharepoint;
List<subfolder> subfolders;
//Some more strings
public env_conf(string title, string path_to_xml, string path_to_sharepoint ...)
{
//Constructor which is setting the variables
}
}
public struct subfolder
{
string folder;
bool is_standard;
public env_conf(string folder, bool is_standard)
{
//Constructor which is setting the variables
}
}
And this is how the environment configs are set up:
var finance_conf = new env_conf("MyTitle","MyXMLPath","MySPPath",
new List<subfolder>{new subfolder("MySubFolder",true);new subfolder("MySubFolder2",false)}
);
var sales_conf = new env_conf("MySalesTitle","MySalesXMLPath","MySalesSPPath",
new List<subfolder>{new subfolder("MySalesSubFolder",true);new subfolder("MySalesSubFolder2",false)}
);
This last step - the definition of the config-instances shall now be inside of a settings file.
Saving string and also string[] in settings file was no problem for me so far. But now I have more than that...
More than that, I do NOT have Visual Studio. I work with SharpDevelop, which was very good so far.
Marking my structs as serializable was not helpful. Also, when I manually set the type of the setting to MyNamespace.env_conf, it wont appear in the settings designer - only a "?" appears in the Type-field.
So for now, I don't know how to proceed. Also, all the info I find in the internet doesn't seem to help me. Please help me.
How has my XML settings file to be edited?
How has my source code to be edited?
Greetings!
I would do it by creating serializable classes, then you can deserialize the config file to an instance of your class, and you'll have all the settings.
For example, the classes might look like:
[Serializable]
public class EnvironmentConfig
{
public string Title { get; set; }
public string XmlPath { get; set; }
public string SharepointPath { get; set; }
public List<SubFolder> SubFolders { get; set; }
public override string ToString()
{
return $"{Title}: {XmlPath}, {SharepointPath}, {string.Join(", ", SubFolders.Select(s => s.Folder))}";
}
}
[Serializable]
public class SubFolder
{
public string Folder { get; set; }
public bool IsStandard { get; set; }
}
And then in code, you can create an instance of your class, give it some values, and serialize it to a config file. Later, you can deserialize this file to load any changes your users may have made.
This example creates a default config and displays the values to the console. Then it gives the user a chance to modify the file, and displays the new values.
// Create a default config
var defaultEnvCfg = new EnvironmentConfig
{
Title = "USWE Environment",
XmlPath = #"\\server\share\xmlfiles",
SharepointPath = #"\\server\sites\enterpriseportal\documents",
SubFolders = new List<SubFolder>
{
new SubFolder { Folder = "Folder1", IsStandard = true },
new SubFolder { Folder = "Folder2", IsStandard = false }
}
};
// Display original values:
Console.WriteLine(defaultEnvCfg.ToString());
// Serialize the config to a file
var pathToEnvCfg = #"c:\public\temp\Environment.config";
var serializer = new XmlSerializer(defaultEnvCfg.GetType());
using (var writer = new XmlTextWriter(
pathToEnvCfg, Encoding.UTF8) { Formatting = Formatting.Indented })
{
serializer.Serialize(writer, defaultEnvCfg);
}
// Prompt user to change the file
Console.Write($"Please modify the file then press [Enter] when done: {pathToEnvCfg}");
Console.ReadLine();
// Deserialize the modified file and update our object with the new settings
using (var reader = XmlReader.Create(pathToEnvCfg))
{
defaultEnvCfg = (EnvironmentConfig)serializer.Deserialize(reader);
}
// Display new values:
Console.WriteLine(defaultEnvCfg.ToString());
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();

App config in Class library C#

I have a wpf application which is using a dll of a class library. I am unable to access the app.config value in the class library
How I'm trying to access app.config:
ConfigurationSettings.AppSettings["conStr"].ToString();
this is returning a null value
using System.Configuration is also added .
Why don't you just put that value in the Main Project ?
If you're calling the class library from the Main Project. Then the code in the class library uses the AppConfig defined inside the main project.
It is a common practice to have the connection string in the AppConfig for the Main Project and not inside the Class Library.
I recomend to use your own class for save Class Library settings. Something like this:
public class GlobalSettings
{
public double RedFiber { get; set; }
public double GreenFiber { get; set; }
public double BlueFiber { get; set; }
public bool DeleteMinorViews { get; set; }
public static GlobalSettings Load()
{
try
{
return JsonConvert.DeserializeObject<GlobalSettings>(File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\YOUR_APP_NAME\\"));
}
catch ()
{
return DefaultSettings;
}
}
public void Save()
{
File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\YOUR_APP_NAME\\", JsonConvert.SerializeObject(this, Formatting.Indented));
}
private static readonly GlobalSettings DefaultSettings = new GlobalSettings()
{
RedFiber = 0,
GreenFiber = 255,
BlueFiber = 0,
DeleteMinorViews = true,
};
}
I had the same issue. Try adding a settings file for your class library to store your values. The value will be stored in the app.config but accessed using the settings file.
This post explains better: Can a class library have an App.config file?
This post goes into more detail about settings files: Best practice to save application settings in a Windows Forms Application
If you prefer not to do the above you can also move your data to the main projects App.config file and it should work.
try
ConfigurationManager.AppSettings["conStr"].ToString();
If the does not work post your App.Config
ConfigurationSettings.AppSettings is obsolete

Change xpo data model connection string at runtime

I have an application using MSSQLSERVER,when I deploy it to the customer, the server name could change, so I have to change the connection string of my xpo data model at run time,
this is the class generated with the XPO data model
public static class ConnectionHelper {
public const string ConnectionString = #"XpoProvider=MSSqlServer;data source=localhost;integrated security=SSPI;initial catalog=tkdoc";
public static void Connect(DevExpress.Xpo.DB.AutoCreateOption autoCreateOption) {
XpoDefault.DataLayer = XpoDefault.GetDataLayer(ConnectionString, autoCreateOption);
XpoDefault.Session = null;
}
public static DevExpress.Xpo.DB.IDataStore GetConnectionProvider(DevExpress.Xpo.DB.AutoCreateOption autoCreateOption) {
return XpoDefault.GetConnectionProvider(ConnectionString, autoCreateOption);
}
public static DevExpress.Xpo.DB.IDataStore GetConnectionProvider(DevExpress.Xpo.DB.AutoCreateOption autoCreateOption, out IDisposable[] objectsToDisposeOnDisconnect) {
return XpoDefault.GetConnectionProvider(ConnectionString, autoCreateOption, out objectsToDisposeOnDisconnect);
}
public static IDataLayer GetDataLayer(DevExpress.Xpo.DB.AutoCreateOption autoCreateOption) {
return XpoDefault.GetDataLayer(ConnectionString, autoCreateOption);
}
}
I'd like to change the ConnectionString in case the server or the user name or the password change
I suggest that you store the connection string in the application configuration file. This way, users can manually modify it, or you can provide them the special settings form for this purpose.
It is easy to read the connection string from the application configuration file. The code example can be found here on StackOverflow: Get connection string from App.config

Using multiple values for one key in appSettings

I'm learning about how to use config files and I ran into some problems that I'm hoping someone here can give me some advice. It doesn't matter if my files are XML or not but the majority of examples I have read are using them and Im all for anything that makes my life easier.
the problem Im running into is that the appSettings file seems to be setup to only accept one value for one key and I would like to have something similar to:
<key="Machine List" value="Server105" />
<key="Machine List" value="Server230" />
Ive found a hack here but it was written over 6 years ago and I didn't know if there was a better way.
Again, it doesnt matter if this is XML, a flat file, etc.... Im just trying to learn how to use config files instead of hard coding values directly into the app.
Thanks for your help.
if you really need to store multiple machines under the key, it would be more appropriate to do:
<key="Machine List" value="Server105,Server230" />
with the delimiter being a character of your choosing.
An alternative to entry attributes would be to add child nodes to your setting node:
<setting key="Machine List">
<value>Server105</value>
<value>Server230</value>
</setting>
This way you don't need string manipulations to extract the different values.
You can make use of configuration sections where you can define your own configuration. Just add
<configSections>
<sectionGroup name="MyConfiguration">
<section name="MyQuery" type="namespace.QueryConfigurationSection" allowLocation="true" allowDefinition="Everywhere"/>
</sectionGroup>
</configSections>
after the <configuration> and you can add your custom section just after the appsetting
</appSettings>
<!-- custom query configuration -->
<MyConfiguration>
<MyQuery>
<Query1> </Query1>
<Query2> </Query2>
To read you need to create few classes
/// <summary>
/// Creates a custom configuration section inside web.config
/// </summary>
public class QueryConfigurationSection : ConfigurationSection
{
//query 2
[ConfigurationProperty("Query1")]
public QueryElement1 Query1
{
get { return this["Query1"] as QueryElement1; }
}
//query 2
[ConfigurationProperty("Query2")]
public QueryElement2 Query2
{
get { return this["Query2"] as QueryElement2; }
}
}
public class QueryElement1 : ConfigurationElement
{
public string Value { get; private set; }
protected override void DeserializeElement(XmlReader reader, bool s)
{
Value = reader.ReadElementContentAs(typeof(string), null) as string;
}
}
public class QueryElement2 : ConfigurationElement
{
public string Value { get; private set; }
protected override void DeserializeElement(XmlReader reader, bool s)
{
Value = reader.ReadElementContentAs(typeof(string), null) as string;
}
}
The overridden DeserializedElement will deserialize the Xml(inside) the QueryElement1 & 2.
To read the values from the main application, you just need to call the following:
//calling my query config
QueryConfigurationSection wconfig = (QueryConfigurationSection)ConfigurationManager.GetSection("MyConfiguration/MyQuery");
string _query1 = wconfig.Query1.Value;
string _query2 = wconfig.Query2.Value;
Maybe you should rethink your design. I would just put the list you want in another file and not the config. You could do a delimited string but then if the list got long it would be hard to manage it. You could just put it in a text file or an XML/JSON file. Here is some code that might be a good place to start.
public static class MyClass
{
private static string _path = ConfigurationManager.AppSettings["FilePath"];
private static List<string> _list;
static MyClass()
{
_list = new List<string>();
foreach (string l in File.ReadAllLines(_path))
_list.Add(l);
}
public static List<string> GetList()
{
return _list;
}
}
I made it a static class so it would only read from the file once and not everytime you need to get information from it.
This might also be a good thing to put in a database if you need more functionality. But for a small read-only kind of thing, this will work better than a delimited string for longer values.

Custom ConfigurationSection: CallbackValidator called with empty string

I am writing a custom configuration section, and I would like to validate a configuration property with a callback, like in this example:
using System;
using System.Configuration;
class CustomSection : ConfigurationSection {
[ConfigurationProperty("stringValue", IsRequired = false)]
[CallbackValidator(Type = typeof(CustomSection), CallbackMethodName = "ValidateString")]
public string StringValue {
get { return (string)this["stringValue"]; }
set { this["stringValue"] = value; }
}
public static void ValidateString(object value) {
if (string.IsNullOrEmpty((string)value)) {
throw new ArgumentException("string must not be empty.");
}
}
}
class Program {
static void Main(string[] args) {
CustomSection cfg = (CustomSection)ConfigurationManager.GetSection("customSection");
Console.WriteLine(cfg.StringValue);
}
}
And my App.config file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="customSection" type="CustomSection, config-section"/>
</configSections>
<customSection stringValue="lorem ipsum"/>
</configuration>
My problem is that when the ValidateString function is called, the value parameter is always an empty string, and therefore the validation fails. If i just remove the validator, the string value is correctly initialized to the value in the configuration file.
What am I missing?
EDIT I discovered that actually the validation function is being called twice: the first time with the default value of the property, which is an empty string if nothing is specified, the second time with the real value read from the configuration file. Is there a way to modify this behavior?
I had the same problem (except I was creating a custom validator rather than using CallbackValidator) - the validator was being called twice, with the first call passing in default values, and the second call passing in the configured values. Since an empty string was not a valid value for one of my properties, it was causing a configuration error even when I had configured a string value.
So I just changed the validator to return on an empty string, rather than validate it. You can then use the IsRequired attribute to control what happens when a value is not provided.

Categories