Changes in App.config do not reflect after restarting the application - c#

I am using an app.config file to store the dynamic parameters of my application. The problem is, when I change a value in app.config file, and start the application, it doesn't load the new value from config file. Seems like the values in app.config file are being read and embedded in exe file only at compile time!
This is how I read the config file:
public class Helper
{
static Helper()
{
Foo = ConfigurationManager.AppSettings["Foo"];
}
public static string Foo { get; set; }
}
Am I missing something?

Are you sure you are changing the correct file? You don't want to change the app.config file, but the <exename>.exe.config file, in the same directory as the .exe
The app.config file is what you edit in the ide, but when you compile your app this file is renamed to <exename>.exe.config and copied to the output directory when you compile. The .exe looks for a file with the same name as itself with the .config extension when looking for the default configuration.

The static nature of your class and method may be causing you the issue. Maybe refactor it to the following...
public static class Helper
{
public static string Foo
{
get
{
return ConfigurationManager.AppSettings["Foo"];
}
}
}
Actually, thinking about it, it doesn't help you a great deal since ConfigurationManager.AppSettings["Foo"] is already (effectively) a static call - you're just adding another layer of abstraction that may well not be required.

Related

How can a C# library detect if app.config exists and manually load a config file if not?

I have a static C# library project which relies on configuration. This library may be used in two scenarios:
From managed C# applications. Easy - the application's app.config file will be used, via ConfigurationManager
From unmanaged C++ applications (using COM)
In case 2. there is no app.config. I would like the library to still be able to use ConfigurationManager but it should explicitly load an XML config file with the same structure as app.config.
This question talks about how to manually load a config file: Loading custom configuration files
But how can the library detect which case 1/2 its in? I would be happy with an InitLib method which passes a config name, or a static initializer, but I can't see how to put the pieces together.
The config file name to use in case 2 could either be passed in directly, or hardcoded as MyAssembly.Lib.config or similar.
So to clarify: you have a class in a class library, the library references System.Configuration.ConfigurationManager.dll, and the class looks does something like this:
using System.Configuration;
namespace FooLibrary
{
public class Foo
{
public Foo()
{
var bar = ConfigurationManager.AppSettings("FooLibrary.Foo.Bar");
}
}
}
Now when you call this class from a console application, say, Baz.exe, there will exist a Baz.exe.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="FooLibrary.Foo.Bar" value="Baz" />
</appSettings>
</configuration>
And all works.
It doesn't work when the library runs in a context without a configuration file. While I think it's possible to give an unmanaged application, say, Qux.exe a configuration file Qux.exe.config which .NET will then read for assemblies loaded from that executable, that situation isn't ideal. Even if that'd work (I think, but am not sure, that it's just a file name convention, not something the runtime does for executables on startup). It's possible that the executable running the assembly is not under your control anyway (e.g. somewhere in System32).
While you could let the library load a configuration file relative to its own location, and to answer your question:
But how can the library detect which case 1/2 its in?
You could just test for the AppSettings key anyway, and if not found, assume you've got no configuration file, and open that of the DLL instead:
public class Foo
{
private readonly string _bar;
public Foo()
{
// Read from .exe.config or Web.config
_bar = ConfigurationManager.AppSettings("FooLibrary.Foo.Bar");
if (string.IsNullOrEmpty(_bar))
{
// Assume that if not present, own config must be loaded:
var dllConfigPath = Assembly.GetExecutingAssembly().Location;
// Will just append ".config" despite its name
Configuration config = ConfigurationManager.OpenExeConfiguration(dllConfigPath);
_bar = config.AppSettings.Settings["test"]?.Value;
if (string.IsNullOrEmpty(_bar))
{
// Not found in both configs, now what?
}
}
}
}
And you should refactor it a bit to read multiple variables. And now you want to unit test this code, so you'll have to provide a configuration file there as well.
These problems are solved by not reading the configuration in class libraries, but in application startup, and passing the appropriate values to the constructor of the classes from the library:
public Foo(string bar) { ... }
// And then from your executable:
var foo = new Foo(ConfigurationManager.AppSettings["FooLibrary.Foo.Bar"));
// And your unit test
var foo = new Foo("FromTest");
But you can't pass constructor parameters through COM, which the compiler will tell you as well. So you'll have to provide a parameterless constructor, and something like an InitLib(string bar) method for COM only.
And if you, despite all the above, still insist on reading the config there, then it would look something like this:
public class Foo
{
private string _bar;
public Foo()
{
// Read from .exe.config or Web.config
_bar = ConfigurationManager.AppSettings["FooLibrary.Foo.Bar"];
// Can't throw here if _bar is empty, maybe we're called from COM
}
public void ReadDllConfig()
{
// Assume that if not present, own config must be loaded:
var dllConfigPath = Assembly.GetExecutingAssembly().Location;
// Will just append ".config" despite its name
Configuration config = ConfigurationManager.OpenExeConfiguration(dllConfigPath);
_bar = config.AppSettings.Settings["test"]?.Value;
// Can throw here if _bar is empty
}
public void FooForCom()
{
// TODO: test _bar again, it can still be null.
}
}

Two projects in a solution that use different default paths

I have two projects in my solution, ChatProject and ChatProjectTest.
ChatProjectTest has a single class file that has many methods that test methods in ChatProject.
My problem is that ChatProject uses some files, like data.bin and log.txt, that are stored in the .exe folder (that is ChatProject\bin\Debug\ChatProject.exe). I want ChatProjectTest to use the same files, and not go ahead and create or load new files in its own .exe folder (ChatProjectTest\bin\Debug\ChatProject.exe), like it does currently.
To be clear, the file paths are stored in constant variables in ChatProject like this:
private static string DATABASE_NAME = "data.bin";
I didn't hardcode their paths.
One solution can be configuring your projects to put all the output files into the same the same bin/ directory under your solution root (instead of two separate bin/ folders).
To do this, go to the "Build" tab under project settings and set "Output path" to
$(SolutionDir)Bin\$(Configuration)\
Repeat this for both of your projects.
If you don't specify a path to a file it looks in the current directory for them.
To use the same ones, you either have to specify some sort of relative path from the Test Output, or build the tests into the same folder as the Project.
You may allow the target file path to be injected e. g. via an optional constructor parameter:
public class SampleClass
{
private readonly string OutputDirectory;
public SampleClass(string outputDirectory = ".")
{
OutputDirectory = outputDirectory;
}
public void WriteData(string data)
{
File.AppendAllText($"{OutputDirectory}\\data.bin", data);
}
}
[TestClass]
public class SampleClassTest
{
[TestMethod]
public void WriteDataTest()
{
var sut = new SampleClass("..\\..\\..\\ChatProject\\bin\\Debug");
sut.WriteData("data");
}
}

Winform app: Compiled App.Config-like file?

I would like to know if there is some kind of built-in compiled "App.Config" file?
The goal is to be able to have one of our library which can have some of its default values overriden when being used in some client application.
Thoses DLL are loaded dynamically, so I cannot just give a parameter in the constructor.
I don't want to use the App.config file because the user can edit those values(otherwise it would have been just fine).
There are several different ways to solve this.
If you like the idea of config-files, but do not want to have it accessible by end users in the compiled application, perhaps you can create your own settings-file in a format that suits your needs, and include it as an embedded resource?
An upside of this would be that you can access it as a regular XML or config file or whatever in Visual Studio, while it will be hidden from the end user. Personally I think I would prefer this to using special code / classes to store config-data.
To include a file as an embedded resource, include it into one of your Visual Studio projects, right click the included file and select Properties. Now under Build Action, select Embedded Resource. When you build your project now, the file will be included internally in the produced .dll-file.
I'm sure you'll be able to find lot's of info about how to access an embedded resource from code. As an example, there are some useful examples in this SO question. Note especially this answer, which also mentions an alternative way to include a resource.
Expanding on my comment... you could just make an interface for a settings class with hardcoded values, and then make different implementations of that interface. To actually change which one to use, all you'd need to do is comment/uncomment the line that instantiates an object into your settings variable before you build the dll:
public class MainDllProject
{
ISettings m_Settings;
public MainDllProject()
{
// Change this before compiling
this.m_Settings = new DebugSettings();
//this.m_Settings = new DeploySettings();
// use settings from the settings class
String setting1 = this.m_Settings.Setting1
Int32 setting2 = this.m_Settings.Setting2
//...
}
}
public interface ISettings
{
String Setting1 { get; }
Int32 Setting2 { get; }
}
public class DebugSettings: ISettings
{
public String Setting1
{ get { return "data_debug";} }
public Int32 Setting2
{ get { return 2;} }
}
public class DeploySettings: ISettings
{
public String Setting1
{ get { return "data_deploy";} }
public Int32 Setting2
{ get { return 1;} }
}
On finding "a built-in way of solving this", as you said, maybe this will be useful for you...
You can actually use the Visual Studio build configuration manager to build with different settings. Using the #If directives, you can automatically make it select which lines of code to use based on the configuration. A simple example based on the default debug configuration, which adds the "DEBUG=True" variable automatically:
public MainDllProject()
{
#If DEBUG Then
this.m_Settings = new DebugSettings();
#ElseIf
this.m_Settings = new DeploySettings();
#End if
}
You can actually make your own custom-named variables to check on just like that DEBUG one: after making a configuration, open the Project properties window, go to the Compile tab, select that specific configuration in the dropdown, and then at the bottom select "Advanced Compile Options". In there is a line "Custom constants" in which you can add such variables. For simple if-statements, you can just make a boolean like "CLIENTDEPLOY=True", and then you can use #If CLIENTDEPLOY Then in your code.

App.config multi-project access strategies

My current solution has 3 project with 2 app.config (one for common settings and another for service settings). As of now I'm simply creating static classes to act as a mediator to access values. I do this so I don't have to write ConfigurationManager.AppSettings["SomeKey"] everywhere. This works fine until you want to access an app.config file from a different project.
Here is what I'm currently doing (all properties omitted for brevity).
public class ServiceConfiguration
{
public static readonly string SyncEvery = ConfigurationManager.AppSettings["SyncEveryMinutes"];
}
How can I access an app.config file located in another project? I thought perhaps setting VS to copy the file to the output directory would do the trick however my configuration object is still null.
I can't imaging many good reasons to read another app's configuration in the first place, it just opens a can of worms that isn't worth dealing with.
Expose a class that exposes the project's configured values as properties, and access them from a consuming class.
public class FirstProjectClass
{
public static int SyncEveryMinutes
{
get { return (int)ConfigurationManager.AppSetting["SyncEveryMinutes"] };
}
}
public class SecondProjectClass
{
public void ShowConfigedValue()
{
Console.Writeline("Syncing every {0} minutes", FirstProjectClass.SyncEveryMinutes);
}
}
if you've got complex configuration requirements you can also look into custom configuration sections
ConfigurationManager.OpenExeConfiguration can be helpfull:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
Also: what Jason said - it is usually a bad idea.

How do I specify the name of my application's App.config file in WPF?

This is very frustrating... I can set the Configuration File for a Windows Forms Application just fine. Consider this:
public static void Main(){
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"SharedAppConfig.config");
//do other things
}
However, in a WPF application, this doesn't seem to work! If I set this value, the value of the AppDomain.CurrentDomain.SetupInformation.ConfigurationFile property is correct, but any calls to that configuration file while debugging yield no results. There are WCF configuration settings in an App.config that I need to share between application, so this is my proposed solution. Is it possible to dynamically set the location of my config file in WPF?
Help! Thanks!
You should be able to do something along the lines of:
using System.Configuration;
public class TryThis
{
Configuration config = ConfigurationManager.OpenExeConfiguration("C:\PathTo\app.exe");
public static void Main()
{
// Get something from the config to test.
string test = config.AppSettings.Settings["TestSetting"].Value;
// Set a value in the config file.
config.AppSettings.Settings["TestSetting"].Value = test;
// Save the changes to disk.
config.Save(ConfigurationSaveMode.Modified);
}
}
NOTE: This will attempt to open a file named app.exe.config at C:\PathTo. This also REQUIRES that a file exists at the same path with the name "app.exe". The "app.exe" file can just be an empty file though. For your case I'd almost make a shared "Config.dll" library that would handle the config file.
~md5sum~
Is this on the service side or the client side? If on the service side, it is often the case that the service is running in its own AppDomain, so that if you set AppDomain.CurrentDomain.SetData(...) it won't apply to the service configuration.
I'm not entirely sure how to get around this, but you should be able to control the service's configuration by implementing your own ServiceHost.

Categories

Resources