C# Keeps forgetting my progress - c#

using (StreamWriter sw = new StreamWriter(sName + ".txt", true))
{
iDayNum++; //Adds a day on each time that case 3 is used.
Console.Write("How many minutes have you been exercising? ");
iExcerMinutes = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
The code inside here works fine but when I reopen the program and ask the program what daynumber I am on it resets, what am I missing?

Hopefully this will help get you started - one technique is as follows.
Right-click your project, select properties/settings and create a user-scope setting.
I just created one called 'RunCount' of type int with value zero in a console application - I set the access modifier to 'public', as it happens.
The following code persists the run count incrementing it as it goes.
class Program
{
static void Main(string[] args)
{
Settings.Default.RunCount += 1;
Settings.Default.Save();
Console.WriteLine(String.Format("This is run number {0} for this user", Settings.Default.RunCount));
Console.WriteLine("Press a key to continue");
Console.ReadKey();
}
}
If you were to run this example, then have a look in c:\users\"yourname"\Appdata\Local\"yourprogramname" you will find a .config file containing :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<yourprogramname.Properties.Settings>
<setting name="RunCount" serializeAs="String">
<value>1</value>
</setting>
</yourprogramname.Properties.Settings>
</userSettings>
</configuration>

Related

Persistent user settings

I am trying to save user settings in C# and reuse them in the next session.
All over the net, one finds tipps like this:
How to save user settings programatically?
I have a .setting file in my project with the default settings.
When a user changes a setting, I call save, and in %APPDATA% the file appears, with the user settings.
It looks like this:
private void SetSetting(string prop, Object val)
{
try
{
string strval = String.Format("G{0}_{1}", Group_Id, prop);
Properties.Last.Default[strval] = val;
}
catch
{
System.Configuration.SettingsProperty property = new System.Configuration.SettingsProperty(String.Format("G{0}_{1}", Group_Id, prop));
property.PropertyType = Properties.Def.Default[String.Format("G0_{1}", Group_Id, prop)].GetType();
property.DefaultValue = Properties.Def.Default[String.Format("G0_{1}", Group_Id, prop)];
property.PropertyType = val.GetType();
property.Provider = Properties.Last.Default.Providers["LocalFileSettingsProvider"];
property.Attributes.Add(typeof(System.Configuration.UserScopedSettingAttribute), new System.Configuration.UserScopedSettingAttribute());
Properties.Last.Default.Properties.Add(property);
Properties.Last.Default.Reload();
string strval = String.Format("G{0}_{1}", Group_Id, prop);
Properties.Last.Default[strval] = val;
}
Properties.Last.Default.Save();
}
As you can see, I have the settings instance Last as in "settings from last session" and Def as in default.
Basically, a user can add and delete groups at will in the app. Def holds the default configuration for a new group. Last should hold the number of groups in the last user session, as well as the properties of each group. Thus the formatting with the Group_Id and so on.
So, as I said. During runtime, its fine. User settings are properly written to the file in %APPDATA% and everything.
The file is like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c5629387e089" >
<section name="Project1.Properties.Last" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c5629387e089" " allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<Project1.Properties.Last>
<setting name="G1_do_cut" serializeAs="String">
<value>True</value>
</setting>
</Project1.Properties.Last>
</userSettings>
</configuration>
So, the setting for do_cut for Group 1 is saved as G1_do_cut
But as soon as I restart the application, the user setting is ignored.
The code used is:
private Object GetSetting(string prop)
{
try { return Properties.Last.Default[String.Format("G{0}_{1}", Group_Id, prop)]; }
catch { return Properties.Def.Default[String.Format("G0_{1}", Group_Id, prop)]; }
}
and in the try, an exception G1_do_cut is not found in settings is thrown and the catch loads the default.
During a user session, the GetSettings works correctly - if I try to read G1_do_cut after it has been set, no exception is thrown and I get the correct value.
How do I get C# to reuse the settings after restarting the application?

Where do I insert this data into my code?

I want to set a cache limit for my C# program. My program is creating files periodically and saving them to a folder. I want it so if the folder (C:\SysApp) hits this limit (150000KB) it will automatically start deleting the files starting with the oldest ones deleting only a certain amount at a time (149900KB).
So far I have this code:
private void DeleteOldFilesIfOverFolderLimit(string folderPath,
long folderSizeLimit,
long amountToDelete)
{
var folder = new DirectoryInfo(folderPath);
var files = folder.GetFiles();
var folderSize = files.Sum(fi => fi.Length);
if (folderSize > folderSizeLimit)
{
// Sort the list of files with the oldest first.
Array.Sort(files,
(fi1, fi2) => fi1.CreationTime.CompareTo(fi2.CreationTime));
var amountDeleted = 0L;
foreach (var file in files)
{
amountDeleted += file.Length;
file.Delete();
if (amountDeleted >= amountToDelete)
{
break;
}
}
}
}
I'm just trying to figure out where I need to insert the specific data for my program (given in first paragraph in parenthesis).
I'm using Visual Studio Community 2015.
Click on the project options and select settings:
Enter the default values
and your program can read these values (from the .settings file or the defaults) using the following code
static void Main(string[] args)
{
string folder=Properties.Settings.Default.folder;
long limit=Properties.Settings.Default.sizeLimit;
long delete=Properties.Settings.Default.toDelete;
}
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. These are read automatically when the program starts.
The contents are an XML file with the settings values clearly visible.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SO_KeepStettings.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<SO_KeepStettings.Properties.Settings>
<setting name="folder" serializeAs="String">
<value>C:\SysApp</value>
</setting>
<setting name="sizeLimit" serializeAs="String">
<value>157286400</value>
</setting>
<setting name="toDelete" serializeAs="String">
<value>156237824</value>
</setting>
</SO_KeepStettings.Properties.Settings>
</userSettings>
</configuration>
Deleting files is sketchy, if you accidentally pass in a malformed string or simply the wrong string then you will be losing data, such as accidentally deleting your only copy of your PhD thesis or destroying your operating system. So, I'm just going to show you how to call a method instead of showing you how to use this code you were given:
Starting with a Hello World! example:
public class Hello1
{
public static void Main()
{
System.Console.WriteLine("Hello, World!");
// This is here only to pause the console window so it stays open.
System.Console.ReadLine();
}
}
Now let's implement our own method to print any string to the console:
public class Hello1
{
public static void Main()
{
PrintToConsole("Hello World!");
// This is here only to pause the console window so it stays open.
System.Console.ReadLine();
}
private static void PrintToConsole(string stringToPrintToConsole)
{
System.Console.WriteLine(stringToPrintToConsole);
}
}
Lastly, let's pass in another parameter to control how many times the line is printed:
public class Hello1
{
public static void Main()
{
PrintToConsole("Hello World!", 5);
// This is here only to pause the console window so it stays open.
System.Console.ReadLine();
}
private static void PrintToConsole(string stringToPrintToConsole, long numberOfTimesToPrint)
{
for (int i = 0; i < numberOfTimesToPrint; i++)
{
System.Console.WriteLine(stringToPrintToConsole);
}
}
}
You were given a method but no where are you calling that method. Note how in my program I have to call PrintToConsole() somewhere, and this being a console application the entire program starts and finishes in Main() so that is where I put the code. You could technically take the body of your method and paste it directly into Main, then everywhere you see the usage of the variable folderPath you replace it with the actual string "C:\\SysApp" and likewise with the other 2 parameters and the program would work the same.

reading an xml file in C# using CsQuery

using CsQuery;
namespace CSQuery
{
class Program
{
static void Main(string[] args)
{
var dom = CQ.Create(/*I am not sure what goes here*/);
//Not sure if this is the correct setup as well
CQ mf = dom["MANUFACTURER"];
CQ md = dom["MODEL"];
Console.WriteLine(mf);
Console.WriteLine(md);
Console.ReadKey();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
--------------------------------------------------------
PARTS:
Title: Computer Parts
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST>160.00</COST>
<ITEM> Monitor </ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART></PARTS>
Above is my code I have written so far I am trying to extract the MANUFACTURER and MODEL from the sample given xml code. When I compile I get an error message saying source can not be found and I think it may be a problem with my setup and I am unclear on what exactly is suppose to go into my CQ.Create() as a parameter(I tried putting in the exact parts.xml file but that didn't help).

Loading Properties.Settings from a different file at runtime

Is there any way to load settings from a different file other than the default App.config file at runtime? I'd like to do this after the default config file is loaded.
I use the Settings.Settings GUI in Visual Studio to create my App.config file for me. The config file ends up looking like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SnipetTester.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<SnipetTester.Properties.Settings>
<setting name="SettingSomething" serializeAs="String">
<value>1234</value>
</setting>
</SnipetTester.Properties.Settings>
</applicationSettings>
</configuration>
In code, I'm able to access the settings like this:
Console.WriteLine("Default setting value: " + Properties.Settings.Default.SettingSomething);
The idea is that when the application is run, I should be able to specify a config file at run time and have the application load the config file into the Properties.Settings.Default object instead of using the default app.config file. The formats of the config files would be the same, but the values of the settings would be different.
I know of a way to do this with the ConfigurationManager.OpenExeConfiguration(configFile);. However, in the tests that I've run, it doesn't update the Properties.Settings.Default object to reflect the new values from the config file.
After thinking about this a bit longer, I've been able to come up with a solution that I like a little better. I'm sure it has some pitfalls, but I think it'll work for what I need it to do.
Essentially, the Properties.Settings class is automatically generated by Visual Studio; it generates the code for the class for you. I was able to find where the code was generated and add a few function calls to load a config file on its own. Here's my addition:
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
//Parses a config file and loads its settings
public void Load(string filename)
{
System.Xml.Linq.XElement xml = null;
try
{
string text = System.IO.File.ReadAllText(filename);
xml = System.Xml.Linq.XElement.Parse(text);
}
catch
{
//Pokemon catch statement (gotta catch 'em all)
//If some exception occurs while loading the file,
//assume either the file was unable to be read or
//the config file is not in the right format.
//The xml variable will be null and none of the
//settings will be loaded.
}
if(xml != null)
{
foreach(System.Xml.Linq.XElement currentElement in xml.Elements())
{
switch (currentElement.Name.LocalName)
{
case "userSettings":
case "applicationSettings":
foreach (System.Xml.Linq.XElement settingNamespace in currentElement.Elements())
{
if (settingNamespace.Name.LocalName == "SnipetTester.Properties.Settings")
{
foreach (System.Xml.Linq.XElement setting in settingNamespace.Elements())
{
LoadSetting(setting);
}
}
}
break;
default:
break;
}
}
}
}
//Loads a setting based on it's xml representation in the config file
private void LoadSetting(System.Xml.Linq.XElement setting)
{
string name = null, type = null, value = null;
if (setting.Name.LocalName == "setting")
{
System.Xml.Linq.XAttribute xName = setting.Attribute("name");
if (xName != null)
{
name = xName.Value;
}
System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs");
if (xSerialize != null)
{
type = xSerialize.Value;
}
System.Xml.Linq.XElement xValue = setting.Element("value");
if (xValue != null)
{
value = xValue.Value;
}
}
if (string.IsNullOrEmpty(name) == false &&
string.IsNullOrEmpty(type) == false &&
string.IsNullOrEmpty(value) == false)
{
switch (name)
{
//One of the pitfalls is that everytime you add a new
//setting to the config file, you will need to add another
//case to the switch statement.
case "SettingSomething":
this[name] = value;
break;
default:
break;
}
}
}
}
The code I added exposes an Properties.Settings.Load(string filename) function. The function accepts a config filename as a parameter. It will parse the file and load up any settings it encounters in the config file. To revert back to the original configuration, simply call Properties.Settings.Reload().
Hope this might help someone else!
Look at using ExeConfigurationFileMap and ConfigurationManager.OpenMappedExeConfiguration.
See Cracking the Mysteries of .Net 2.0 Configuration
The ExeConfigurationFileMap allows you to specifically configure the
exact pathnames to machine, exe, roaming and local configuration
files, all together, or piecemeal, when calling
OpenMappedExeConfiguration(). You are not required to specify all
files, but all files will be identified and merged when the
Configuration object is created. When using
OpenMappedExeConfiguration, it is important to understand that all
levels of configuration up through the level you request will always
be merged. If you specify a custom exe and local configuration file,
but do not specify a machine and roaming file, the default machine and
roaming files will be found and merged with the specified exe and user
files. This can have unexpected consequences if the specified files
have not been kept properly in sync with default files.
It depends on the type of the application:
Web Application & Windows Application - use the configSource xml attribute if you are willing to store the config files in the same folder (or subfolders) as the application
Create a settings provider and also implement IApplicationSettingsProvider. Samples here and here. You might also need to use the IConfigurationManagerInternal interface to replace the default .NET configuration manager. When implementing the provider don't forget to make a difference between user settings and application settings and the roaming profiles.
If you want to get started quickly just decompile the LocalFileSettingsProvider class (the default settings provider) and change it to your needs (you might find some useles code and might need to replicate all of the classes on which it depends).
Good luck
You can include the types so you don't need to manually update the source every time.
`private void LoadSetting(System.Xml.Linq.XElement setting)
{
string name = null, type = null;
string value = null;
if (setting.Name.LocalName == "setting")
{
System.Xml.Linq.XAttribute xName = setting.Attribute("name");
if (xName != null)
{
name = xName.Value;
}
System.Xml.Linq.XAttribute xSerialize = setting.Attribute("serializeAs");
if (xSerialize != null)
{
type = xSerialize.Value;
}
System.Xml.Linq.XElement xValue = setting.Element("value");
if (xValue != null)
{
if (this[name].GetType() == typeof(System.Collections.Specialized.StringCollection))
{
foreach (string s in xValue.Element("ArrayOfString").Elements())
{
if (!((System.Collections.Specialized.StringCollection)this[name]).Contains(s))
((System.Collections.Specialized.StringCollection)this[name]).Add(s);
}
}
else
{
value = xValue.Value;
}
if (this[name].GetType() == typeof(int))
{
this[name] = int.Parse(value);
}
else if (this[name].GetType() == typeof(bool))
{
this[name] = bool.Parse(value);
}
else
{
this[name] = value;
}
}
}`

AppSettings get value from .config file

I'm not able to access values in configuration file.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var clientsFilePath = config.AppSettings.Settings["ClientsFilePath"].Value;
// the second line gets a NullReferenceException
.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- ... -->
<add key="ClientsFilePath" value="filepath"/>
<!-- ... -->
</appSettings>
</configuration>
Do you have any suggestion what should I do?
This works for me:
string value = System.Configuration.ConfigurationManager.AppSettings[key];
The answer that dtsg gave works:
string filePath = ConfigurationManager.AppSettings["ClientsFilePath"];
BUT, you need to add an assembly reference to
System.Configuration
Go to your Solution Explorer and right click on References and select Add reference. Select the Assemblies tab and search for Configuration.
Here is an example of my App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="AdminName" value="My Name"/>
<add key="AdminEMail" value="MyEMailAddress"/>
</appSettings>
</configuration>
Which you can get in the following way:
string adminName = ConfigurationManager.AppSettings["AdminName"];
Give this a go:
string filePath = ConfigurationManager.AppSettings["ClientsFilePath"];
Read From Config :
You'll need to add a reference to Config
Open "Properties" on your project
Go to "Settings" Tab
Add "Name" and "Value"
Get Value with using following code :
string value = Properties.Settings.Default.keyname;
Save to Config :
Properties.Settings.Default.keyName = value;
Properties.Settings.Default.Save();
I am using:
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
//configMap.ExeConfigFilename = #"d:\test\justAConfigFile.config.whateverYouLikeExtension";
configMap.ExeConfigFilename = AppDomain.CurrentDomain.BaseDirectory + ServiceConstants.FILE_SETTING;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
value1 = System.Configuration.ConfigurationManager.AppSettings["NewKey0"];
value2 = config.AppSettings.Settings["NewKey0"].Value;
value3 = ConfigurationManager.AppSettings["NewKey0"];
Where value1 = ... and value3 = ... gives null and value2 = ... works
Then I decided to replace the internal app.config with:
// Note works in service but not in wpf
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"d:\test\justAConfigFile.config.whateverYouLikeExtension");
ConfigurationManager.RefreshSection("appSettings");
string value = ConfigurationManager.AppSettings["NewKey0"];
Using VS2012 .net 4
In the app/web.config file set the following configuration:
<configuration>
<appSettings>
<add key="NameForTheKey" value="ValueForThisKey" />
...
...
</appSettings>
...
...
</configuration>
then you can access this in your code by putting in this line:
string myVar = System.Configuration.ConfigurationManager.AppSettings["NameForTheKey"];
*Note that this work fine for .net4.5.x and .net4.6.x; but do not work for .net core.
Best regards:
Rafael
Coming back to this one after a long time...
Given the demise of ConfigurationManager, for anyone still looking for an answer to this try (for example):
AppSettingsReader appsettingsreader = new AppSettingsReader();
string timeAsString = (string)(new AppSettingsReader().GetValue("Service.Instance.Trigger.Time", typeof(string)));
Requires System.Configuration of course.
(Editted the code to something that actually works and is simpler to read)
See I did what I thought was the obvious thing was:
string filePath = ConfigurationManager.AppSettings.GetValues("ClientsFilePath").ToString();
While that compiles it always returns null.
This however (from above) works:
string filePath = ConfigurationManager.AppSettings["ClientsFilePath"];
Some of the Answers seems a little bit off IMO Here is my take circa 2016
<add key="ClientsFilePath" value="filepath"/>
Make sure System.Configuration is referenced.
Question is asking for value of an appsettings key
Which most certainly SHOULD be
string yourKeyValue = ConfigurationManager.AppSettings["ClientsFilePath"]
//yourKeyValue should hold on the HEAP "filepath"
Here is a twist in which you can group together values ( not for this question)
var emails = ConfigurationManager.AppSettings[ConfigurationManager.AppSettings["Environment"] + "_Emails"];
emails will be value of Environment Key + "_Emails"
example : jack#google.com;thad#google.com;
For web application, i normally will write this method and just call it with the key.
private String GetConfigValue(String key)
{
return System.Web.Configuration.WebConfigurationManager.AppSettings[key].ToString();
}
Open "Properties" on your project
Go to "Settings" Tab
Add "Name" and "Value"
CODE WILL BE GENERATED AUTOMATICALLY
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup ..." ... >
<section name="XX....Properties.Settings" type="System.Configuration.ClientSettingsSection ..." ... />
</sectionGroup>
</configSections>
<applicationSettings>
<XX....Properties.Settings>
<setting name="name" serializeAs="String">
<value>value</value>
</setting>
<setting name="name2" serializeAs="String">
<value>value2</value>
</setting>
</XX....Properties.Settings>
</applicationSettings>
</configuration>
To get a value
Properties.Settings.Default.Name
OR
Properties.Settings.Default["name"]
ConfigurationManager.RefreshSection("appSettings")
string value = System.Configuration.ConfigurationManager.AppSettings[key];
Or you can either use
string value = system.configuration.ConfigurationManager.AppSettings.Get("ClientsFilePath");
//Gets the values associated with the specified key from the System.Collections.Specialized.NameValueCollection
You can simply type:
string filePath = Sysem.Configuration.ConfigurationManager.AppSettings[key.ToString()];
because key is an object and AppSettings takes a string
My simple test also failed, following the advice of the other answers here--until I realized that the config file that I added to my desktop application was given the name "App1.config". I renamed it to "App.config" and everything immediately worked as it ought.
Updated
ConfigurationManager is outdated, you need to use IConfiguration in the .NET Сore environment (IConfiguration is provided by .NET Core built-in dependency injection).
private readonly IConfiguration config;
public MyConstructor(IConfiguration config)
{
this.config = config;
}
public void DoSomethingFunction()
{
string settings1 = config["Setting1"];
}
In my case I had to throw a ' on either side of the '#System.Configuration.ConfigurationManager.AppSettings["key"]' for it to be read into my program as a string. I am using Javascript, so this was in my tags. Note: ToString() was not working for me.
Do something like this :
string value1 = System.Configuration.ConfigurationManager.AppSettings.Get(0); //for the first key
string value2 = System.Configuration.ConfigurationManager.AppSettings.Get(1); //for the first key

Categories