My Scenario
I have a class library that is going to be called from multiple separate executable applications. This class library needs to know about an address of a database server (and many other configuration options, auth info, etc) to access. I have a configuration and administration application, separate from the class library, that also needs to know and set these configuration options.
My Question
Is it be common practice to store these user specific configuration options in the Windows registry, or is it preferred to use the typical 'App.config' XML approach for the class library and allow the configuration tool to change and modify it?
I am leaning toward the registry approach, but I know many people have opinions about not using it. What would you do?
The best practice is to use XML configuration files in the user's %appdata% directory.
There are a number of reasons for this:
Your application is most likely to be installed into Program Files. If the user hasn't granted (or been granted) administrative rights to your application's process, you won't be able to write to the file.
I've worked in partially trusted environments where registry access is just simply not an option. The client had completely disabled registry permissions to the .NET Runtime on that server.
Your user should always have access to their own %appdata% directory. Here's a sample:
string configFilePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "myAppConfig.config";
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = configFilePath;
Configuration cfg = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
cfg.AppSettings.Settings.Add("mySetting", "myValue!");
cfg.Save(ConfigurationSaveMode.Modified);
// to read the setting back
string mySetting = cfg.AppSettings.Settings["mySetting"].Value;
// at this point, mySetting = "myValue!"
Remember to add the System.Configuration v2.0.0.0 reference to your project! The default System.Configuration namespace does not have all of the required classes.
I prefer xml configs over registry settings because I can simply make a class and use the xmlSerializer to open and save right into my classes.
Check this topic out for a similar SO question.
In my specific case, these specific config settings made more sense to be stored in the registry. I can't be positive that our users will install the applications to the same locations, and at the very least, I'd have to store the location of the "master" config XML file in the registry so the other applications could locate it.
I simply whipped up a class with an index to read/write configuration settings to the registry like a Hashtable (string ponySetting = myRegistryObject["DefaultPonySetting"]) and called it a day. I reference the main assembly with this class in all the other applications anyways. Huzzah
I wouldn't use the registry for sure but for simple application-wide settings I just roll my own XML file in the same location as the EXE and use my own classes to access it. For this sort of thing the setting handling in .NET is way overcomplicated, and it's not even as bad now as it used to be.
Related
I have an app.config which is working fine.
But I also have a tool for automated testing, that runs some tests in environment without any file access. So I have to read a config file from string (or memory stream), but without mapping it physically because there is no access to file system from this automatic testing process.
In real life, of course, config file is stored somewhere, but for automated testing purposes I need some workaround to read a config file from string stored in memory. Is it even possible? I googled a lot, but the only thing I found is Save it as temp file and then read, but it's not my case.
Avoid a direct dependency from your class on app.config or any other file. Your class doesn't need app.config or Properties.Settings. It needs the values contained in the those files..
If you create a workaround for testing purposes then you're testing a different version of your class. That's the inherent problem - direct dependency on these files isn't testable. It doesn't mean that they're bad in some way or that we shouldn't use them, only that the class that requires the values should not read them from the file.
An ideal solution is constructor injection, a form of dependency injection. Provide the value to the class in its constructor and store it as a field. That way when the class is created it always has the values it needs.
At runtime you can use a dependency injection container - here's a walkthrough on setting one up for WCF. You're likely in a different project type, but the concepts still apply.
But for testing, it's as easy as creating a class and passing whatever value you want to use into the constructor. It's impossible to test with different values when the class reads from settings but it's easy using constructor injection.
Without the configuration file you'll have the default settings. You may override the default values:
Properties.Settings.Default["PropertyName"] = NewPropertyValue";
(Set the correct access modifier on your Settings class and use the correct namespace if it is in a library)
As first option I would go for Settings file in your case.
Even your user won't be ablle to access settings file content. Then it will return a default value for a particualr property.
You can try creaty a silly console app
static void Main(string[] args)
{
Console.WriteLine(Settings.Default.MyProperty);
Console.ReadLine();
}
were you set the your value for MyProperty on the Settings Tab of you Project Properties.
Then you can build your solution, open the binaries folder and delete your exe.config file and you will see that the app will be use default values.
As second option you can use command line arguments. could also be an option for you. (Here the article about some tricky case for command line arguments Backslash and quote in command line arguments )
Third option could be placing your file at c:\users\your app user \AppData\Roaming\YourAppName folder. here you should be granted for file access even for restricted user
For education reason I would also reccomend to look at this article: https://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(ApplicationSettingsOverview);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5)&rd=true
Maybe you find the "Load Web Settings" option nice.
Another palce for investigation could be
Ok so i have 2 classes so far that i want to put in my common dll, logger and db. im moving them from my current project to a new class library project and changing their namespaces and whatnot. The issue I am having is that I wish to use the app config of my application (or any app that I want to reference my commonlib.dll) but I dont know how to use the referencing projects app.config. Is there any way to do this?
The OpenExeConfiguration() methods of ConfigurationManager are your ticket. One of them will take a path to the executable, allowing you to open the app config of a specified application (even a different one; you can use this technique to change the configuration of another application before launching it with Process.Start()). The other one will open the app.config of the current application (even if your library is used by multiple apps) for a specified user level (All users, current roaming user, and current roaming and local user). Usually, when dealing with an actual app.config, you want the one that applies to all users; the per-user configs are stored in each user's AppData folders.
Also, one last thing; unless your library has its own config file, the ConfigurationManager properties, like AppSettings, will be populated based on the current executable's app.config. So it could be as simple as using those properties. Keep in mind that those properties are read-only and only loaded once at program startup, so if you make changes to your config during program execution that you want to be effective immediately, it's better to explicitly load/save config files.
We have many environments and thinking of creating dynamic application configuration as part of CI. The configuration values will be stored in Database using WPF. Operation team manages the app for new app config entries.
The problem I am facing is how can I dynamically create the config and validate it? Opinions..? Thanks in advance.
If the number of configurations is finite and known (test, UAT, production desktop, production mobile, etc), you can take advantage of the configSource attribute found on the AppSettings, ConnectionStrings and ConfigSection elements. Here's the basic premise; create an AppSettings.xyz.config file for each configuration, where xyz is the name of the configuration ("local" "test", "uat", "prod", etc). Create a single app.config file that uses a <!ENTITY config "xyz"> definition, and has configSource attributes for various sections set similar to:
<appsettings configSource="appSettings.&config.config">
Now, in deployment logic, you change one thing; the string literal defined by the entity. This change is simple enough that you don't even really need XML parsing to make the change; just slurp the file into memory with a FileStream, find the entity definition, make the change and spit the new content back out into the file. If you're using an installer, you can control which child configs are installed, or just put them all out there for simplicity.
Take a look at T4. You can create a skeleton .config file with certain variables that are filled from the database to generate the environment-specific file.
OpenExeConfiguration has 2 overloads:
ConfigurationManager.OpenExeConfiguration (ConfigurationUserLevel) ----- (1)
ConfigurationManager.OpenExeConfiguration (String) ----- (2)
OpenMappedExeConfiguration has only 1 prototype:
OpenMappedExeConfiguration (ExeConfigurationFileMap fileMap,ConfigurationUserLevel userLevel) ----- (3)
It seems both (2) and (3) can be used to open a specific config file rather than the default app.config file.
So what's the difference between them? When to use which?
Why do we seperate the UserLevel and Config File Location in (1) and (2), but combine them in (3)?
Thanks for any replies.
Update
I know that Microsoft always like to do things in more than one ways. But it should do it for a reason. Any body know the reason in my question? Do we need a bounty ;) ?
The difference is explained in the ultimate .NET config resource - Cracking the Mysteries of .NET 2.0 Configuration:
OpenExeConfiguration (String)
will append ".config" to the filename
you provide and load that
configuration file. It's important to
note that OpenExeConfiguration(string
exePath) is a very misleading method,
as the filename does not have to be
the filename of the .exe that is
running [...]
By providing a filename other than the
EXE filename, an alternate *.config
file can be opened.
OpenExeConfiguration (ConfigurationUserLevel)
The second method,
OpenExeConfiguration(ConfigurationUserLevel
level) will load the appropriate
configuration file for the specified
configuration level. Configuration
levels, available in the Exe context,
allow you to specify whether you want
exe, roaming user, or local user
configuration [...] Remember that configuration is hierarchical and merged. When requesting roaming or local user configuration, that level up through machine.config are merged, resulting in the complete configuration accessible by your application for the given user level.
OpenMappedExeConfiguration(), OpenMappedMachineConfiguration()
Unlike the OpenExeConfiguration()
methods, which make several
assumptions about where your
configuration files reside,
OpenMappedExeConfiguration() and
OpenMappedMachineConfiguration() allow
you to explicitly specify where your
*.config files reside on disk. Using these methods, you can load an
alternate machine.config, load
User.config files from the locations
of your own choosing (vs. letting the
.NET framework decide on some
convoluted path), etc. When accessing
machine.config, a custom version is
not required,
OpenMachineConfiguration() should be
used instead.
The difference between OpenExeConfiguration (String) & OpenMappedExeConfiguration (ExeConfigurationFileMap, ConfigurationUserLevel) ) is that the mapped version will let you choose the configuration file that you wish to open using an ExeConfigurationFileMap.
If you use the OpenExeConfiguration(string) overload then it will open the configuration using the Machine and Exe config locations whereas the mapped version will let you pick the specific file you wish to load from any location (obviously still respecting permissions, etc.).
If you take a look at the source, both methods actually call the same implementation method:
public static System.Configuration.Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
{
return OpenExeConfigurationImpl(fileMap, false, userLevel, null);
}
public static System.Configuration.Configuration OpenExeConfiguration(string exePath)
{
return OpenExeConfigurationImpl(null, false, ConfigurationUserLevel.None, exePath);
}
So when to use one over the other? Use OpenMappedExeConfiguration when you don't want to open the default configuration file. In my experience, the only time I call either of these methods is when I want to read a non-default configuration so I've only used OpenMappedExeConfiguration.
I have a Solution with 3 projects in, each project needs access to certain settings. I'm looking for a way to have these setting values available to any project from 1 distinct source. I cant use the .Config file as that is relevent to that particular project.
I could use the database but have been told this is not good practice (Without an reason)
Any ideas?
You could do this:
create a solution.config in your solution folder
in each project's app.config, add this to your <appSettings> node:
<appSettings file="solution.config">
....
</appSettings>
You would have to put symbolic links to your common solution.config in each project folder - but you could have one single physical file that you share amongst the projects.
The <appSettings> node is the only one that allows that sort of "cummulative" settings - those from the file specified in the file= will be added to your app settings, but potentially overwritten by anything you specify explicitly in your app.config.
On the other hand, yes, of course, you could use the database. We do that, too, in most of our projects, since we typically do have access to the database, but not to the file system in the client's server machines. I don't see why that should necessarily be a bad thing - we have settings for DEV, TEST and PROD in a table - so you have all your settings in one place - and we pick those settings we need when we need them. Works just fine - of course, some settings like the connection strings to the database cannot be stored there - but the bulk of our config info is. Again: I really don't see any reason why this should be a bad choice per se - so unless your source can back his/her statement up with some facts and reasons, I'd ignore it.
You can define configSource attribute in a defined configSection, to reference an external file from which to load your properties.
Here you can find an example:
Is there any way for an App.config file to reference another full config file? (.NET)
You can also use a DB of course, but that would probably involve developing some kind of configuration console, since it's not a good practice to manage config attributes directly into DB.
Otherwise you can create your config file (an xml, or yaml for example) and create your own shared config parser.
I create a class to hold system-wide settings using either a Singleton pattern, or a Global instance (whichever you preference is).
If another project is in the solution, it can see the class (when references are added).
This also decouples the presentation of the settings from the storage mechanism (database, config file, custom XML file, whatever), and if you design to the interface, it makes unit testing more flexible, too.
You could add an entry into each projects .config file that points to the global one. You would need to read that in three places though.
Another solution that springs to mind is to put your common settings into their own assembly with it's own .config file. You then include that assembly in each of your projects. The .config file is read in the assembly and you can read out those values you need.
What kinds of settings?
You can use the system wide machine.config and web.config files for settings that apply across an entire machine.
\Windows\Microsoft.NET\Framework[64]\[version]\config\machine.config
\Windows\Microsoft.NET\Framework[64]\[version]\config\web.config
You could use the registry if you have access to it. Then all you would need is a class to read them out (and possiblty one to put them in) and each project could use that class to read them.
The major downside though is that you would have to add the settings to each machines registry that you run your solution on.