Replacing app.config at runtime - c#

Here is my appconfig:
<connectionStrings>
<add name ="cn" connectionString="User ID=YOUR_USER_HERE; Password=YOUR_PASS_HERE;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=.)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=.)));"/>
</connectionStrings>
I have tried this function:
public void updateConfigFile(string con)
{
//updating config file
XmlDocument XmlDoc = new XmlDocument();
//Loading the Config file
XmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
foreach (XmlElement xElement in XmlDoc.DocumentElement)
{
if (xElement.Name == "connectionStrings")
{
{
xElement.FirstChild.Attributes[1].Value = con;
}
}
}
//writing the connection string in config file
XmlDoc.Save("App.config");
}
That did not work. It ran without any error. But it did not save connectionString into appconfig file. I also tried this idea:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings["Blah"].ConnectionString = "Data Source=blah;Initial Catalog=blah;UID=blah;password=blah";
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
I get an error that says UnauthorizedAccess. ( I believe it is because of my school network)
These two options have not worked so far. I also tried to set ConfigurationManager.ConnectionStrings["cn"] to my custom connectionString. Since it is readonly, that failed too. Is there any other idea that I can replace connectionString at runtime?
Thanks in advance.

Changing the app configuration file must be done before your application starts, as certain keys are read by the runtime when your application is being bootstrapped only, and others are turned into readonly.
You can dynamically change the configuration entries of the AppSettings section only by referencing the System.Configuration assembly. All the other keys are by design read only.
If you don't want to alter the configuration before starting the application, you need to think about all the involved entities: who is going to read your connection string? If it is you, you can simply store it somewhere else or even in the AppSettings key. Instead, if external components require to read it from your configuration file, you have no chance that changing the architecture of your application in order to have a wrapper that does the changes before running your application.
The AppSettings key ca be changed in this way, after refencing the System.Configuration assembly (this is vital).
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="key1" value="configuration"/>
</appSettings>
</configuration>
Program.cs
using System;
using System.Configuration;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
System.Configuration.ConfigurationManager.AppSettings["key1"] = "changed";
var value = System.Configuration.ConfigurationManager.AppSettings["key1"];
Console.WriteLine($"This is the new key: {value}.");
}
}
}

Related

How to read the custom configuration settings in c#? [duplicate]

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

Specify AppSettingsReader() to look in different app.config for key

I'm using the AppSettingsReader() method to get a value from a given key in the app.config file:
var value = new AppSettingsReader().GetValue("SomeKey", typeof(string)) as string;
This is done in a class which is in a seperate assembly with its own app.config file. Now if I specify the key/value pair in this app.config:
<appSettings>
<add key="SomeKey" value="MyValue" />
</appSettings>
It throws the error:
"The key 'SomeKey' does not exist in the appSettings configuration section."
Because it looks in the App.config file from my main application which is, as stated before, in a different assembly. When I put my key/value pairs in there it works properly.
Is there a way of telling AppSettingsReader() to look in the app.config of the assembly from which it is called and not in the main (parent) assembly?
For this case you can use the ConfigurationManager class. It allows you to open configuration files from various places. To open a .config file, other than the one from the .exe, you could use the method OpenMappedExeConfiguration.
string pathToOtherConfigFile = ""; //you need to specify the path
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = pathToOtherConfig;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
var value = config.AppSettings["SomeKey"];

Modifying appSettings "file" attribute at runtime

string appConfPath = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName;
string fullPath = appConfPath + "\\Local\\RandFolder\\ThisOne\\application.settings.xml";
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.File = fullPath;
config.AppSettings.Settings.Add("Password", "djydyjdjtdtyjddj");
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
var temp = config.AppSettings;
I am currently trying to set the "file" attribute of my appSettings configuration and reference XML's included settings at runtime. I am unable to do this before compile because the XML settings file will change based on the local machines settings.
However, after making the above changes, the temp variable only contains the "Password" item and is unable to retrieve the other settings located in the included file path. I know the file attribute is being set but for some reason the referenced setting are still hidden. The application.settings.xml file looks like this...
<?xml version="1.0" encoding="utf-8"?>
<appSettings>
<add key="ServerLocation" />
<add key="PerforceURI" value="yuhsgbyluvgblsg" />
</appSettings>
Any help is greatly appreciated!
I won't try to critique what you are doing, but provide you with a simple explanation of what you are seeing.
ConfigurationManager.RefreshSection refreshes the section in the Configuration instance used by the static ConfigurationManager. It does not effect the Configuration instance you created by calling OpenExeConfiguration; for that to occur you would need to call OpenExeConfiguration again.

Writing key value pairs into app.config file

It works fine with Read, but I can't seem to get the Write happening. It doesn't throw any IO Exception when I try to write file. As if nothing happened.
Here is my code, please look at the GetValue() and SetValue() functions:
using System.Configuration;
public class AppConfig {
private string _username;
private string _password;
public AppConfig() {
_filePath = GetValue("Username");
_password = GetValue("Password");
//... more
}
public string Password {
get { return _password; }
set { SetValue("Password", value); _password = value; }
}
public string Username {
get { return _username; }
set { SetValue("Username", value); _username = value; }
}
private void SetValue(string key, string val) {
var cfg= ConfigurationManager
.OpenExeConfiguration(ConfigurationUserLevel.None);
cfg.AppSettings.Settings[key].Value = val;
cfg.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
private string GetValue(string key) {
return ConfigurationManager.AppSettings[key];
}
}
And this is the app.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key ="Password" value ="123456"/>
<add key ="Username" value ="hohoho"/>
</appSettings>
</configuration>
Any idea how to make the Write happening? Thank you.
The configuration system in .Net was not designed to let you programmatically save changes to the app.config in the assembly folder. I know there is a "Save" method there, but those changes actually save to a copy of the config file. The location of the copy depends on the scope of the setting.
Application Settings such as these:
<appSettings>
<add key="" value=""/>
</appSettings>
Have "application scope" if I recall correctly. If you use the Settings page in the project settings page or open Settings.settings in the Properties folder, you can choose the scope (User or Application).
This way, changes to the settings are persisted for the current user or for that specific version of the application. These copies are stored in a generated folder somewhere in the %APPDATA% for the appropriate account. The configuration system automatically loads the settings again depending on who's logged in.
This is why you also have an "Upgrade" method. It allows you to add settings to new versions of your application and upgrade the user's settings, causing only the new properties to be added to the user's copy. In this way, the setting in the app.config in the assembly folder is only the default value for the setting.
The comments above touch on why this is the way it works: Files inside Program Files are intended to remain untouched after installation and UAC ensures this.
I suggest reading up on the configuration system, it is quite powerful. If you still really want to modify app.config, you have to write custom code to modify the app.config file directly and
install into user's profile folders, or
always run your program as
an administrator
Try the following code
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings[key].Value = value;
config.Save();
ConfigurationManager.RefreshSection("appSettings");

How to open a config file app settings using ConfigurationManager?

My config file is located here:
"~/Admin/Web.config"
I tried opening it via the below code but it didn't work:
var physicalFilePath = HttpContext.Current.Server.MapPath("~/Admin/Web.config");
var configMap = new ConfigurationFileMap(physicalFilePath);
var configuration = ConfigurationManager.OpenMappedMachineConfiguration(configMap);
var appSettingsSection = (AppSettingsSection)configuration.GetSection("appSettings");
when appsettings line runs, it throws the below error message:
Unable to cast object of type 'System.Configuration.DefaultSection' to type 'System.Configuration.AppSettingsSection'.
My Web.Config looks like below:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<appSettings>
<add key="AdminUsername" value="Test1"/>
<add key="AdminPassword" value="Test2"/>
</appSettings>
<connectionStrings></connectionStrings>
</configuration>
How could I get the appsettings?
For web-app, you need to use System.Web.Configuration.WebConfigurationManager class and no need to set absolute path.
var web=System.Web.Configuration.WebConfigurationManager
.OpenWebConfiguration("~/admin/web.config");
String appValue=web.AppSettings.Settings["key"].Value;
If you are looking for adding some stuff to the Web.config, and then reading it from the code.
What you need is Custom Configuration Sections in Web.config
Look here:
How do I define custom web.config sections with potential child elements and attributes for the properties?
and here:
Creating Custom Configuration Sections in Web.config - 4GuysFromRolla.com

Categories

Resources