What is the recommended location to save user preference files? Is there a recommended method for dealing with user preferences?
Currently I use the path returned from typeof(MyLibrary).Assembly.Location as a default location to store files generated or required by the application.
EDIT:
I found two related/interesting questions:
Best place to save user information for Windows XP and Vista applications
What's the way to implement Save / Load functionality?
EDIT #2:
This is just a note for people like me who had never used settings before.
Settings are pretty useful, but I had to do a whole bunch of digging to figure out what was going on (coming from the Python world, not something I am used too). Things got complicated as I wanted to save dictionaries and apparently they can't be serialized. Settings also seem to get stored in 3 different files depending on what you do. There is an app.config, user.config and a settings.setting file. So here are two more links that I found useful:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ddeaca86-a093-4997-82c9-01bc0c630138
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/efe370dc-f933-4e55-adf7-3cd8063949b0/
You can use the Application Settings easily enough.
If you haven't done so before just right click on the project and choose Properties. Select the Settings tab. Make sure you chose "User" for the scope (otherwise the setting is read-only).
The code to access this is simple:
forms.Width = Application1.Properties.Settings.Default.Width;
If you need to save it:
Application1.Properties.Settings.Default.Width = forms.Width;
Application1.Properties.Settings.Default.Save();
In the sample above, Width is the custom setting name you define in the Settings tab and Application1 is the Namespace of your application.
Edit: Responding to further questions
You mentioned you wanted to store Dictionary objects in the Settings. As you discovered, you can't do this directly because Dictionary objects are not serializable. However, you can create your own serializable dictionary pretty easily. Paul Welzer had an excellent example on his blog.
You have a couple of links which sort of muddy the situation a little. Your original question is where to save "User Preference Files". I'm pretty certain Microsoft's intention with the Settings functionality is exactly that... storing user skin preferences, layout choices, etc. It not meant as a generic repository for an application's data although it could be easily abused that way.
The data is stored in separate places for a good reason. Some of the settings are Application settings and are read-only. These are settings which the app needs to function but is not specific to a user (for example, URIs to app resources or maybe a tax rate). These are stored in the app.config.
User settings are stored in an obfuscated directory deep within the User Document/Settings folder. The defaults are stored in app.config (I think, can't recall for certain off the top of my head) but any user changes are stored in their personal folder. This is meant for data that changes from user to user. (By "user" I mean Windows user, not your app's user.)
Hope this clarified this somewhat for you. The system is actually pretty simple. It might seem a little foreign at first but after a few days of using it you'll never have to think of it again... it just works.
When running as non-admin or on Vista you can't write to the "Program files" folder (or any sub folder of it).
The correct location to store user preference is (replace MyCompanyName and MyApplicationName with the correct names, obviously)
On disk:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_CURRENT_USER\Software\MyCompanyName\MyApplicationName
Those location are per-user and they work with non-admin user, several users using the same computer, fast user switching, terminal services and all the other ways people can interact with your software.
If you need a common location for all users then:
It will only work when the user run as an administrator
It will not work reliably on Vista
You have to take care of everything yourself (like two users running the application on the same computer at the same time via fast user switching).
and the locations are:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationCommonData) + "\\MyCompanyName\\MyApplicationName"
Or in the registry under the key:
HKEY_LOCAL_MACHINE\Software\MyCompanyName\MyApplicationName
You can use isolated storage. You can isolate by user, assembly and/or domain.
Introduction to Isolated Storage
http://msdn.microsoft.com/en-us/library/3ak841sy(VS.80).aspx
Types of Isolation
http://msdn.microsoft.com/en-us/library/eh5d60e1(VS.80).aspx
the following seems to be the best option:
Application.UserAppDataPath
Related
I am almost done with my winforms application. Coming from an asp.net background
there are a couple of things, I am not sure how to handle when a user install my exe.
So my application uses filesystem directories to store content files mp3,mp4,(images),.txt&.zip files. The user can add new (content files) to customize these content libraries with in my application.
My question is. What is the best practice for deciding the location of these directories my application relys on. Should the user be asked where to put them, should they go in c:ProgramFiles/MyApplication?
I just want the best way to do this and avoid installation issues Thanks
If they are something the user should interact with, then they should go in the documents folder. See vaguely related answer here. – Cody Gray
An application run by a user account has the same privileges and permissions as that user. Therefore, there is no way that the application could do something the user couldn't do on his own.
If the data you need to store is intended to be browsed or modified by the user, it should go in Environment.SpecialFolder.Personal.
Otherwise, data should be stored in either Environment.SpecialFolder.ApplicationData (if it should roam with the user account) or Environment.SpecialFolder.LocalApplicationData (if it should not roam with the user, and instead should be limited to the local machine).
Yes, the user can get into these folders and destroy the data. By doing so, they run the risk of breaking your application. You can't secure yourself from yourself.
Develop a "repair" utility that can recover from the damage by recreating the necessary files on startup of your application if necessary.
It may seem like this question has been asked a thousand times before, but I can't find an answer that actually points to a path that is common AND writable for all users.
In any case - in my application the users can download some fairly large data files that need to be accessible to the application after download. The application is used in multi user enviroments, so I'm not interested in storing a copy of the downloaded files for each user.
So far I've been using CommonApplicationData (C:\ProgramData\[Vendor]\[Application] created using Wix installer), but I've recently learned that this is meant as readonly storage and several users have experienced issues with this because CommonApplicationData is write protected.
I've been checking different options and the only viable one I have found so far is the %public% folder (https://blogs.msdn.microsoft.com/cjacks/2008/02/05/where-should-i-write-program-data-instead-of-program-files/).
Is this the best/correct place to put the files or is there another solution? Needs to work in Windows XP/Vista/7/8/10.
CommonApplicationData is indeed the correct place to store this data, unless the users should be able to see them as documents to double-click.
When you create the folder (or the individual files or subfolders within it) you should set the permissions according to your needs.
One alternative approach, to provide better cross-user security, is to install a system service to download and install these files on the users behalf.
My application basically creates an XML file in C:\ProgramData\MyAppFolder and dumps config settings in it.
I need to allow even standard users to have permission to add or delete settings to these config files. Right now I see that standard users only have read/execute permission but not "Full Control".
I've seen other questions being answered with ways to modify permissions to that particular folder but I don't want to change the default permission level, since it might be reset by a system admin.
If C:\ProgramData can't give that access to all users, is there any folder that best suits the needs of application?
EDIT:
My initial question might be misleading. I don't want to give rights to users, but rather allow the application to modify the XML file when it is run by all users.
DECISION:
I think changing the permissions while creating the folder in ProgramData is the only option.
And if that's not possible, CommonDocuments is the way to go.
Thanks Eve.
I would use a folder in the Environment.SpecialFolder enum.
Example:
var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Assuming you have an installer for your application, your installer can create a subfolder in the common appdata directory (aka C:\ProgramData) which your application will have read/write access to. Depending on your choice of installation technology you can set the permissions on that folder as well, although that may be overkill. I know with WiX basically all you have to do is a per-machine installation and make sure that sub folder gets created.
Users should not be allowed to write arbitrary data to this directory. This is equivalent to regular users being able to modify the C:\Users\AllUsers directory. If users need to be modifying this directory you have serious design flaws and should reconsider this approach. What should happen is the users are given GUI interface to interact with that manipulates these values behind the scenes without giving them direct access, similar to how getters/setters work in most programming languages. Needless to say it is a very large security hole when regular users can corrupt a system for other users.
UPDATE
I don't want to give users direct access to the file. My question
might have been misleading. I want to allow the program to have full
control on the file even when it being run by all users. I'm actually
doing this: "users are given GUI interface to interact with that
manipulates these values behind the scenes without giving them direct
access"
This article which has far too much information to post here, will provide details on remaining secure as to not leak permissions. The first thing you want to do is make sure that your application user is in its own group and cannot login/have any special permissions. What you can than do is have this group added to the directory with write permissions, which would allow this application to perform these tasks. If that is not possible you will need to work within UAC to not break the security of the system as is detailed in the article above.
Second Update
Thanks for the link. Any suggestions on some other folder which can do
the job, rather than messing with the permissions?
Sure you can write it into the directory where the application is written to, i.e. C:\Program Files\Some Awesome Program, this keeps everything in one place, and you only have to worry about your user/group and anything that the person who installed it has allowed for. It also prevents other people from messing with it unless of course they are administrators.
I'm developing a small C# Winforms game and one of the things I'm wanting to do is save application specific data. However, I'm struggling a bit to understand the correct place this should be stored.
As far as I can see there are several types of data an application might store and accordingly different places for it to be held:
1. Application properties
- Settings such as where the application stores it's data, who the last logged in user was, the default window size, position etc. Is this information suppose to go into app.settings, or perhaps into the registry?
2. Global application data
- This might include sprites and other game assets that are used by every user that runs the application on this machine. Where would this common data be stored? It's worth noting that in my particular case this data will not be provided with a default install and users will be allowed to add their own game assets which should be then available to any other user on the same computer.
3. User specific application data
- This would include a users saved game files, their specific application preferences and their profile information. Where should I be storing this?
Ideally I wish my application to be compatible with Windows XP, Vista, 7 and of course the upcoming Windows 8 - I don't know if this changes the methods but hopefully it will assist with providing advice.
This is my first foray into this kind of development and I would appreciate some 'best practice' advice.
Question 2:
I suggest using a subfolder in Environment.SpecialFolder.CommonAppData (maps to C:\ProgramData on Windows7 by default). This is a hidden folder.
Question 3:
Put those files into Environment.SpecialFolder.AppData(maps to C:\Users\[USERNAME]\AppData\Roaming by default, hidden folder), if you expect that the user does not intend to backup / modify those. Some games also put their save games into Environment.SpecialFolder.MyDocuments, probably because it is easier for users to find them there.
Example code:
var directory = Environment.GetFolderPath(Environment.SpecialFolder.AppData);
using (FileStream fs = File.Create(Path.Combine(directory, "myAppDirectory", "myFile.txt")))
{
// write data
}
For a complete list of special folders on Windows follow the link
SIDENOTES
Users are allowed to move around those directories, so make sure you use the code provided above
There is a bug in Windows 7 x64 regarding CommonAppData directory and the bug gets more severe in Windows 8 x64 CP. I've blogged about this: problems after moving CommonAppData directory on Windows 7 x64 and Windows 8 x64
Application properties - Most application data you described should be specific to each user and put in Environment.SpecialFolder.ApplicationData (the %appdata% environment variable). I would generally avoid putting data in the registry as it is hard to find, edit, and fix. If you do not want data to be associated with the user when they are roaming (maybe the files are big or connected to the computer in someway) then you can put it in Environement.SpecialFolder.LocalApplicationData (the `%localappdata% environment variable).
Global application data - I would put global application data in Environment.SpecialFolder.CommonApplicationData ( the %programdata% environment variable)
User specific application data - Same as #1, except when the data is intended to be easily found by the user (e.g. saved games) in which case it should go in Environment.SpecialFolder.MyDocuments, which has no associated environment variable.
As yas4891 points out you can reliably get these folder paths using Environment.GetFolderPath() using one of the Environment.SpecialFolder` values listed here.
We have a C#.Net application which uses a network database. I mean to say that many instances of the application will access the same db from different machines. So if I have to store the user-id to show the user while re-logging in, where can I store it?
The options i have are:
- Storing it in a local file in application directory. (But the problem is that the application is installed using Click Once. When the application is updated the application directory is being changed. May be I am missing something here.)
- Storing in the registry. Are there any other?
Can some one please suggest what to do? Correct me if I am wrong.
There are buil-int locations for this kind of stuff see Environment - specifically:
ApplicationData (user-specific roaming)
LocalApplicationData (user-specific non-roaming)
CommonApplicationData (not user-specific)
Generally you want to store any data that needs to persist between sessions, and is user specific in the registry, or the user AppData folder. Normally for small things (i.e. ids, basic settings etc....) the registry is the best place. Just make sure to stick it under HKCU\Software\Your company name\your program name. Although if the data is sensitive you should be careful where you place it, and it should be encryptedto protect it from basic snooping. If it's data that isn't sensitive though then the registry is a good place to put it.
This assumes of course that the installation and configuration doesn't need to be xcopy portable (i.e. a user could just copy the installation folder to a new place/computer and have everything work as normal). If that's the case then you'll want to store it under the installation directory.
If you need to store the UserID on the local, keep it in some kind of configuration file, mabe under a "LastLogin" entry. Check out this question and specifically this answer for more information.
Consider using Isolated Storage