Class design/best approach for initializing a user configuration file - c#

I want to initialize a user configuration through a user configuration file. The path for the file can be read from the registry.
The file is located in a folder with the user's name.
So I need the following functionality:
Reading a string from registry
building the path to the configuration file
Reading the file into a configuration object
Now there are several approaches to handle this:
First, I need
one "helper"-class for getting the file path (let's call it Shared)
one "container"-class for the configuration information (let's call it Configuration)
So, Shared has a function/property like UserConfigurationFile which returns the path to the configuration file.
To get the path to the file I have a function InitializeUserConfigurationFile() which is called in the constructor of Shared:
class Shared {
public Shared()
{
InitializeUserConfigurationFile();
}
void InitializeUserConfigurationFile()
{
//
// Reads username
//
//
// Reads path from Registry
//
//
// etc.
//
}
//
// etc.
//
}
Any better suggestions?
When I want to Initialize my Container I have different options:
Is it best to initialize the user configuration within the constructor?
Sth. like:
class Container
{
Shared shared = new Shared();
public Container()
{
InitializeUserConfiguration();
}
void InitializeUserConfiguration()
{
LoadConfiguration(shared.UserConfigurationFile);
}
void LoadConfiguration(string filename)
{
//
// Initializes all parameters frome filename
//
}
}
Or through two steps (through an own method LoadConfiguration())?
Sth. like:
Shared shared = new Shared();
Container container = new Container();
container.LoadConfiguration(shared.UserConfigurationFile);
Or inside the constructor of Container by delivering a filename?
Sth. like:
Shared shared = new Shared();
Container container = new Container(shared.UserConfigurationFile);
or everything in Container..?
There are so many ways...
I hope somebody knows a best-approch...
Regards,
Inno

It is better to use standard configuration classes exist in .net. Such as ApplicationSettingsBase and Configuration.
Here you can find good article series:
Unraveling the Mysteries of .NET 2.0 Configuration
Unraveling the Mysteries of .NET 2.0 Configuration
Cracking the Mysteries of .NET 2.0 Configuration

For best practices, don't use the registry, and don't reinvent the wheel.
Since you didn't mention it, have you looked at the System.Configuration namespace?
The .NET Framework constains a perfectly good configuration system that is well tested. It is also the domain of Sys Admins, who also know about config files and the accompanying tools.
So it is unclear why you are reinventing the wheel, possibly making it a little less round.
There are practical reasons to shun the Registry (distribution, backup) but also, as arbiter points out, it is not going to move to other (future) platforms. Did you notice that those namespaces are not starting with System ?

Related

How to acced to my app.config from c# interactive?

I initialized the interactive element with the project from the context menu of my project.
I am testing a function in C# interactive that needs to read my app.config file to get a connectionstring.
I got the next error:
No connection string named 'ccnName' could be found in the application config file.
When I use the next code, i get a null value. I suppose it is because it is not reading the app.config of my project.
ConfigurationManager.ConnectionStrings["cnnName"]
It is the only connectionstring that the default app.config has:
[data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true]
In this post from 2012 with the same topic, one engineer involved in this project said that this option was not available. I hope it is available now in 2018
So, nowadays how can i load the app.config that i want?
"Constructor" was the magic word. This may not help in your case since you've found a solution, but it might be helpful for others in the same situation.
If you inject a System.Configuration.Configuration object into the class, you don't have to rely on ConfigurationManager's static properties.
public class LibraryClass
{
private Configuration _configuration;
public LibraryClass(Configuration configuration)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
}
public void FunctionUnderTest()
{
string connectionString = _configuration.ConnectionStrings.ConnectionStrings["cnnName"].ConnectionString;
// Connect to the database as you normally would.
}
}
In a console/GUI application and unit tests, load it like this to use {anything}.config:
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Register 'configuration' as a singleton using the container of your choice.
In a web application, load it like this to use web.config:
Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~/Web.config");
// Register 'configuration' as a singleton using the container of your choice.
To use it in C# Interactive, load it using the first method and provide the dependency to the class directly:
#r "System.Configuration"
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(
new ExeconfigurationFileMap() { ExeConfigFilename = #"path\to\Arbitrary.config" },
ConfigurationUserLevel.None);
var lib = new LibraryClass(configuration);
lib.FunctionUnderTest();
Note that the section properties are an extra layer deep compared to what you would normally expect.
I think it has something to do with how ConfigurationManager's static properties work with the Configuration instance.

How do I handle error logging for a system assembly without a circular reference?

I have a .NET assembly that wraps an XML configuration file. The config file contains a number of system settings including the path and file name formatting info for the error log file. Other assemblies reference this one through a singleton class:
public sealed class SettingsManager
{
private static volatile SettingsManager manager;
private static object syncRoot = new Object();
//...
private SettingsManager()
{
//load XML config file
}
public static SettingsManager Manager
{
get
{
if (manager == null)
{
lock (syncRoot)
{
if (manager == null)
manager = new SettingsManager();
}
}
return manager;
}
}
//......
//Methods getting and setting configuration data
//......
}
I also have a Logging assembly that provides classes for error handling and usage tracking in the rest of the system. It references the Settings library to figure out where to save errors to:
SettingsManager.Manager.GetCurrentErrorFileName();
So the Settings assembly is a core dependency for the other assemblies in the project. But if I need to log errors in the Settings library I can't very well include the Logging assembly as a reference for Settings because I'll have a circular reference.
The problem I'm bumping into, is how do I handle errors that may be generated by the XML file routines in the Settings library?
Do I hard-code a default file location for these errors to write to?
What is best practice in this case?
I thought about the system event log, but these assemblies are going to be used in both a Windows service and a hosted MVC website. So I don't think the event log is an option.
Two words... dependency injection.
More likely than not, your Logging assembly has absolutely no business knowing about the Settings assembly. It should probably either:
Expect some environment variable to be set in the app domain telling it where to log, with a sensible default if not provided
Expect something to tell it where to log (perhaps by setting a property on the logger)
In either option, the entry-point to your app is a good place to do this. Maybe in your first few lines of code you'd do something like:
Logger.LogFilePath = Settings.Manager.GetCurrentErrorFileName();

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.

Redirect ConfigurationManager to Another File

I am looking to redirect the standard .Net ConfigurationManager class to another file; entirely. The path is determined at runtime so I can't use configSource or such (this is not a duplicate question - I have looked at the others).
I am essentially trying to duplicate what ASP.Net is doing behind the covers. Thus not only my classes should read from the new config file, but also any standard .Net stuff (the one I am specifically trying to get to work is the system.codeDom element).
I have cracked open Reflector and started looking at how ASP.Net does it - it's pretty hairy and completely undocumented. I was hoping someone else has reverse-engineered the process. Not necessarily looking for a complete solution (would be nice) but merely documentation.
I finally figured it out. There is a public documented means to do this - but it's hidden away in the depths of the .Net framework. Changing your own config file requires reflection (to do no more than refresh the ConfigurationManager); but it is possible to alter the configuration file of an AppDomain that you create via public APIs.
No thanks to the Microsoft Connect feature I submitted, here is the code:
class Program
{
static void Main(string[] args)
{
// Setup information for the new appdomain.
AppDomainSetup setup = new AppDomainSetup();
setup.ConfigurationFile = "C:\\my.config";
// Create the new appdomain with the new config.
AppDomain d2 = AppDomain.CreateDomain("customDomain", AppDomain.CurrentDomain.Evidence, setup);
// Call the write config method in that appdomain.
CrossAppDomainDelegate del = new CrossAppDomainDelegate(WriteConfig);
d2.DoCallBack(del);
// Call the write config in our appdomain.
WriteConfig();
Console.ReadLine();
}
static void WriteConfig()
{
// Get our config file.
Configuration c = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Write it out.
Console.WriteLine("{0}: {1}", AppDomain.CurrentDomain.FriendlyName, c.FilePath);
}
}
Output:
customDomain: C:\my.config
InternalConfigTest.vshost.exe: D:\Profile\...\InternalConfigTest.vshost.exe.config

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