User Content Directories Best Practice - c#

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.

Related

Where to put common user program data in Windows XP/Vista/7/8/10?

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.

Where is the proper location for an application to store a large database on Windows?

My application uses a sqlite database to store the user's content. This database can grow to be 1 GB+ for heavy users. The database is currently stored in ApplicationData (%appdata%), but the documentation for this indicates it is for roaming data which should be small, for example settings that should persist across sessions. Some other options:
LocalApplicationData: documentation indicates this is for data that may be removed when the user logs off.
MyDocuments/Personal: I believe this also roams.
UserProfile: documentation says "Applications should not create files or folders at this level"
Some requirements for the storage location:
User specific (no common areas)
Non-administrative user must have read/write access
Data should not roam (like AppData\Roaming)
Data must not be deleted automatically
Many thanks for any suggestions for such a place on a Windows system.
If a user has a redirected ("roaming") application data folder and/or a redirected documents folder, it is likely that the user regularly uses multiple machines and expects his or her content to be available on whichever machine he or she is logged into. So most likely you should use either the roaming application data folder or the documents folder.
My initial instinct was to lean towards the former, because users generally don't like seeing mysterious and/or unexpected files in their documents folder, and may be inclined to delete them. On the other hand, the roaming application data folder is less likely to be backed up (we don't!) so, on the whole, I'd recommend the documents folder; to mitigate the other problem, put the database in a subfolder of Documents and give the subfolder a very clear name.
The local data folder is typically used for non-user-content such as caches and temporary files. I'm not aware of any professional product that stores user content there. IT folk are likely to take it for granted that it is safe to delete anything in these folders, and as already pointed out there are systems configured to do this automatically.
You certainly shouldn't use UserProfile; if the user profile is roaming, the content will be uploaded to the server every time the user logs out, and downloaded (if necessary) when the user logs in. (This is only true of UserProfile; the roaming application data folder and other redirected folders are accessed directly from the server and never sit on the local disk.)
I don't believe that the size of the file necessarily makes a redirected folder inappropriate. Mozilla Thunderbird, for example, stores the user's mail in the roaming application data folder, and this can get quite large. As far as I know, this has not caused any widespread problems.
However, there are a few Windows APIs that can't be used on a networked file, and it also won't work if any of the processes that will be accessing the file are running in a different security context (e.g., as a system service). You should check the documentation for sqlite to determine whether this is supported or not.
If you are not able to use a networked drive, I think the only good solution is to use the documents folder by default, but detect when it is on the network and ask the end user to select an alternative location.
In any event, you should provide either the system administrator or the end user (or both!) with a documented, supported way of overriding the default location.
For a per-user store, you need the AppData/Local folder. The environment variable is %localappdata%. The .NET enum is Environment.SpecialFolder.LocalApplicationData.
As for the "documentation indicates this is for data that may be removed when the user logs off."...
Yes. But it's rare. For example, it might happen for users on virtualized clients (think Citrix). In those cases, having a persistent 1GB SqlLite store will be a problem. For those of us on regular workstations, the data will probably not be removed.

How to give Create, Read and Modify permissions to all users for a file created by my application in C:\ProgramData?

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.

WPF/C#: Where should I be saving user preferences files?

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

Restrict a directory that can be used only through a .net Application

I have a windows Application that stores certain files in a directory. I would like to know if there is a way in .net that I can restrict users not to have access to that directly (by just going to that directory in windows, and grab files) so only my application can add/verify/delete a file in that directory.
Could you use the Isolated Storage in .Net? While, it isn't necessarily restricted away from your users it may be a lot harder to find.... (stores under the local settings\application data\isolated storage for the logged in user)
Via code you work with it by using / importing the System.Io.IsolatedStorage and then you can create directories, files, etc... normal.
You also don't have to keep track of the actual directory on the HD it's in as .Net manages this. Maybe a nice plus.
This is only possible if your application runs with different credentials than the user running the application.
By default all applications run with the credentials of the user who launched the process. This means the application has the same directory and file restrictions as the user. Without a different account, the application can only decrease it's ability to access the file system, not increase it.
Dealing with the file system is evil in general. Even if you could get the user to not play in that directory you still can't trust the results will be in the exact same state as you left them. It's possible for other users, physical disk corruption or any number of other things to corrupt your files.
The only way to sanely program the file system is to expect failure from the start and count yourself lucky when it actually works.
The application needs to run as a specific user - and that user will always have the same rights as your application. You can, potentially, make a service that runs as an administrator to prevent standard users from accessing a directory, but the administrator will still be able to change things in the directory.
I suggest you look for another approach for your problem. There are potentially alternatives - perhaps you should consider keeping some type of encrypted hash on the directory contents. That would at least allow you to verify that the contents have not been changed, although it won't prevent the change from occurring.
As others have mentioned, you need the application to act as a different user than the ones currently logged in. You should look into 'impersonation', here are some links that can get you started on getting your application to act as a different user when performing certain tasks:
http://csharptuning.blogspot.com/2007/06/impersonation-in-c.html
http://www.codeproject.com/KB/cs/cpimpersonation1.aspx
The easiest (although not secure in any way) method, would be to use a hidden folder, which the users know nothing about. so \servername\hiddenfiles$
A more secure alternative would be to change the credentials the program is using to access the folder. Is it necessary for them to access it as themselves?
An alternative would be to create a dummy account for each user, where they do not know the password. Make it relate to their windows login, so domain\myname becomes domain\mynamehidden. Then use this to connect to the directory.
This will ensure everything can be audited nicely too.
Look at FileSystemWatcher - it doesn't prevent from changes in directory, but allows to notify program about changes in dir.

Categories