I'm working on a C# class library that needs to be able to read settings from the web.config or app.config file (depending on whether the DLL is referenced from an ASP.NET web application or a Windows Forms application).
I've found that
ConfigurationSettings.AppSettings.Get("MySetting")
works, but that code has been marked as deprecated by Microsoft.
I've read that I should be using:
ConfigurationManager.AppSettings["MySetting"]
However, the System.Configuration.ConfigurationManager class doesn't seem to be available from a C# Class Library project.
What is the best way to do this?
For a sample app.config file like below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="countoffiles" value="7" />
<add key="logfilelocation" value="abc.txt" />
</appSettings>
</configuration>
You read the above application settings using the code shown below:
using System.Configuration;
You may also need to also add a reference to System.Configuration in your project if there isn't one already. You can then access the values like so:
string configvalue1 = ConfigurationManager.AppSettings["countoffiles"];
string configvalue2 = ConfigurationManager.AppSettings["logfilelocation"];
You'll need to add a reference to System.Configuration in your project's references folder.
You should definitely be using the ConfigurationManager over the obsolete ConfigurationSettings.
Update for .NET Framework 4.5 and 4.6; the following will no longer work:
string keyvalue = System.Configuration.ConfigurationManager.AppSettings["keyname"];
Now access the Setting class via Properties:
string keyvalue = Properties.Settings.Default.keyname;
See Managing Application Settings for more information.
Right click on your class library, and choose the "Add References" option from the Menu.
And from the .NET tab, select System.Configuration. This would include the System.Configuration DLL file into your project.
I'm using this, and it works well for me:
textBox1.Text = ConfigurationManager.AppSettings["Name"];
Read From Config:
You'll need to add a reference to the configuration:
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 the configuration:
Properties.Settings.Default.keyName = value;
Properties.Settings.Default.Save();
You must add a reference to the System.Configuration assembly to the project.
You might be adding the App.config file to a DLL file. App.Config works only for executable projects, since all the DLL files take the configuration from the configuration file for the EXE file being executed.
Let's say you have two projects in your solution:
SomeDll
SomeExe
Your problem might be related to the fact that you're including the app.config file to SomeDLL and not SomeExe. SomeDll is able to read the configuration from the SomeExe project.
Try this:
string keyvalue = System.Configuration.ConfigurationManager.AppSettings["keyname"];
In the web.config file this should be the next structure:
<configuration>
<appSettings>
<add key="keyname" value="keyvalue" />
</appSettings>
</configuration>
Step 1: Right-click on references tab to add reference.
Step 2: Click on Assemblies tab
Step 3: Search for 'System.Configuration'
Step 4: Click OK.
Then it will work.
string value = System.Configuration.ConfigurationManager.AppSettings["keyname"];
I had the same problem. Just read them this way:
System.Configuration.ConfigurationSettings.AppSettings["MySetting"]
web.config is used with web applications. web.config by default has several configurations required for the web application. You can have a web.config for each folder under your web application.
app.config is used for Windows applications. When you build the application in Visual Studio, it will be automatically renamed to <appname>.exe.config and this file has to be delivered along with your application.
You can use the same method to call the app settings values from both configuration files:
System.Configuration.ConfigurationSettings.AppSettings["Key"]
As I found the best approach to access application settings variables in a systematic way by making a wrapper class over System.Configuration as below
public class BaseConfiguration
{
protected static object GetAppSetting(Type expectedType, string key)
{
string value = ConfigurationManager.AppSettings.Get(key);
try
{
if (expectedType == typeof(int))
return int.Parse(value);
if (expectedType == typeof(string))
return value;
throw new Exception("Type not supported.");
}
catch (Exception ex)
{
throw new Exception(string.Format("Config key:{0} was expected to be of type {1} but was not.",
key, expectedType), ex);
}
}
}
Now we can access needed settings variables by hard coded names using another class as below:
public class ConfigurationSettings:BaseConfiguration
{
#region App setting
public static string ApplicationName
{
get { return (string)GetAppSetting(typeof(string), "ApplicationName"); }
}
public static string MailBccAddress
{
get { return (string)GetAppSetting(typeof(string), "MailBccAddress"); }
}
public static string DefaultConnection
{
get { return (string)GetAppSetting(typeof(string), "DefaultConnection"); }
}
#endregion App setting
#region global setting
#endregion global setting
}
Also, you can use Formo:
Configuration:
<appSettings>
<add key="RetryAttempts" value="5" />
<add key="ApplicationBuildDate" value="11/4/1999 6:23 AM" />
</appSettings>
Code:
dynamic config = new Configuration();
var retryAttempts1 = config.RetryAttempts; // Returns 5 as a string
var retryAttempts2 = config.RetryAttempts(10); // Returns 5 if found in config, else 10
var retryAttempts3 = config.RetryAttempts(userInput, 10); // Returns 5 if it exists in config, else userInput if not null, else 10
var appBuildDate = config.ApplicationBuildDate<DateTime>();
If your needing/wanting to use the ConfigurationManager class...
You may need to load System.Configuration.ConfigurationManager by Microsoft via NuGet Package Manager
Tools->NuGet Package Manager->Manage NuGet Packages for Solution...
Microsoft Docs
One thing worth noting from the docs...
If your application needs read-only access to its own configuration,
we recommend that you use the GetSection(String) method. This method
provides access to the cached configuration values for the current
application, which has better performance than the Configuration
class.
I strongly recommend you to create a wrapper for this call. Something like a ConfigurationReaderService and use dependency injection to get this class. This way you will be able to isolate this configuration files for test purposes.
So use the ConfigurationManager.AppSettings["something"]; suggested and return this value. With this method you can create some kind of default return if there isn't any key available in the .config file.
Just for completeness, there's another option available for web projects only:
System.Web.Configuration.WebConfigurationManager.AppSettings["MySetting"]
The benefit of this is that it doesn't require an extra reference to be added, so it may be preferable for some people.
I always create an IConfig interface with typesafe properties declared for all configuration values. A Config implementation class then wraps the calls to System.Configuration. All your System.Configuration calls are now in one place, and it is so much easier and cleaner to maintain and track which fields are being used and declare their default values. I write a set of private helper methods to read and parse common data types.
Using an IoC framework you can access the IConfig fields anywhere your in application by simply passing the interface to a class constructor. You're also then able to create mock implementations of the IConfig interface in your unit tests so you can now test various configuration values and value combinations without needing to touch your App.config or Web.config file.
Please check the .NET version you are working on. It should be higher than 4. And you have to add the System.Configuration system library to your application.
You can use the below line. In my case it was working:
System.Configuration.ConfigurationSettings.AppSettings["yourKeyName"]
You must take care that the above line of code is also the old version and it's deprecated in new libraries.
The ConfigurationManager is not what you need to access your own settings.
To do this you should use
{YourAppName}.Properties.Settings.{settingName}
I was able to get the below approach working for .NET Core projects:
Steps:
Create an appsettings.json (format given below) in your project.
Next create a configuration class. The format is provided below.
I have created a Login() method to show the usage of the Configuration Class.
Create appsettings.json in your project with content:
{
"Environments": {
"QA": {
"Url": "somevalue",
"Username": "someuser",
"Password": "somepwd"
},
"BrowserConfig": {
"Browser": "Chrome",
"Headless": "true"
},
"EnvironmentSelected": {
"Environment": "QA"
}
}
public static class Configuration
{
private static IConfiguration _configuration;
static Configuration()
{
var builder = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json");
_configuration = builder.Build();
}
public static Browser GetBrowser()
{
if (_configuration.GetSection("BrowserConfig:Browser").Value == "Firefox")
{
return Browser.Firefox;
}
if (_configuration.GetSection("BrowserConfig:Browser").Value == "Edge")
{
return Browser.Edge;
}
if (_configuration.GetSection("BrowserConfig:Browser").Value == "IE")
{
return Browser.InternetExplorer;
}
return Browser.Chrome;
}
public static bool IsHeadless()
{
return _configuration.GetSection("BrowserConfig:Headless").Value == "true";
}
public static string GetEnvironment()
{
return _configuration.GetSection("EnvironmentSelected")["Environment"];
}
public static IConfigurationSection EnvironmentInfo()
{
var env = GetEnvironment();
return _configuration.GetSection($#"Environments:{env}");
}
}
public void Login()
{
var environment = Configuration.EnvironmentInfo();
Email.SendKeys(environment["username"]);
Password.SendKeys(environment["password"]);
WaitForElementToBeClickableAndClick(_driver, SignIn);
}
Another possible solution:
var MyReader = new System.Configuration.AppSettingsReader();
string keyvalue = MyReader.GetValue("keyalue",typeof(string)).ToString();
I have been trying to find a fix for this same issue for a couple of days now. I was able to resolve this by adding a key within the appsettings tag in the web.config file. This should override the .dll file when using the helper.
<configuration>
<appSettings>
<add key="loginUrl" value="~/RedirectValue.cshtml" />
<add key="autoFormsAuthentication" value="false"/>
</appSettings>
</configuration>
extra : if you are working on a Class Library project you have to embed the settings.json file.
A class library shouldn't really be directly referencing anything in
app.config - the class doesn't have an app.config, because it's not an
application, it's a class.
Go to the JSON file's properties.
Change Build Action -> Embedded resource.
Use the following code to read it.
var assembly = Assembly.GetExecutingAssembly();
var resourceStream = assembly.GetManifestResourceStream("Assembly.file.json");
string myString = reader.ReadToEnd();
now we have a JSON string we can Deserialize it using JsonConvert
if you didn't embed the file inside the assembly you can't use only the DLL file without the file
I'm using Visual Studio for Mac version 17.0.6.
As you can see on this screenshot it is not possible to add a reference to System.Configuration.
Solution:
install NuGet Package - System.Configuration.ConfigurationManager.
Create app.config file and set "Build action" to "EmbeddedResource"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="name" value="Joe"/>
</appSettings>
</configuration>
using System.Configuration;
enjoy)
string name = ConfigurationManager.AppSettings["name"];
BTW: Do not add an app.config for a library
I found the answer in this link https://stackoverflow.com/a/1836938/1492229
It's not only necessary to use the namespace System.Configuration. You have also to add the reference to the assembly System.Configuration.dll , by
Right-click on the References / Dependencies
Choose Add Reference
Find and add System.Configuration.
This will work for sure.
Also for the NameValueCollection you have to write:
using System.Collections.Specialized;
Here's an example: App.config
<applicationSettings>
<MyApp.My.MySettings>
<setting name="Printer" serializeAs="String">
<value>1234 </value>
</setting>
</MyApp.My.MySettings>
</applicationSettings>
Dim strPrinterName as string = My.settings.Printer
I have a C# unit test project with application settings in the app.config file. I am testing a class that exists in a different project. That class depends on both, ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings.
The project that the class being tested resides in does not have an app.config file. I would have thought that because the class is being instantiated in the context of the unit test project that it would use the unit test project's app.config file. Indeed, that does seem to be the case for the connection string.
The class retrieves the connection string without any issues. However, when the class tries to retrieve any application settings the configuration manager always returns null. What is going on here?
Edit 1
I thought maybe it would be a good idea to try load some settings in the test project to see what happens. I tried to load the setting in the unit test immediately before calling the code that instantiates the class in the external project. Same result, nothing. I guess I can exclude the other project from the equation for the time being.
Here is an excerpt from my config file:
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyNamespace.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
...
<applicationSettings>
<MyNamespace.Properties.Settings>
<setting name="Bing_Key"
serializeAs="String">
<value>...</value>
</setting>
</MyNamespace.Properties.Settings>
</applicationSettings>
and here is how I am attempting to load the setting:
string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"];
Consider refactoring your code that accesses the config to use a wrapper. Then you can write mocks for the wrapper class and not have to deal with the importing of the configuration file for the test.
In a library that is common to both, have something like this:
public interface IConfigurationWrapper {
string GetValue(string key);
bool HasKey(string key);
}
Then, in your libraries that need to access config, inject an instance of this interface type into the class that needs to read config.
public class MyClassOne {
private IConfigurationWrapper _configWrapper;
public MyClassOne(IConfigurationWrapper wrapper) {
_configWrapper = wrapper;
} // end constructor
public void MethodThatDependsOnConfiguration() {
string configValue = "";
if(_configWrapper.HasKey("MySetting")) {
configValue = _configWrapper.GetValue("MySetting");
}
} // end method
} // end class MyClassOne
Then, in one of your libraries, create an implementation that depends on the config file.
public class AppConfigWrapper : IConfigurationWrapper {
public string GetValue(string key) {
return ConfigurationManager.AppSettings[key];
}
public bool HasKey(string key) {
return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant());
}
}
Then, in the code that calls your class.
//Some method container
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper());
dataClass.MethodThatDependsOnConfiguration();
Then in your test, you are free from dependency bondage. :) You can either create a fake version that implements IConfigurationWrapper and pass it in for your test, where you hard-code the return values from the GetValue and HasKey functions, or if you're using a mocking library like Moq:
Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>();
fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config.");
MyClassOne testObject = new MyClassOne(fakeWrapper.Object);
testObject.MethodThatDependsOnConfiguration();
Here is an article that covers the concept (albeit, for web forms, but the concepts are the same): http://www.schwammysays.net/how-to-unit-test-code-that-uses-appsettings-from-web-config/
You mentioned settings in the project properties. See if you can access the setting this way:
string test = Properties.Settings.Default.Bing_Key;
You may need to get the executing assembly of where the project settings file is defined, but try this first.
EDIT
When using Visual Studio's project settings file, it adds stuff to your app.config and creates the app.config if it is not present. ConfigurationManager CAN'T touch these settings! You can only get to these specific generated project.settings file from using the above static method. If you want to use ConfigurationManager, you will need to hand write your app.config. Add your settings to it like so:
<appSettings>
<add key="bing_api" value="whatever"/>
</appSettings>
If you're using .NET Core your problem could be a known issue caused by the fact that the test process runs as testhost.dll (or testhost.x86.dll), which means the runtime config file is expected to be named "testhost.dll.config" (or "testhost.x86.dll.config"), instead of the app.config output (ex: "MyLibrary.Tests.dll.config").
To fix it, add the code below to your project file (.csproj, etc) inside of root node <Project>. During build, two copies of app.config will be put in the output directory and named "testhost.dll.config" and "testhost.x86.dll.config", which will get your app settings working again. (You only need 1 of these files but it's safer to include both.)
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.x86.dll.config" />
</Target>
I recommend app.config only as a temporary solution. If you're like me you might have run into the problem while upgrading a .NET Framework project to .NET Core and needed a quick fix. But don't forget to look into the new, more elegant solutions provided by .NET Core for storing app settings.
And then he screamed "NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO".
Cite: I have a C# unit test project with application settings in the app.config file. I am testing a class that exists in a different project. That class depends on both, ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings.
You don't do this. EVER!!!! Why? because you have now created a dependency. Instead, use dependency injection so the class can do its work without having to peak into the configuration file that belongs to the application.
i am first time using any DI framework called unity app block. i am getting error. the error is :-
The type name or alias ILogger could not be resolved. Please check your configuration file and verify this type name.
i was trying inject dependency from out side into my main proj. suppose i want to save data to anywhere by dependency. say suppose i want to save data to file or console, database etc.
here i am telling you how i develop my app for incorporating Unity.
first i create a class library project called "Ilogger" it has only one interface. full code of this interface
namespace Ilogger
{
public interface ILog
{
void Write(string msg);
}
}
secondly i create a class library project called "ConsoleWriter" it has only one class which inherit Ilogger interface.so i just add the reference of Ilogger project into ConsoleWriter proj. full code of this ConsoleWriter
namespace ConsoleWriter
{
public class ConsoleWriter : Ilogger.ILog
{
#region ILog Members
public void Write(string msg)
{
Console.WriteLine(msg);
Console.ReadLine();
}
#endregion
}
}
3rd step i create a class library project called "FileWriter
" it has only one class which inherit Ilogger interface.so i just add the reference of Ilogger project into FileWriter proj. full code of this FileWriter
namespace FileWriter
{
public class FileWriter : Ilogger.ILog
{
#region IWriter Members
public void Write(string msg)
{
using (StreamWriter streamWriter = new StreamWriter("c:\\TestUnity.txt", true))
{
streamWriter.WriteLine(msg);
}
}
#endregion
}
}
next i create my win apps from where i inject dependecy at runtime. in this project i add some dll reference of unity block and those are.
Microsoft.Practices.Unity
Microsoft.Practices.Unity.Configuration
system.configuration
i add one app.config file and it has entry like
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias type="ILogger.ILog, ILogger" alias="ILogger" />
<namespace name="ILogger.ILog"/>
<container>
<register mapTo="FileWriter.FileWriter, FileWriter" name="MyFileWriter" type="ILogger"/>
<register mapTo="ConsoleWriter.ConsoleWriter, ConsoleWriter" name="MyConsoleWriter" type="ILogger"/>
</container>
</unity>
</configuration>
here is the main code from where error is thrown
string strCountryCode = "USA";
IDictionary<string, string> loggers = new Dictionary<string, string>();
loggers.Add("USA", "MyFileWriter");
loggers.Add("GBR", "MyConsoleWriter");
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)System.Configuration.ConfigurationManager.GetSection("unity");
//container.LoadConfiguration();
section.Containers.Default.Configure(container);
Ilogger.ILog logger = container.Resolve<Ilogger.ILog>(loggers[strCountryCode]);
logger.Write("Hello World");
this line giving error section.Containers.Default.Configure(container);
i am using DI framework unity first time so i am not being able to catch what mistake i made. so please anyone help me to get the error and tell me how to fix it.
thanks
there may be several issues;
in the entry point of application, where you are trying to read unity configuration, you need to add the assembly which contains ILog interface; the assembly may be missing.
you need to add aliases using full paths; the full path needs to include the assembly name.
in order to observe exact problem, instead of using a configuration file, try to make registrations in the code.
I've created a custom class that inherits from System.Configuration.ConfigurationSection, implemented like this (this is obviously just to get the real configuration running):
public class Config : ConfigurationSection
{
[ConfigurationProperty("quoteOfTheDay", DefaultValue = "It is what it is.", IsRequired = false)]
public string QuoteOfTheDay
{
get
{
return this["quoteOfTheDay"] as string;
}
}
[ConfigurationProperty("yourAge", IsRequired = true)]
public int YourAge
{
get
{
return (int)this["yourAge"];
}
}
}
The full namespace + name of the class is MyApp.Core.Config, it's located in the MyApp.Core project which compiles to the MyApp.Core.dll assembly. I've then referenced this project from my ASP.NET/MVC3 project, which is called MyApp.UI. I've edited the Web.config file to add the sectionGroup and section elements like this:
<configSections>
<sectionGroup name="myAppConfigGroup">
<section name="myAppSection"
type="MyApp.Core.Config, MyApp.Core, Version=1.0.0.0, Culture=neutral, PublicKey=null"
allowLocation="true"
allowDefinition="Everywhere" />
</sectionGroup>
</configSections>
<myAppConfigGroup>
<myAppSection>
</myAppSection>
</myAppConfigGroup>
However, it doesn't seem like the type MyApp.Core.Config get used to validate the configuration or provide intelli-sense as I edit the configuration. Here's some observations I've made:
I defined the yourAge property as IsRequired = true and the application runs fine without it.
I can even change the type (to some type that doesn't even exist like Foo.Bar) in the <section> element, and everything still runs fine
But if I remove the <section> element, the app doesn't run.
I'm baffled, any help?
You are probably not using the configuration?
If you are not using it, it will only do a check if the root nodes are registered via configSections but it will not look at the details at that point.
When you will actually load it using ConfigurationManager.GetSection the settings will be validated and in your case of this configuration it will trigger an exception telling that the required YourAge property is missing.
in code i can do some thing like this:
container.Register(AllTypes.FromAssemblyNamed("AssemblyName"));
can i do the same thing using Configuration file "Windsor.Config"???
Responding to your comment.
There's also a 3rd way (in Windsor 2.5, currently in beta 2 - final release is expected very soon).
You can have each of your modules reference Windsor, and each module have its own set of Installers.
Than you can use the new directory scanning capability to install components from all these assemblies:
// In your root assembly
var container = new WindsorContainer();
container.Install(
FromAssembly.This(),
FromAssembly.InDirectory(new AssemblyFilter("Modules")),
Configuration.FromAppConfig()
)
In addition if you have components following identical structure you can also register components from multiple assemblies in single installer. See more here.
container.Register(
AllTypes.FromAssemblyInDirectory(new AssemblyFilter("Modules"))
.Where(t=>t.Namespace.EndsWith(".Services"))
.WithService.DefaultInterface()
);
I am pretty sure that only with the fluent configuration API can you set up conventions for your application so that as you create new components you aren’t required to register them individually, as you example shows.
You can write a trivial facility to do that, e.g.:
AllTypesConfig.xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<facilities>
<facility id="alltypes">
<assemblies>
<item>Castle.Core</item>
</assemblies>
</facility>
</facilities>
</configuration>
code:
public class AllTypesFacility : AbstractFacility {
protected override void Init() {
var asmList = FacilityConfig.Children["assemblies"].Children;
foreach (var asm in asmList)
Kernel.Register(AllTypes.FromAssemblyNamed(asm.Value).Pick());
}
}
var container = new WindsorContainer(#"..\..\AllTypesConfig.xml");
container.AddFacility("alltypes", new AllTypesFacility());
container.Resolve<NullLogger>();
If you need more flexibility it will get progressively harder to represent the fluent config in XML.