Get application settings without file access - c#

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

Related

Settings specific to a class

I have a class where I retrieve certain settings from a database (usernames and passwords). This database is sitting on a network, and it means that if the passwords are changed, I can simply change it in the database, and all the applications that use this class will still work.
I am fully aware of the pros and cons of storing usernames and passwords in a database and in a separate location. I don't want to discuss those, please.
The class has a hard-coded static string that is the path to the database. It is a fully qualified network name (not just the drive letter). I did this because we had an issue where our network DNS got screwed up, and drive letter mappings stopped working, and some people have different drive mappings anyway.
We recently had our server moved, so I now need to go through and change these hard-coded strings.
I was thinking that I should store the path in a settings / configuration file instead. I considered "application.settings", but it is not an application setting; its specific to the class. Is there a preferred way of doing this in the existing .Net framework (this is a C# issue)?
I could simply have a small text or XML file that sits in the application directory, which is probably fine... is there an existing framework namespace or open-source code snippet that someone knows of that I can use?
I think, if you want class specific configuration, you should try to have those class instances, configuration driven. Another way of thinking but; Defining a something in a configuration file, will create an instance of the defined classname.
For example: Create a section, and call it, <Modules> and create items in like: <module type="<namespace>.DBConvertor" param="username=root;passwd=whatever"> This type will be created at startup (you need some coding here). And it's even possible to create more than one instance simultaneously with it's specific configurations.
This kind of configuration is already implemented:
You might take a look at this: "How to: Create Custom Configuration Sections Using ConfigurationSection" https://msdn.microsoft.com/en-us/library/2tw134k3.aspx
And creating instances from typenames, use the Activator class.
Besides that, there are many module/plugin libraries, (like Managed Extensibility Framework (MEF) https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx but could be a little over the top in this case).

How can I distinguish user settings by name in C#?

Following CodeProject and StackOverflow.105932 (and a few others, e.g., StackOverflow.1873658 and MSDN articles) I have a main form whose Size, Location and WindowState are saved in and read from Properties.Settings.Default.<name>, e.g., Properties.Settings.Default.WindowState = WindowState; and this works great for this one form. EVERY code example I turn up seems to think there will be one and only one global setting for WindowState, none of them say how to distinguish these settings per instance.
However, I wrote the code in a superclass of the Form because I want all the Forms IN THIS APPLICATION to inherit from that class so they are all able to save/read their own size, location and state.
What I'd LIKE to do is simply replace the word "Default" in the key path above with the class name of the inheriting form. Here is pseudo code that would be great if it worked (it doesn't, and I cannot find a variation that does):
Properties.Settings[this.ToString()].WindowState = WindowState;
How can I do this correctly, reusably, maintainably, entropy-proof?
Edit: Would "config sections" be the answer? (Maybe create a section for each Form subclass?)
Edit: No, not config sections but I think this class must be part of the correct solution.
Well, at its core that's just not the way settings work in .NET by default. The settings file for settings with Scope = User are carefully hidden away in a private AppData folder with an unspeakable name. A name that's created by hashing various properties of the main EXE, including its name, location and [AssemblyVersion]. Important to prevent programs from overwriting each others settings file by accident. There is no documented way to get to that file from another program. Mostly because you have no good way to guess these property values for another program.
There are workarounds for that, instead of the default LocalFileSettingsProvider class you can create your own class derived from SettingsProvider. It's a bit painful, System.Configuration is not exactly the finest namespace in .NET. A good way to get started is by using the RegistrySettingsProvider SDK sample.
Or just punt the problem, just create your own XML file that you store in an AppData folder that you can always get to from any app. Which is in general a good idea because you'll tend to get burned by versioning problems when many apps share a common data file. You'll want to declare an XML-serializable class in its own assembly that stores these properties. With a heavy "Do not change without talking to me first" comment on top.

Reset Static fields on change in INI file

I have a C# class library which reads an INI file to obtain the value for a parameter
for e.g. (debug=on)
Now on every call and some times multiple times in one call I have to check this INI and this leads to I/O overhead.
To overcome this I made the parameter in code to be static so at the load time it will check the INI and will store the result.
But now I have to add this condition that reset your IIS or kill your windows form in case you change the INI value.
Note: I dont want to use configuration files (app.config/web.config) as this library is used in various projects (forms/web/services).
So in your opinion what is the best way to Reset Static fields on change in INI file without doing an IIS Reset etc.
Any reason it has to actually be static fields? I would suggest having some sort of configuration interface which you can pass around as a dependency to the bits that need it. You can then have three implementations:
A "fake" with writable properties used for testing
A "file reading" implementation which reads a file on construction, and is then immutable
A "file watching" implementation which has the idea of its current configuration (and instance of the previous one) and replaces its "current" one when the file changes, via FileSystemWatcher. Calls to read the configuration properties simply delegate to the "current" configuration.
This approach will lead to a much better testing experience - both for within your class library and potentially for code which uses your class library.
If you really, really need a single place that you can always get at a configuration, you could always use the above but have a single static field which refers to the "file watching" implementation.
Look into using a FileSystemWatcher

Application Wide Settings Available to All Projects

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.

Do I have to derive from ConfigurationSection to support per-user settings?

I'm playing around with .NET's configuration support (the ConfigurationManager class and related support classes). I would like to write an application that, once installed:
Has default settings in foo.exe.config (in Program Files).
The user may later override the settings with nondefault values which should be persisted.
The user's preferences should be persisted in the user's profile, since he shouldn't have write permissions to the Program Files directory.
The app should use the user's preferences when they're set, otherwise use the defaults.
It seems like this ought to be easy - it's a very common pattern. But my attempts at this are running into bumps and I'm wondering if I'm taking the right approach.
The following code produces the runtime exception "ConfigurationSection properties cannot be edited when locked".
using System;
using System.Configuration;
namespace DemoAppSettingsProblem
{
class Program
{
static void Main(string[] args)
{
Configuration userConfig =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
if ( userConfig.AppSettings.Settings["foo"] != null )
userConfig.AppSettings.Settings.Remove("foo");
userConfig.AppSettings.Settings.Add("foo", "The string is foo.");
userConfig.Save(ConfigurationSaveMode.Modified); // exception!
}
}
}
The problem is that the .NET-defined <appSettings> section is declared with the default allowExeDefinition=MachineToApplication (see this nice post by Microsoft's Irena Kennedy). This prohibits the section from being written to the user's profile (either local or roaming).
So, I assume I need to define my own section, with allowExeDefinition=MachineToLocalUser. But as far as I can tell from the MSDN docs, that means I need to create my own configuration class, derived from ConfigurationSection. The examples there point me toward more work than I was expecting, which usually sets off my alarm bells that I'm doing something wrong.
Is it really this difficult to achieve this? Is there a simple way .NET provides to support this, or should I perhaps be taking a different approach altogether?
I've used the settings feature, it writes user settings to the app config for you...
http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
Assuming you're on .NET 2.0 and higher, have you checked out the "Settings" files? Those are being stored inside your app.config - application settings in <applicationSettings> sections, user-definable settings in <userSettings>, which incidentally have the allowExeDefinition=MachineToLocalUser setting you mentioned.
Maybe that could be an approach? Those user settings are a defined type, which you could definitely reuse under a different name, if needed ("mySettings").
Marc

Categories