I need to store a few settings (connection strings, folder paths) in a config file.
Should I use App.config?
Seems obvious, but....
1) App. contains some .NET config stuff (packages, versiosn etc) which I don't ever want anyone to be able to touch - I'd rather always these get compiled into the program.
2) It feels weird to have my dev-mode config settings compiled into the program, and invoked when App.Config is missing (defaults to built in resource or something)
3) I like clean config files so I can tell at a glance what the settings are (and I have OCD) ?
Yes, stuff it all into app.config. My reasoning is, nothing in app.config is really editable by the end user, even those bits that only the end user would know (connection strings and folder paths). Do you want a non computer-literate person editing an XML file with Notepad? I know I don't.
The only reliable way to get end-user values into app.config is to prompt the user for them during installation, and write them yourself as a custom action.
Yes, it's best practice, and prevents people from having to recompile your application to make basic config changes: ex. a new user needs to get an automatic email, much easier to alter a config file than recompile and re-deploy the app. In regards to your config file problem, here's an elegant solution: http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx
I prefer to just rename the files, or keep commented strings around depending on how much I have to do to move from dev to production.
My rule for *.config files is to use them when I want the ability to change a setting without re-deploying binaries. If I don't care about requiring a deployment to make a change, then I'll use constants. If I'm in doubt, I'll use the config file. I almost always use config files.
When I do use the *.config for something, I'll expose those values through another "Configuration" class that has one static read-only property for each value I wish to expose. i.e. if my app config has a setting
<add key="ServerLoadTime" value="-30" />
Then my configuration class might look like:
public static class Configuration
{
/// <summary>
/// Get the number of minutes before prior to the event that the server is started.
/// </summary>
public static int ServerLoadTime
{
get
{
if (ConfigurationManager.AppSettings["ServerLoadTime"] != null)
return int.Parse(ConfigurationManager.AppSettings["ServerLoadTime"]);
Logging.Write("ServerLoadTime is missing from the Configuration file.", EventLogEntryType.Warning, Logging.Sources.General, "Configuration.ServerLoadTime", null);
return -30; // return a default value.
}
}
}
This approach creates a standardized encapsulation that provides:
A quick way to reference the values without having to go though CM and checking validity.
A surface to deal with badly configured values/missing values.
A place to cast the strings that come from a config file into the type needed.
A place to log missing values while still providing a default-of-last-resort.
A place to deal to attach logic to a result if needed.
Related
I need some setting of an application that will be shared among all users of the computer, but could also be changed at at run time. That seam simple, but according to the Application Settings MSDN article, it's either one or the other.
There are two types of application settings, based on scope:
Application-scoped settings can be used for information such as a URL for a Web service or a database connection string. These values are associated with the application. Therefore, users cannot change them at run time.
User-scoped settings can be used for information such as persisting the last position of a form or a font preference. Users can change these values at run time.
I could write code to edit the app.config XML file, but since it's located in the program directory, it's protected under windows 7. So this is not possible without elevating the program or playing with NTFS rights.
So I need the configuration file to be written in a common folder like System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData).
But this is a fairly common requirement!
So, I'm wondering if there a simple way of achieving this without reinventing the wheel, or if I have to write my own Setting Manager.
After reading the answers here and playing with the ConfigurationManager.Open methods I ended up with the following:
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyApp", "MyApp.config");
Configuration MyAppConfig = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = path }, ConfigurationUserLevel.None);
The nice part is the file doesn't have to exist, and if you call Save() on it, it will create the folder and the file for you. AppSettings["key"] didn't work though so I had to use
MyAppConfig.AppSettings.Settings["key"].Value
to read and write an existing value and
MyAppConfig.AppSettings.Settings.Add("key", value)
to add a new value.
I have had a similar problem and ended up writing my own settings class. It was very basic. I created a Settings class with the properties I needed, and a SettingsManager with Save() and Load() methods that simply serialized/deserialized the object via XmlSerializer into/from a file.
Yes, it is your own code, but it is very simple code, takes less time than trying to figure out whether there is a component providing what you need and how to customize it.
The Application Settings infrastructure does not support this - only non-editable application data and user-scoped data are supported. You can easily read and write your own XML into the CommonApplicationData folders, however, instead of using the application data.
I have a program which I'm going to deploy using the package for deployment built into VS.
Now I have an app.config file which I want the user to be able to modify (even after running the program), but I have no idea where exactly the installer dumps the files, and I'm not expecting the users to root around their filesystem.
What I was thinking is - I ask the user to specify some directory (which needs to happen anyway since its a game) - I check for the config file there, and if its not there, I copy it from the root directory the program can see - then read the one in the 'save' folder.
That said, its sounding like a very ugly and hacky solution - is there a better one?
I wouldn't be encouraging users to modify the app.config. The app.config is copied into the same directory as your app exe and usually contains settings which your app depends on to run correctly e.g. DB connection strings, system defaults etc. Your playing a dangerous game by letting users change settings in there directly.
A safer approach would be to export another XML file into the users documents folder where they can override app settings. Have your app load in the app.config first then override those values with any settings found in the users own config file.
I would also recommend implementing some sort of UI for this, even if its really basic. Your average user isn't going to be comfortable editing XML directly, too much margin for error.
You could use the application (or user) settings to persist any changes that the user might want to make in the configuration. See the ApplicationSettingsBase class and this article.
Say your application contains a user setting called Score, managed internally by a class called MyUserSettings:
public class MyUserSettings : ApplicationSettingsBase
{
[UserScopedSetting()]
[DefaultSettingValue(0)]
public int Rank
{
get
{
return (int)this["Score"];
}
set
{
this["Score"] = value;
}
}
}
You can save the current values, usually when the main form is closing, using the Save method:
myUserSettings.Save();
If you want users to modify some settings directly, you can use a property grid or your own form that binds the instance of MyUserSettings class.
If the settings are marked as "User", then the values would be stored in the user.config file, in %InstallRoot%\Documents and Settings\username\Local Settings or %InstallRoot%\Documents and Settings\username\Application Data (for roaming profiles).
I want to store settings for my C# application, such that default setttings can be easily shipped with my binaries and the end-user can change them using a simple text editor(or in some other simple way).
I seem to face several alternatives : a .config file, .settings file or a .resx file. What are the pros and cons of these?
Edit1: End-users are computer professionals mainly, so editing these files should not be much of a problem.
Edit2: The settings are something like connection strings, and some other parameters (mostly one-time stuff). Building some kind of GUI/API for changing them is not really an option. Also my application will not edit any of these values, so persistence through code is not required.
Yes, Project + Properties, Settings tab was designed to do this. Add your settings here, change the Scope to Application. That generates a app.exe.config file in your build direcctory, deploy it along with your EXE. Use Properties.Settings.Default.SettingName in your code to obtain the setting value. Your user will normally need admin privileges to edit the .exe.config file on the target machine to change the setting value.
The small print: settings do not work well for DLL assemblies, you have to merge the .config files by hand. When using the debugger, settings are retrieved from the app.vshost.exe.config file.
The .settings file is a helper file used by the IDE, ignore it. .Resx files store resources, they get compiled and embedded in a binary form in an assembly. They are not editable by the user.
I think you can have two ways of doing this.
For regular users, you can make a custom GUI that will make it simple for them to use.
For advanced users, they can edit the configurations using a text editor if it's stored in a text file (ini file, config file, etc..) or you can make an API.
The .settings file is typically used for user-specific preferences and configuration information (whereas the .config file is used for global settings for the application or anything that modifies the .Net runtime. Simply putting parameters in a .config file can alter the behavior of your application even without you writing a single line of code for it).
Check out the Settings article on MSDN for more: http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx
Since the file will be modified by the users, I think using app.config is not a good idea. What if they break the file structure? Or set an invalid value? Probably your application will crash directly.
One of the solutions would be to use a custom XML file. You will then validate it when your application starts. XSD will probably be the more elegant way to do it, but you can also parse it directly and validate it in code. If the file is invalid, instead of crashing, you will try to solve the problem, and if impossible, display a pretty error to the user, explaining that there is an error in XML at line n, position n, which is [error description here].
If the end user is really going to be editing them, I'm not sure I would want them editing my app.config file.
You have another couple alternatives that you haven't included. You could use an old-school .INI file that is simpler for an end user to understand. You could also use the registry. I would recommend the INI file, unless your users are very savvy, in which case use the .config file.
The answer depends on the deployment method. For instance, if you are using ClickOnce and offer updates, you might encouter problems using Application Settings.
I believe the best way to go is to create a GUI, something that is most certainly suitable for novice users. Given that you already excluded that option, use John's suggestion (ini files).
Alright, so I know about the Settings.Properties.Default.* Stuff, but thats not what im trying to use.. I'm trying to develop my own class, ill show you:
public sealed class SettingsHolder<T>
{
public SettingsHolder(){}
public T Setting
{
get{ /*return setting*/ }
set( /*store setting*/ }
}
}
so then i could compile that to a dll, and reference it in an application, and do something like this
SettingsHolder<string> stringHolder = new SettingsHolder<string>();
stringHolder.Setting = "hello world";
and on next application launch
string welcome = stringHolder.Setting;
and welcome should = "hello world".. is this at all possible? i had origannally tried to disect the actual properties.settings class, but with no luck
The .NET/VS settings framework already does exactly what you indicate that you're trying to do, without the clumsy runtime casts and generic classes. Absent a very compelling reason not to use it, that is what you should use. It already handles persisted user-level settings.
If for some reason you absolutely cannot use that, either store the settings directly in a file somewhere in the user's AppData, or use Isolated Storage. You will have to write your own persistence model for it.
If an application could rewrite its own executable code on disk, it would raise all sorts of thorny questions about security and reliability. Besides, security restrictions on Vista and Windows 7 would prevent it from functioning correctly anyway - unless it's a ClickOnce app, it's probably installed in a program folder (i.e. Program Files), and you'd need a user with administrative privileges to elevate the process in order to make it work.
I don't think that's possible. The setting data has to be stored somewhere, in some file or database (when you compile your app you have .exe.config file).
Whe you do new classname() you create the object with members of that class initialised in memory to their default values. e.g. if your SettingsHolder class contained an int _n; it would be initialised to 0. Alternatively, you can of course initialise your member variable to a specific value, e.g. int _n = 5;
As far as I recall, this is in the definition of the language, which therefore precludes what you suggest; which is essentially something along the lines of 'self-modifying code with state'.
Therefore, you do need to use mechanisms to store state in your programs - such as Properties.Settings (which saves to XML config files by default), or a DB for example.
You don't really need to dissect the Properties.Settings class. If you access Settings from the project properties menu, and add a 'User' or 'Application' setting. It can then be accessed with Properties.Settings.Default.SettingName. You do need to instruct the code to save changes to the properties, if I recall correctly.
When you compile a C# project, the app settings from app.config are saved along with the exe file. For example, if the program name is "solve_np.exe", there will be a "solve_np.exe.config" next to it, making it look less neat than I want it to. How can you embed it into the .exe?
I tried to set Build Action to Embed Resource, but that did not do the trick.
Aha. I guess you're falling foul of Visual Studio automatically placing stuff in configuration that you DONT want configured by the end user.
In this case use resources. Simply add a new file of type .resx. With this you'll be able to add things like strings and images to the resource file. After you build this it should provide static access to the resources (it typically generates a code file from the resources for you so you don't have to access ResourceManager yourself).
E.G. If I made resources.resx with a string called MyConfigValue after a build I should be able to access this like:
textBox.Text = Resources.MyConfigValue;
If you want values that are kinda variable but shouldn't be configurable then this is the right place to put them.
HTH.
It isn't unprofessional to have an app.config file shipped alongside your exe. I think the word you may be looking for is untidy. I personally don't find this is the case myself however everyone is different! Perhaps you could simply make the app.config file hidden by default?
Or another alternative is to create your own config file which you could save to the App Data folder or even storing the settings in the registry instead.
Here's another factor to consider. Seasoned .Net developers are accustomed to the standard application design, which incorporates using config files in both web apps and desktop apps. If you depart from that practice, you will make it more difficult for any developers who follow you to understand what you have done. Even sa's on the web server may be confused by the absence of a config file.
Since pretty much everybody does it this way, your code does not look "untidy" to others. On the contrary, it would be befuddling not to see a config file where one is expected.
Typically the theory of a configuration file, is that it stores settings you may want to change once you've deployed the application (for something like user preferences). To do this, you need to be storing somewhere external to your application. If you use the default setup, you get "[Your].exe.config". There are many other options you could look at, but nearly every one of them ends up with a file written somewhere, if you providing a mechanism that saves settings of some kind.
I agree with serhio darasd and Quibblesome but you can just delete "solve_np.exe.config" and it'll just use default configs.
After considering what was written in these comments and other searching, I decided that the best way to handle my issue of wanting my Entity Framework connection string to be embedded into my executable instead of needing the MyApplication.exe.config file with my deployed solution was to created a derived class like such:
Public Class MyEFDataContainerLocal
Inherits MyEFDataContainer
Public Sub New()
MyBase.New(My.Settings.MyEFContainerConnectionString)
End Sub
End Class
I just created an Application Setting of type Connection String that contained the same string as what is found in the App.Config file. I just had to replace the "e;'s with actual quotes.
Then whenever I wanted to use the MyEFDataContainer as in Dim db As New MyEFDataContainer I would just use Dim db As New MyEFDataContainerLocal instead.