0

I developed a WPF application with MS Access database. Everything is working fine. But when I tried to publish the app in order to create a setup file to use the application on other pcs, I am getting the following exception when I first run the app:

System.Data.OleDbException: Could not find file 'C:\Users\me\AppData\Local\Apps\2.0\77NYD08R.L6A\Y93TLQGV.2TD\pier..tion_b5378b5ea7b941ca_0001.0000_9b5c3ff3b52b7eb4\Data.

I'm accessing the database in the code as follows:

private void ConnectToDatabase()
{
     dBConnection.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=MyProjectDB.mdb";
     dBConnection.Open();
}

And I added the database in bin/Debug folder. Why it's trying to get the database file from AppData\Local folder? Should I move the database file to another folder?

Vojtěch Dohnal
  • 7,867
  • 3
  • 43
  • 105
Hanady
  • 779
  • 2
  • 15
  • 38
  • How did you "publish" the application? The AppData folder *is* where applications are supposed to store their data files. You used a relative file path for the database which means that your code is trying to find the database either in the installation folder (the read-only `Program Files` which should *not* be writable for security reasons). Somehow, this was redirected to the AppData path – Panagiotis Kanavos Feb 26 '16 at 13:13
  • I just right clicked on project and clicked publish. As fas as I know, windows apps don't have an AppData folder. Am I wrong? – Hanady Feb 26 '16 at 13:18
  • Yes. *Windows* has this folder, just like it has Documents, Users etc. *All* applications are supposed to store their own data there. There are also per-user data folders in each user's profile directory. `Publish` isn't "just" publishing, it creates a ClickOnce application that doesn't actually get installed in the usual way (ie with an MSI, copying files etc). The application is installed per user, doesn't require administrative priviledges, gets automatically updated etc. That's only possible because the AppData and per-user folders are used – Panagiotis Kanavos Feb 26 '16 at 13:23

2 Answers2

0

Basically there is what you should do:

Do not leave the database file in your project folder, copy it elsewhere, like to Environment.SpecialFolder.ApplicationData. You do it when the app is first launched and there no database file exists, so you copy the database from your project folder to your data folder.

There is quite a good answer, how to deal with the problem here.

If you need to write to the data deployed with your executable you should first copy it someplace you know the user will be able to write to, such as to Environment.SpecialFolder.ApplicationData, and write to the copy. Not only is DataDirectory not necessarily writable by users, it is part of the deployment and not part of the user data; if you repair or uninstall your executable then DataDirectory gets reinstalled or deleted. Users don't like it when you delete their data, so don't save it to DataDirectory

You can get the path of your ClickOnce executable via this command:

 var exePath = System.IO.Path.GetDirectoryName(
               new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);

See then this answer: Use something like that if the database should be used by multiple users of target computer:

AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(System.Environment.GetEnvironmentVariable("public"), YOUR_FOLDER_NAME));

Or just one database for one user:

AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),YOUR_FOLDER_NAME));

You should be aware that ClickOnce deployment method allows users that are not local admins to install your app, so it is better to choose such a folder on the target machine that should be by default writable for the end user.

Then you use |DataDirectory| in the connection string within your config file, like in the mentioned answer.

The DataDirectory would be a place where you copy the mdb file from exePath to your target data folder.

Your problem also is, that ClickOnce apps are installed in the user profile, so the database, if it is to be shared among different users of 1 computer, should be placed somewhere in c:\users\public folder. If it is to be used only by a single user, it can be placed in documents folder or somewhere in the current user's profile.

So for a shared database your db folder where you copy your mdb after the first deployment could be something like this:

Path.Combine(System.Environment.GetEnvironmentVariable("public"), YOUR_FOLDER_NAME)

for a non-shared database it would be

Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),YOUR_FOLDER_NAME)

There is usually a very good reason not to leave your data in your project folder as it is quite plainly recommended by Microsoft here:

When a ClickOnce application is uninstalled, its Data Directory is also removed. Never use the Data Directory to store end-user–managed data, such as documents.

But if it is OK with you then you might be just fine changing the file attributes in Visual Studio, see this answer.

But also when you udpate the mdb file within your project, the locally installed data file gets rewritten by the published ClickOnce updates - one more link here, just to see that this is quite common approach to have data copied elsewhere by ClickOnce app at startup.

Community
  • 1
  • 1
Vojtěch Dohnal
  • 7,867
  • 3
  • 43
  • 105
  • The connection string is *already* looking into the ApplicationData folder. The question is, how can the OP deploy the database file there using ClickOnce ? Besides, unless the same database is to be used by multiple users of the machine, using the user's App data folder isn't a bad thing – Panagiotis Kanavos Feb 26 '16 at 13:27
  • What if the app gets uninstalled, the data are lost then, I believe...? – Vojtěch Dohnal Feb 26 '16 at 13:28
  • The same as with *every* other application - files that were modified are left behind. That's what Windows Installer does as well. Document-style data is supposed to go into the Documents folder. The rules aren't that different from Store applications – Panagiotis Kanavos Feb 26 '16 at 13:33
  • Still it seems to me more common practice even for ClickOnce app to create another folder either within Documents or somewhere within writable user's folders, so that the data are not left in an obfuscated App folder. – Vojtěch Dohnal Feb 26 '16 at 13:35
  • On the contrary. ClickOnce is supposed to *minimize* impact. And the App Data folder *is* writeable by the application. *Application* data, not *user* data, has no business living outside the control of the application. User data is what documents are about. Besides, ClickOnce is supposed to require minimal priviledges. Making changes to folders breaks that – Panagiotis Kanavos Feb 26 '16 at 13:37
  • Seems to me that MSDN does not share this opinion, see https://msdn.microsoft.com/en-us/library/d8saf4wy.aspx – Vojtěch Dohnal Feb 26 '16 at 21:24
-1

You need to provide the location of you access database in the connection string

dBConnection.ConnectionString  = "Provider=MICROSOFT.ACE.OLEDB.12.0; " +
                "Data Source=|DataDirectory|MyProjectDB.mdb"

|DataDirectory| needs to be a full relative path this is just a placeholder. So you can use

var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);

dBConnection.ConnectionString  = "Provider=MICROSOFT.ACE.OLEDB.12.0; " +
                "Data Source=" + path + "\MyProjectDB.mdb"
James Dev
  • 2,979
  • 1
  • 11
  • 16
  • What is the directory path you are using in the connection string? – James Dev Feb 26 '16 at 13:17
  • As I mentioned, I put the database file in the debug folder, and in the connection string I directly accessed it using `Data Source=|DataDirectory|MyProjectDB.mdb` or Data Source=MyProjectDB.mdb but both didn't work – Hanady Feb 26 '16 at 13:21
  • Updated answer |DataDirectory| is just a placeholder. – James Dev Feb 26 '16 at 13:37
  • The path is relative. If it weren't a ClickOnce, it would already be looking at its current directory. Since it's ClickOnce, 1) it isn't installed in `Program Files`, 2) no content files will be placed in the executable's folder 3) Data is supposed to be placed in the App data, which is why relative paths are redirected to that folder. Simply adding the mdb as content to the project will ensure it *is* included in the deployment – Panagiotis Kanavos Feb 26 '16 at 13:39