Best way to provide software settings? - c#

I'm using C# .NET.
In my software I'm providing settings dialog through which user can set the application settings which I want to save to a file.
Requirements (typical):
Every class I defined uses some part of these settings. So, these should be global to all classes.
These should be loaded while software is started.
When ever user changes settings and clicks 'save'/'apply'. Current settings should change.
I am wondering what is the best way to do this? Also, what is the best way to save these settings to disk? I mean should I create a Settings class object and serializing it to 'settings.dat' or provide an structured file like XML/JSON
This is required for almost every other software. So, isn't there any design pattern for this?
EDIT:
Well, thats something that I didn't know. Its nice :). But say while user is using the software in the middle he changes the settings then all the other objects that are using these global Properties.Settings.Default.* should be changed. Is there any kind of notification mechanism? Some kind of event?

.Net projects already have the notion of Settings, scoped to either the user or the application, that will meet all of your requirements above. There are classes to read and write the settings. I would highly recommend that you look at these instead of rolling something up yourself.
Using Settings in C#
You can use Settings in a variety of project types, although in certain types of projects like ASP.Net projects, User-level settings may not be available.

The Settings class that comes with .Net is very handy, and I use it for most of my projects. The one gotcha to watch out for is that every new version of the application gets its own settings file, so make sure you have sensable defaults. All the settings will disappear whenever a new EXE is distributed.
Global state is very hard to deal with correctly, so I usually pass the relevant settings to the various objects in their constructors, or in properties. And I usually don't apply settings changes to those objects, since, in many cases, it's very hard for an object to deal with a changing setting intelligently. Rather, I just use the new settings for the new objects as they are created. If a setting needs to be applied immediately, then I just dump the old object and create a new one. It just depends on the details of the application.
If you have an Apply button on your settings screen, then I would recommend reloading and displaying all of the values after saving them. This way the display is sure to contain exactly what is actually saved. This could be important if any settings are parsed. I've had users enter a month and day combination into a particular field, and the format they used was different from what was expected, so the value saved was incorrect. By updating the screen after the Apply, these sorts of errors can be made obvious.
I hope this helps!

You and womp are both right:
You should create a Settings class that is a Facade over the .NET settings. That way you get the best of both worlds: the testability of a hand-rolled solution and the ease of implementation typically associated with Microsoft Silver Bullets.

I personally would go the Properties.Settings route. Add a Settings file to the Properties folder of your app. This lets you easily add items to the app.config file of your application. There is a built in .net class that you can use to read/write values found in the Settings file. You can then write a small wrapper class that encapsulates that functionality or simply use the built in .net one all over the place.
I personally would create a threadsafe Singleton class that uses the small wrapper class over the built in .net one. Yes it's some extra work but it's a small amount and gives you some great power in your app for the little bit of work.
Edit: Sorry forgot to include the MSDN settings link.
http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx

As others have suggested using the Settings feature is the way to go. Settings also provide events when the they are updated so you can handle them and take necessary actions. You can also use the Upgrade method to move the settings from previous version into the newer one. Just make sure that you call it only once (probably from the installer).
Settings can also be bounded to the controls so you will not have to map them manually from controls to settings.

Related

Application Settings in MVC5 Web App - Using C# class vs Web.Config?

I'm building out my application and I'm at a point where I've hardcoded a lot of settings at the top of my class files - stuff like ApiSid and ApiKey, SmtpServiceUsername, MyEmailPassword etc. I'm now trying to consolidate these and I see two options:
1) Push them all into web.config. I don't like the thought of muddling up my web.config with tens (almost 100) settings though... I also feel uncomfortable with security here.
2) Build a static class that just contains these settings (Settings.cs) - basically housing a bunch of constants that are referenced throughout the app.
I feel more comfortable with the second approach because I can keep my settings totally isolated and not worry about exposing them via web.config - is there anything inherently wrong with this approach?
is there anything inherently wrong with this approach?
What makes you think putting constants in the code is any more secure than in the config? The compiled DLLs are right there next to the Web.Config, if somebody can examine one of them they can examine the other one. Hard-coded values can be de-compiled pretty easily.
Config files exist for a reason. Specifically, if any value is going to change per environment then it belongs in the config file. That way the same identical codebase can be used in any environment (development, test, production, etc.) and you'd just edit the config values for that environment. Having to re-compile the code just to deploy the same version to a new environment is less than ideal, since it's no longer the same version.
I don't like the thought of muddling up my web.config with tens (almost 100) settings though
Why not? If they're all flat static values, a list of appSettings keys would be fine. If there's more structure to them, create custom config sections.
This is not necessarily the best approach but I'd store these kind of settings in the database. This gives you database security for the settings plus it's easy to update the settings without having to stop / restart the application so you avoid kicking out users.
Once you have your settings in the database, you can load them periodically (like every 15-20 minutes) to detect changes. In the meantime, create a dictionary of the data and either wrap it in a class that provides type-safe access through properties or just use the dictionary directly. Since this is web application, you'll have to use a thread-safe class (like ConcurrentDictionary) to make sure multiple threads can safely access your settings.
If you have so many settings, web.config would be cluttered and every change would force an app pool restart. As #David mentions in his answer, the config file gives you an easy way to have different settings for different environments but this is also easy to do with a database approach where settings may be present once per environment.

how to change .NET user settings location

By default settings are stored at: C:\Documents and Settings\\Local Settings\Application Data\<Project Name>
How can I change this path to application directory. I also don't want to have different files for different users. How make the settings global?
I tried to change the scope of the settings to "application" but then I cannot change them at runtime.
Using the default built-in behavior you can't!
Q: Why is the path so obscure? Is there any way to change/customize
it?
A: The path construction algorithm has to meet certain rigorous
requirements in terms of security,
isolation and robustness. While we
tried to make the path as easily
discoverable as possible by making use
of friendly, application supplied
strings, it is not possible to keep
the path totally simple without
running into issues like collisions
with other apps, spoofing etc.
The LocalFileSettingsProvider does not
provide a way to change the files in
which settings are stored. Note that
the provider itself doesn't determine
the config file locations in the first
place - it is the configuration
system. If you need to store the
settings in a different location for
some reason, the recommended way is to
write your own SettingsProvider. This
is fairly simple to implement and you
can find samples in the .NET 2.0 SDK
that show how to do this. Keep in mind
however that you may run into the same
isolation issues mentioned above .
I agree with Robert Harvey's answer do it yourself, or write a custom settings provider.
You can always read and write your own XML configuration files.
There are difficulties with programmatically changing settings for all users (since they come from the exe.config file, which is usually in Program Files and thus protected from write access in modern OSes). You can try making the settings application-wide but then use the ConfigurationManager to mess with the config file, similarly to the solution to this question.

Using the database to hold application settings

I am looking at ways to make our application more extensible and easier to manipulate without having to alter the web.config (or, in our case, application.config files, which contain the appsettings node).
One way I have thought about is keeping the app settings in the database table that has a sqlcachedependancy. This means that:
Any time a setting is changed in the database, the cache is invalidated, and the settings are retrieved again, thus updating the application in realtime without having to alter files and restart the entire app.
We can create a custom tool which allows us to alter the settings.
The cons as I see it are that this may cause serious logic problems in that, if you have something that checks an appsetting at the start of a process, and it then changes halfway through, you could end up unintentionally altering the process flow, as the requirement for a complete application restart is negated.
Is there a way round this?
Is there a better way to manage appsettings, so that you can alter them on the fly remotely for one, several, or all servers in one go?
I think you've nailed the two major players:
either you have access to the file system and you put all your settings in a plethora of *.config files there
OR:
you don't have access (or only very limited access) to the server's file system and thus you're probably better off putting config settings and user preferences in a database, basically leaving nothing but the connection string to the config file on disk
Both approaches have their pros and cons. I've been trying for a long time to find a way to "materialize" a config section from a database field, so that I could basically just use the config XML, but stored in a database field. Unfortunately, the entire .NET 2.0 config system is very much "locked down" and just only assumes data will come from files - there's no way to plug in e.g. a database provider to allow the config system to read its contents from a database field :-( Really too bad!
The only other approach I've seen is a "ConfigurationService" in the StockTrader 2.0 sample app provided by Microsoft, but for my needs, it felt like overkill and like a really complex, really heavy-weight subsystem.
You could use SQLite, which will be a self-contained DB in a single file. Two birds with one stone?
If you reference an external config file that contains appsettings (leaving everything else in the normal app.config) then I believe editing it only reloads those settings, it doesn't force the whole app to restart.
There's a similar question on the subject here:
Nested app.config (web.config) files
WRT the problem of values changing in the middle of program execution, I guess you could locally cache the values, and raise an event when they change, allowing routines to reach a suitable point before using the updated values.
I think in asp.net we sort of get this for free because each page lifecyle is distinct, so the value is simply applied to new page requests only, not in the middle of an execution.
Edit: A little extra info:
Configuration Changes Cause a Restart of the Application Domain
From MSDN:
Changes to configuration settings in Web.config files indirectly cause the application domain to restart. This behavior occurs by design. You can optionally use the configSource attribute to reference external configuration files that do not cause a restart when a change is made. For more information, see configSource in General Attributes Inherited by Section Elements.
More information on the ConfigurationManager class in the System.Configuration namespace which could be used to modify the config files programatically (ie in a custom tool, if relevant disk read permissions can be provided). If you stick to using the built in configuration classes, I think changing the external configs, would not cause application restart, but would raise events (such as property changed) which you could handle, to ensure your code is not caught out by changing settings.

Hold global data for an ASP.net webpage

I am currently working on a large-scale website, that is very dynamic, and so needs to store a large volume of information in memory on a near-permanent basis (things like configuration settings for the checkout, or the tree used to implement the menu structure).
This information is not session-specific, it is consistent for every thread using the website.
What is the best way to hold this data globally within ASP, so it can be accessed when needed, instead of re-loaded on each use?
Any AppSettings in web.config are automatically cached (i.e., they aren't read from the XML every time you need to use them).
You could also manually manipulate the cache yourself.
Edit: Better links...
Add items to the cache
Retrieve items from the cache
Caching Application Data
It's not precisely clear whether your information is session specific or not...if it is, then use the ASP Session object. Given your description of the scale, you probably want to look at storing the state in Sql Server:
http://support.microsoft.com/kb/317604
That's the 101 approach. If you're looking for something a little beefier, then check out memcached (that's pronounced Mem-Cache-Dee):
http://www.danga.com/memcached/
That's the system that apps like Facebook and Twitter use.
Good luck!
Using ASP.NET caching feature is a good option I think. In addition to John's answer, you can use Microsoft's Patterns & Practices team's Caching Application Block.
This is a good video exploring the different ways to can retain application state.
http://www.asp.net/learn/3.5-videos/video-11.aspx
It brushes on the Application object which is global for the whole application, for all users and shows you how to create a hit counter (obviously instead of storing an integer you could store objects). If you need to make changes, you do need to use a lock for concurrency, and I'm not sure how it handles LARGE amounts of data because I've never had to keep that much there.
I usually keep things like that in the Application object.
If the pages are dependent upon one another and they post to one another, you could use the page's request object. Probably not the answer you're looking for, but definitely one of the smallest in memory to use.
I have run into the same situation in the past and found an interface to be the most scalable solution. Application cache may be the answer today, but will it scale to meet your needs?
If you need to scale up, you may find cookies, or some type of temp database storage to be the trick. Simply add a new method to your interface, and set the interface to choose the "mode" from web.config.

Is switching app.config at runtime possible?

Is there a way at runtime to switch out an applications app.config (current.config to new.config, file for file). I have a backup/restore process which needs to replace its own application.exe.config file. I have seen this post but it does not answer how to do this at runtime.
Turns out I can swap the .config file for the new one and do a ConfigurationManager.RefreshSection(...) for each section. It will update from the new .config file.
Microsoft .NET's app.config is not designed for your scenario, as well as many others. I often encounter a similar need, so I have spent a lot of effort designing a solution.
Redesign to use app.config only as a configuration bootstrap: specify where to find the rest of the real configuration data. This information should almost never change, so there is no need to handle file watching or application restarts.
Pick an alternate location for the real configuration data: a file, a database, perhaps even a web service. I prefer a database most of the time, so I create a configuration table with a simple structure that allows me to store my data.
Implement a simple library to wrap your configuration access so that you have a simple API for the rest of your application (via dependency injection). Hide the usage of app.config as well as your real configuration storage location(s). Since .NET is strongly-typed, make the configuration settings so--convert each string retrieved into the most-specific type available (URL, Int32, FileInfo, etc.).
Determine which configuration settings can be safely changed at runtime versus those that can't. Typically, some settings need to change along with others, or it simply makes no sense to allow them to change at all. If all your configuration data can safely change at runtime, then that makes things easy, but I HIGHLY doubt such a scenario. Hide the changeability and interdependencies of the configuration settings to the extent possible.
Design the response to the unavailability of your real configuration data. I prefer to treat the absence of any configuration setting as a fatal error that aborts the application, unless I can identify a usable default. Likewise, I abort in the absence of the configuration storage container (file, database table, etc.).
Enjoy, and best wishes.
Are you able to restart the application when you detect that you need to switch files? If so, it's just a matter of switching the files and restarting. Now, the tricky bit is if .NET keeps the app.config file open while the program is running. I suspect it doesn't, but if the most obviously approach fails, I suggest you have a second application (cfgswitcher.exe) which waits for the process with a PID specified on the command line to terminate, then switches config files and relaunches the original process. Then your app would just need to launch cfgswitcher.exe (passing in its own PID as a command line argument) and terminate.
As I say though, it's worth trying the more obvious approach first.
EDIT: If you can't restart the application (or even part of it in a new AppDomain) then various aspects of app.config (assembly bindings etc) can't be changed. If you're only interested in your own configuration sections changing, then I suggest you store them in a separate config file and reload them whenever you want to.
Look at the events available to you on the ApplicationSettingsBase class. There are PropertyChanged & SettingChanging that may give you what you need.
You could also watch the file and if it has changed call the reload method to get the new settings.
I don't think it is possible at all to switch the configuration at runtime without restarting, so if you can't apply Jon's approach, you should try to come up with an other approach.
Anyway, maybe it's just me not having enough information about your scenario, but this kind of feels fishy.
Are you sure that swapping the configuration file is the best way to achieve whatever requirement you need to meet? I mean, this is quite an uncommon thing. If I were you, I would try to come up with some other approach.

Categories