Simplify test configuration by reading App.config from tests - c#

My app allows the user to specify in App.config the columns they want in their output:
<?xml version="1.0"?>
<configuration>
<appSettings>
.
.
.
<!-- specify columns you want -->
<add key="NameCol" value="true"/>
<add key="AddressCol" value="true"/>
<add key="TelCol" value="true"/>
.
.
.
</appSettings>
I have a separate project that tests my app. In the tests I change various column settings and after each test clear the settings using code like this:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// set config options here
// now clear config options
config.AppSettings.Settings.Remove("NameCol");
config.AppSettings.Settings.Remove("AddressCol");
config.AppSettings.Settings.Remove("TelCol");
Is there a way to read the column names from the App.config file and have a for loop for the above? So it would be something like this. What would getColNamesFromAppConfig() looklike?
columnNames = getColNamesFromAppConfig()
foreach (string colName in ColumnNames)
{
config.AppSettings.Settings.Remove(colName);
}

How about:
foreach (SettingsProperty property in Settings.Properties) // or ConfigurationProperty?
{
// ...
}
PS. By the way, if I were you, I would consider wrapping settings in a custom object (implemented by yourself). If you have to do this:
config.AppSettings.Settings.Remove("NameCol");
config.AppSettings.Settings.Remove("AddressCol");
config.AppSettings.Settings.Remove("TelCol");
in a test, it's a code smell to me. I believe you should be able to mock settings for testing purposes. This is a matter of taste, however.

Related

C# ASP MVC pulling data from the web config file is not working

I'm trying to pull data from the web config file as outlined by this msdn resource.
Here is my code:
System.Configuration.Configuration activeCampaignApiSetting1 =
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
if (activeCampaignApiSetting1.AppSettings.Settings.Count > 0) {
System.Configuration.KeyValueConfigurationElement activeCampaignApiKeySetting =
activeCampaignApiSetting1.AppSettings.Settings["ActiveCampaignApiKey"];
if (activeCampaignApiKeySetting != null) {
activeCampaignApiKey = activeCampaignApiKeySetting.Value;
}
System.Configuration.KeyValueConfigurationElement activeCamapignApiUrlSetting =
activeCampaignApiSetting1.AppSettings.Settings["ActiveCampaignApiUrl"];
if (activeCamapignApiUrlSetting != null) {
activeCampaignApiUrl = activeCamapignApiUrlSetting.Value;
}
}
When I try to instantiate this class:
var acs = new Acs(activeCampaignApiKey, activeCampaignApiUrl);
it throws an exception telling me that the values are blank.
The values in the web config file are there:
<add key="ActiveCampaignApiKey" value="apikey_removed" />
<add key="ActiveCampaignApiUrl" value="apiurl_removed" />
Anyone know where I may be going wrong?
Cheers
If they are appSetting inside web.config, you can access them via ConfigurationManager.AppSettings.
<?xml version="1.0"?>
<configuration>
<configSections>
<appSettings>
<add key="ActiveCampaignApiKey" value="apikey_removed" />
<add key="ActiveCampaignApiUrl" value="apiurl_removed" />
</appSettings>
</configSections>
</configuration>
string activeCampaignApiKeySetting
= ConfigurationManager.AppSettings["ActiveCampaignApiKey"];
string activeCamapignApiUrlSetting
= ConfigurationManager.AppSettings["ActiveCampaignApiUrl"];
Please make sure you reference System.Configuration, and include using System.Configuration; directive.
FYI: They return string value (not key value pair).
Ok so I have a better solution,
As I'm working with nopCommerce I need to use:
private readonly ISettingService _settingService = EngineContext.Current.Resolve<ISettingService>();
string apikey = _settingService.GetSettingByKey<string>("apikey_removed");
string apiurl = _settingService.GetSettingByKey<string>("apiurl_removed");
As outlined in this forum thread
Then in the administration backend under configuration > settings > all settings I add the key there.
This is a much better solution because if the api key or url ever need to be changed it can be done through the nopcommerce administration panel. rather than rebuilding/publishing the solution to a web server.
Hope this helps someone :)

is it possible to Use key values within app.config in vs 2013

I am trying to access a key value into the another key in app.config but it does not work.
<appSettings>
<add key="KEY1" value="dev.cloud" />
<add key="url" value="https://www.[KEY1].com"/>
</appSettings>
I tried ${KEY1} like valumanifest.xml but this does not work in app.config.
am I missing something here ?
You have to use ConfigurationManager to read settings in the appSettings section.
For example:
var key1Val = ConfigurationManager.AppSettings["KEY1"] // returns the value of KEY1 from appSettings.
You need to add the using, then this should work.
var Key1 = Settings.Default.KEY1;
If you want to know more about the Setting.Default, check this out.

Why is the ConfigurationManager.GetSection "system.webServer/handlers" not available?

I'm trying to read some configuration in my global.aspx Application_Start method. When I read ConfigurationManager.GetSection("system.web/httpHandlers") everything is fine:
ConfigurationManager.GetSection("system.web/httpHandlers")
{System.Web.Configuration.HttpHandlersSection}
base {System.Configuration.ConfigurationSection}: {System.Web.Configuration.HttpHandlersSection}
Handlers: Count = 48
But when I read ConfigurationManager.GetSection("system.webServer/handlers") (which contains my custom handlers, it returns null. What am I doing wrong?
The section looks like this:
<system.webServer>
<handlers>
<add verb="*" path="*.loc" name="LocalizedResourceStreamer"
type="CFW.WebUI.HttpHandlers.LocalizedResourceStreamer,WebUI" />
</handlers>
</system.webServer>
Notes:
Web.configs are nested, ConfigurationManager.GetSection takes nesting into account by default.
The overall problem is trying to see if *.loc files are being served.
So far:
Looks like the system.webServer is ignored.
Depending on your OS/setup, the system.webServer element may be configured to be ignored - and so the config system will not be constructing any inner configuration items from it. E.g. on my machine (WinXP, IIS 5.1), it's set to ignored by default.
Check the machine.config on the machine where this code is running, and see how the system.webServer element is configured. I don't have machines available with suitable later OSes at the moment, but it may be that this element is always set to be ignored - after all, that part of the config is for IIS' use, rather than our own.
try :
**p.s. my web.config contains : <httpHandlers> and not handlers as yours. change as necessarily :) - also the webserver vs system.web **
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection webConfigSections = webConfig.GetSection("system.web/httpHandlers");
if (webConfigSections != null)
{
// PropertyInformationCollection t = webConfigSections.ElementInformation.Properties;
XDocument xmlFile = XDocument.Load(new StringReader(webConfigSections.SectionInformation.GetRawXml()));
IEnumerable<XElement> query = from c in xmlFile.Descendants("add") select c;
foreach (XElement band in query)
{
}
}
p.s. thats the problem with this section - he doesnt have a uniquee element name that can be taken. thats why you take it whole("add" element) and parse it.

How to change location of app.config

I want to change the location where my application looks for the app.config file.
I know that I can use ConfigurationManager.OpenExeConfiguration() to access an arbitrary config file - however, when the .Net Framework reads the config file (for ConnectionStrings or EventSources, for instance), it will look at the default location. I want to actually change the location, globally for the entire .Net Framework (for my application, of course).
I also know that I can use AppDomainSetup to change the location of the app.config for a new AppDomain. However, that doesn't apply to the primary AppDomain of the application.
I also know that I can override function Main() and create a new AppDomain as above and run my application in that new AppDomain. However, that has other side-effects - for instance, Assembly.GetEntryAssembly() will return a null reference.
Given how everything else works in .Net, I would expect there to be some way to configure the startup environment of my application - via a Application Manifest, or some such - but I have been unable to find even a glimmer of hope in that direction.
Any pointer would be helpful.
David Mullin
I used the approach with starting another AppDomain from Main(), specifying the "new" location of the configuration file.
No issues with GetEntryAssembly(); it only returns null, when being called from unmanaged code - or at least it doesn't for me, as I use ExecuteAssembly() to create/run the second AppDomain, much like this:
int Main(string[] args)
{
string currentExecutable = Assembly.GetExecutingAssembly().Location;
bool inChild = false;
List<string> xargs = new List<string>();
foreach (string arg in xargs)
{
if (arg.Equals("-child"))
{
inChild = true;
}
/* Parse other command line arguments */
else
{
xargs.Add(arg);
}
}
if (!inChild)
{
AppDomainSetup info = new AppDomainSetup();
info.ConfigurationFile = /* Path to desired App.Config File */;
Evidence evidence = AppDomain.CurrentDomain.Evidence;
AppDomain domain = AppDomain.CreateDomain(friendlyName, evidence, info);
xargs.Add("-child"); // Prevent recursion
return domain.ExecuteAssembly(currentExecutable, evidence, xargs.ToArray());
}
// Execute actual Main-Code, we are in the child domain with the custom app.config
return 0;
}
Note that we are effectively rerunning the EXE, just as a AppDomain and with a different config. Also note that you need to have some "magic" option that prevents this from going on endlessly.
I crafted this out from a bigger (real) chunk of code, so it might not work as is, but should illustrate the concept.
I am not sure why you want to change the location of your config file - perhaps there can be different approach for solving your actual problem. I had a requirement where I wanted to share configuration file across related applications - I had chosen to use own xml file as it had given me extra benefit of having complete control over the schema.
In your case, it's possible to externalize sections of your config file to a separate file using configSource property. See here under "Using External Configuration Files" to check how it has been done for connection strings section. Perhaps, this may help you.
var configPath = YOUR_PATH;
if (!Directory.Exists(ProductFolder))
{
Directory.CreateDirectory(ProductFolder);
}
if (!File.Exists(configPath))
{
File.WriteAllText(configPath, Resources.App);
}
var map = new ExeConfigurationFileMap
{
ExeConfigFilename = configPath,
LocalUserConfigFilename = configPath,
RoamingUserConfigFilename = configPath
};
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
Then use config member as you want.
Another approach is to leave the config file with the executable file and move the relevant changeable sections to external xml files which can be in whatever location you choose.
If you are using your config file in a readonly capacity, then you can add the relevant chunks to an XML file in a different location using XML Inlcude. This won't work if you are trying to write values back directly to app.config using the Configuration.Save method.
app.config:
<?xml version="1.0"?>
<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
<appSettings>
<xi:include href="AppSettings.xml"/>
</appSettings>
<connectionStrings>
<xi:include href="ConnectionStrings.xml"/>
</connectionStrings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/></startup>
</configuration>
ConnectionStrings.xml:
<?xml version="1.0"?>
<add name="Example1ConnectionString"
connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example1DB;Persist Security Info=True;User ID=sa;Password=password"
providerName="System.Data.SqlClient" />
<add name="Example2ConnectionString"
connectionString="Data Source=(local)\SQLExpress;Initial Catalog=Example2DB;Persist Security Info=True;User ID=sa;Password=password"
providerName="System.Data.SqlClient" />
AppSettings.xml:
<?xml version="1.0"?>
<add key="Setting1" value="Value1"/>
<add key="Setting2" value="Value2"/>
A file URI looks like this:
file:///C:/whatever.txt
You can even define failover files in case the one you are trying to reference is missing. This pattern is from https://www.xml.com/pub/a/2002/07/31/xinclude.html:
<xi:include href="http://www.whitehouse.gov/malapropisms.xml">
<xi:fallback>
<para>
This administration is doing everything we can to end the stalemate in
an efficient way. We're making the right decisions to bring the solution
to an end.
</para>
</xi:fallback>

How to use application config file in C#?

I am trying to use a config file in my C# console application. I created the file within the project by going New --> Application Configuration File, and naming it myProjectName.config. My config file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SSDirectory" value="D:\Documents and Settings\****\MyDocuments\****" />
</appSettings>
</configuration>
The code to access it looks like this:
private FileValidateUtil()
{
sSDirFilePath = ConfigurationSettings.AppSettings["SSDirectory"];
if (sSDirFilePath == null)
Console.WriteLine("config file not reading in.");
}
Can anyone lend a hint as to why this is not working? (I am getting the error message.)
Thanks!!
badPanda
You can't change the name from app.config and expect ConfigurationManager to find it without providing it more information. Change the name of myProjectName.config back to app.config, rebuild, and you will see a file in the bin folder called myProjectName.exe.config. Then your call to ConfigurationManager.AppSettings should work correctly.
check the documentation
http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
First off, use ConfigurationManager instead of ConfigurationSettings.
Second, instead of saying "doesn't work", which provides no useful information, tell us what you're seeing. Does it compile? Does it throw an exception at runtime? Does your PC start to smoke and smell like melting plastic?
Try this:
public string GetSSDirectory()
{
string sSDirFilePath = string.Empty;
if (!ConfigurationManager.AppSettings.AllKeys.Contains("SSDirectory"))
{
Console.WriteLine("AppSettings does not contain key \"SSDirectory\"");
}
else
{
sSDirFilePath = ConfigurationManager.AppSettings["SSDirectory"];
Console.WriteLine("AppSettings.SSDirectory = \"" + sSDirFilePath + "\"");
}
return sSDirFilePath;
}

Categories

Resources