Make C# Console App recognize manually edited changes in .exe.config file - c#

I successfully wrote a C# console application that collects .XML or .ZIP files from different locations and copies them to a single destination. Those locations are stored in the settings as User-scoped settings (for instance, "Folder01 C:\Data1\" and "Folder02:\Data2"). As you probably already know, building the project generates a [ProjectName].exe.config file in the /bin/Debug folder.
Now, the issue is that I cannot get the console app to recognize any changes that I made in the .exe.config file. Say, I want to add "Folder 03 C:\Data3\" to the settings or edit "Folder02" path to "C:\DataEdited\", the console app will still loop through the settings as initially set up in the code ("Folder01 C:\Data1\" and "Folder02 C:\Data2\").
I also noticed that the console app still runs even after deleting the .exe.config file, as if it does not rely on the file at all. I would like to make changes without having to open the project in Visual Studio and edit locally.
Is that possible?
EDIT:
In response to the request of the Settings that I created and code for getting folder paths, see image image below:
Here is the code:
string[] acceptedExtensions = new[] { ".xml", ".zip" };
string[] settingsToSkip = new[] { "RootFolder", "ArchiveFolder" };
// Collect data
var filteredSettings = Properties.Settings.Default.Properties
.Cast<SettingsProperty>()
.Where(p => !settingsToSkip.Contains(p.Name));
filteredSettings collects Folder01, Folder02, Folder03 and Folder04 and I loop through those to find files with acceptedExtensions.

I believe you expected this feature of c# ConfigurationManager. You might have deleted *.exe.config after your application is started. *.exe.config is not locked or needed after app starts unless you call configurationmanager.refreshsection() method.
Reloading configuration without restarting application using ConfigurationManager.RefreshSection
https://learn.microsoft.com/en-us/dotnet/api/system.configuration.configurationmanager.refreshsection?view=netframework-4.7.2
Thumbs up and mark it if it helped you!

How I have done it in my production code is that I have added to my App.config with my Visual Studios and made it have the format of:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="AConnection" value="127.0.0.1"/>
<add key="Folder01" value="L:\Path\To\A\Thing"/>
<add key="Folder02" value="L:\Path\To\ASecond\Thing"/>
<add key="Folder03" value="L:\Path\To\AThird\Thing"/>
<add key="Folder04" value="L:\Path\To\AFourth\Thing"/>
</appSettings>
</configuration>
Where the <add key="" value="">s are whatever you wish to name them and the values is the path to the correct file.
Assigning:
You can then assign these to variables:
string conStr = ConfiurationManager.AppSettings["AConnection"];
string strFolder1 = ConfigurationManager.AppSettings["Folder01"];
string strFolder2 = ConfigurationManager.AppSettings["Folder02"];
string strFolder3 = ConfigurationManager.AppSettings["Folder03"];
string strFolder4 = ConfigurationManager.AppSettings["Folder04"];

Related

How can i use a value from my appSettings Configuration file, and use it in a constructor method as a decimal value?

So I am in the process of working through a project. Everything was working fine until i put some more control into my form, now it seems as though my tax rates I had set in my configuration file, won't be accepted by my constructor method at run time.
compiles fine, then when i open the form up from the MDi frame, I get this ArguementNullException Handled error and a troubleshoot window pops up.
After doing some researching i am thinking that when i pull my keys from the config file, i am not properly parsing them so that my constructor will take them at run-time.
here's the code that i wrote, im not posting my entire solution, that would be insane at this point.
// sales tax inititalization
decimal gstTax = Decimal.Parse(ConfigurationManager.AppSettings.Get("GoodsAndServicesTaxRate."));
decimal pstTax = Decimal.Parse(ConfigurationManager.AppSettings.Get("ProvincialSalesTaxRate"));
decimal salesTaxRate = gstTax + pstTax;
SalesQuote quote = new SalesQuote(Decimal.Parse(txtSalePrice.Text),
(Decimal.Parse(txtTradeIn.Text)),
salesTaxRate,
(Accessories)optA,
(ExteriorFinish)optB);
And here is the XML file with the key values.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ApplicationName:" value="RRC Automotive Group"/>
<add key="GoodsAndServicesTaxRate" value=".05"/>
<add key="ProvincialSalesTaxRate" value=".08"/>
</appSettings>
</configuration>
And yes there is an assembly reference.
the signature for SalesQuote(decimal,decimal,decimal,Enum,Enum) if that wasn't already obvious.
i want to thank you fellow nerds for any advice... to the best of my knowledge this was all working fine so im not sure what is trumping me up here.
any help helps!
thanks
You have a stray . here
ConfigurationManager.AppSettings.Get("GoodsAndServicesTaxRat‌​e.")
which does not match up with what is in the config file
<add key="GoodsAndServicesTaxRate" value="0.05"/>
This would result in the ConfigurationManager.AppSettings.Get method return null which would cause the parsing Decimal.Parse to fail.

Why is my Connection String only working in Dev?

See DGibbs answer below.
I can't have the config file saved with the EXE, as this is present on each user's desktop, so it seems I am unable to store the password in the config file and will have to come up with some other solution.
I have an app that needs to run a CMD command as an administrator. To achieve this, I stored the password in a connection string in app.config:
<connectionStrings>
<add name="mypw" connectionString="PASSWORD" />
</connectionStrings>
I am then able to call this in my Cmd class as a SecureString:
private static SecureString pw()
{
string connectionString = ConfigurationManager.ConnectionStrings["mypw"].ConnectionString;
SecureString ss = new SecureString();
foreach (char c in connectionString)
{
ss.AppendChar(c);
}
return ss;
}
When I run the app from VS on my machine with debugging (F5), it works fine and the password is retrieved. However, when running it in a development environment I see the exception Object Reference not set to an instance of an object, and from my own debugging I can see that this is happening at this line:
string connectionString = ConfigurationManager.ConnectionStrings["mypw"].ConnectionString;
Can anyone please explain why the app is able to retrieve the connection string on my machine but not when deployed elsewhere? Does the app.config file change when publishing the app?
Few things, don't use <connectionStrings>, this is typically used to store credentials for a db connection, it doesn't make sense here. Try using AppSettings within the App.config file e.g
<appSettings>
<add key="mypw" value="password" />
</appSettings>
You can retrieve the value like this:
string pw = ConfigurationSettings.AppSettings["mypw"];
Finally, make sure you have the config file deployed, it should be [ApplicationName].exe.config and not App.Config. If it doesn't appear, check the Copy to output directory setting, make sure it's set to Copy Always.

How to modify the App.Config section value

I have an app.config like below,
<configuration>
<environment>
<add key="security" value="1"/> -- I want to change this value to 3
</environment>
</configuration>
I tried like below to get to environment section,
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
var environment = config.GetSection("environment");
environment variable doesn't give me enough options to get the child elements to modify the value. Could any one please help me out in this one.
Use user scope settings!! NEVER EVER change the application configuration that way. Any value that is changed within the application should be a user setting.
Usually, you access these settings through
Properties.Settings.Default.MyConfigurationValue = ....;
Properties.Settings.Default.Save();
EDIT
Sample for doing what I wrote in the comments. Create two user settings: FirstRun is a bool which is by default set to true. Environment is your value, by default set to 0.
Then, for example in the Main function in Program.cs you'd do the following:
if (Properties.Settings.Default.FirstRun)
{
Properties.Settings.Default.FirstRun = false;
if (myConditionIsTrue)
Properties.Settings.Default.Environment = 3;
Properties.Settings.Default.Save();
}
Later in your application it is enough to use Properties.Settings.Default.Environment. That's how the settings mechanism is intended to be used if you want to change configuration values from your application.
Under Windows 2000, XP, 7 and the Windows Server branch you would not even have the rights to modify the app.config in your Program Files folder, so don't!

How to build an installer to update an ASP.NET's web.config, DLL, files, etc

I have an add-on for a commercial ASP.NET website. My add-on requires people to merge entries into their web.config, add/overwrite existing files, and add some DLL files to the bin folder.
Is there a good and safe way to create an installer than can do this with a wizard type of installation? It would really help non-technical people install the add-on easily. Maybe even a web-based installer would be good?
Any help or suggestions would be greatly appreciated.
Had a similar problem...
Web.Config
Created a .NET command line program that you can call from your installer passing it the web.config path and other args to match what I'm trying to do
In the command line program you can then modify the web.config to your needs... Below is an example of setting a connection string & the stmp from address in a web.config
public static void SetConnectionString(string name, string connString, string webConfigPath)
{
string directory = System.IO.Path.GetDirectoryName(webConfigPath);
VirtualDirectoryMapping vdm = new VirtualDirectoryMapping(directory, true);
WebConfigurationFileMap wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
System.Configuration.Configuration webConfig = System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
webConfig.ConnectionStrings.ConnectionStrings[name].ConnectionString = connString;
webConfig.Save();
}
public static void SetFromAddress(string email, string webConfigPath)
{
string directory = System.IO.Path.GetDirectoryName(webConfigPath);
VirtualDirectoryMapping vdm = new VirtualDirectoryMapping(directory, true);
WebConfigurationFileMap wcfm = new WebConfigurationFileMap();
wcfm.VirtualDirectories.Add("/", vdm);
System.Configuration.Configuration webConfig = System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(wcfm, "/");
System.Net.Configuration.MailSettingsSectionGroup mailSettings = (System.Net.Configuration.MailSettingsSectionGroup)webConfig.GetSectionGroup("system.net/mailSettings");
mailSettings.Smtp.From = email;
webConfig.Save();
}
Installer
I used NSIS (http://nsis.sourceforge.net/Main_Page). Use HM NIS Edit as a good starting point as it has a wizard that will generate scripts for you. From there you can modify up the scripts to your needs. In my case I called my command line program after the files where installed. Example NSIS script below.
Section "My Config Wizard" SecWizard
ExecWait '"$INSTDIR\Bin\My.Config.Wizard.exe" "$INSTDIR"'
Return
SectionEnd
Good luck! Need more examples just hit me up. :P
The web.config is the tricky part. Your first installer will deploy an XML file and then a user will change something in it. Meanwhile you have another build where the developer makes changes to the XML and now the installer has to try to figure out how that should merge all back together.
Out of the box, it can't.
2 strategies that I've used over the years:
1) Have the installer smart enough to pick out key pieces of information from the xml before replacing the xml. Then apply the information back.
2) Design your software to have 2 XML files. One that the installer can safely always overwrite and the other to act as an override that the user can modify safely.

c# application and configuration settings

I never used Settings class before but I found some articles on CodeProject which I'm currently reading (for example http://www.codeproject.com/KB/cs/PropertiesSettings.aspx) but so far I didn't see how to save string array for getting it after application is started next time.
For example my application has several FileSystemWatcher instances, with each instance several other directories are connected (for example one FSW instance is monitoring one directory for a change and when it happens it copies some file to several other directories), so I would have one string array with watched paths representing FSW instances, and string array for each of those paths, representing directories that are affected.
My question is, what should I use (Settings class or something else), and how should I use that for storing application configuration that is variable number of string arrays? Emphasize is on something I could use very soon as I don't have too much time to make custom class (but would have to if I cannot find solution) or dig into some obscure hacks.
Any tutorial link, code snippet would be very helpful.
Thanks.
Why not use a config file instead? I had a set of FileSystemWatchers like yours and just added a set of paths using custom config sections. Thought that requires you rolling a class to extending the Configuration classes, but I think that you can't beat that approach.
Though if you want a clear easy hack and don't want to get bothered with the Custom Config Sections/Elements/Collections. Just use a quick and easy AppSettings hack. XD
<appSettings>
<add key="ConnectionInfo0" value="server=(local);database=Northwind;Integrated Security=SSPI" />
<add key="ConnectionInfo1" value="server=(local);database=Northwind;Integrated Security=SSPI" />
<add key="ConnectionInfo2" value="server=(local);database=Northwind;Integrated Security=SSPI" />
</appSettings>
Getting it from code.
const string CONNECTIONSTRING="";
int i = 0;
while(ConfigurationSettings.AppSettings["ConnectionInfo"] + i != null)
{
// do stuff with connection info here
// use
ConfigurationSettings.AppSettings["ConnectionInfo" + i];
// to get data.
++i;
}
Tad ugly, I know. Custom Config works best.

Categories