Where do I put my data to keep it safe from ClickOnce updates?

Sometimes you want to include a file with your ClickOnce application and then update it using input from your customer. Or about your customer. Or about what your customer is doing with your application. (“You say you didn’t hit the delete button, but according to the log file, you hit it exactly 47 minutes ago.”)

To include the file in your deployment, add it to your project, and set the properties correctly. “Build Action” should be set to “Content”, and “Copy to Output Directory” to “Copy Always”.

When you deploy a file with a ClickOnce application, it is kept with the installed files. When you deploy a new version of the same application, it creates a new folder for the new version, and installs the files there, and you lose access to the original file, which defeats the whole purpose of saving the user’s changes to it. So if you don’t want to lose the file when there is an update, you need to move it out of the deployment folder.

If you are running Windows Vista or Windows 7, there are very few places to which you can write data on the user’s computer (Cancel or Allow?). You could put it in MyDocuments, but the user is likely to stumble over it and hurt his toe and sue you, or he may delete it because he doesn’t know what it is. So to store data used by your application, the recommended location is Local Application Data.

Create a folder in LocalApplicationData using your company name or product name. You could use another company’s name (like, say, ‘Microsoft’), but this might lead to unpleasant surprises down the road. You could also call it George, but you’ll forget that and then spend an hour looking through all the folders trying to find your file.

The first time the user runs the application, you want to create your folder and copy the file over there. When the user runs it the next time, you don’t want to copy the file over there. If you did that, it would be exactly what ClickOnce does, and would defeat the purpose of this entire blog post.

So the most effective thing to do is check for the directory. If it’s not there, create it. Then check for the file in the directory, and if the file’s not there, copy it over. You could assume if the directory is there, the file will be, but if your application mysteriously crashes (like the user’s laptop gets run over by a truck at that exact moment of execution), then the file could be missing. It only costs you one line of code to protect yourself from an embarrassing execution error.

I’ve tried to make this narrow enough to actually fit in my blog. Ordinarily, I wouldn’t use all the extra variables. I’m posting this in both C# and VB because I’m a C# developer trapped in a VB developer’s body.

Here’s the code in C#:

string localAppData =
  Environment.GetFolderPath(
  Environment.SpecialFolder.LocalApplicationData);
string userFilePath
  = Path.Combine(localAppData, "MyCompany");

if (!Directory.Exists(userFilePath))
    Directory.CreateDirectory(userFilePath);

//if it's not already there, 
//copy the file from the deployment location to the folder
string sourceFilePath = Path.Combine(
  System.Windows.Forms.Application.StartupPath, "MyFile.txt");
string destFilePath = Path.Combine(userFilePath, "MyFile.txt");
if (!File.Exists(destFilePath))
    File.Copy(sourceFilePath, destFilePath);

Here’s the code in VB:

Dim localAppData as String = _
  Environment.GetFolderPath( _
  Environment.SpecialFolder.LocalApplicationData)
Dim userFilePath as String = _
  Path.Combine(localAppData, "MyCompany")

If (Not Directory.Exists(userFilePath)) Then
    Directory.CreateDirectory(userFilePath)
End If

'if it's not already there, 
'copy the file from the deployment location to the folder
Dim sourceFilePath as String = Path.Combine( _
  System.Windows.Forms.Application.StartupPath, "MyFile.txt")
Dim destFilePath as String = _
  Path.Combine(userFilePath, "MyFile.txt")
If (Not File.Exists(destFilePath)) Then
    File.Copy(sourceFilePath, destFilePath)
End If

One thing to note is that when the user uninstalls the application, the data will not be removed, it will remain there forever, or until the user’s laptop gets run over by a truck, and then technically it’s still there even though he may no longer be able to access it. If the user donates his laptop to one of those electronics recycling centers, and instead of wiping the hard drive like they claim, they actually look at the files on it, they will see your file. (You might not want to store the user’s social security number in the file w/o encrypting it.)

On the other hand, if the user ends up having to uninstall and reinstall the application because you accidentally changed the target CPU setting in the deployment properties and didn’t realize it would change the deployment identity and everybody in the company plus a bunch of customers would call you and ask why their upgrade didn’t work (don’t ask), his cached data is still available (small comfort, but better than nothing).

You could actually use this method to handle deploying a SQLServer Compact Edition database or an Access database. Or you could copy Hamlet over to the folder and have the computer read it aloud to your customer. (Everything I learned about Hamlet, I learned from that episode of Gilligan’s Island where they did Hamlet to the music from Bizet’s Carmen. “Neither a borrower not a lender be…” “I ask to be, or not to be, and that is the question that I ask of thee…”)

Tags:

61 Responses to “Where do I put my data to keep it safe from ClickOnce updates?”

  1. FruimiVemiale Says:

    Fantastic, I did not heard about that till now. Thanx.

  2. Matias Says:

    Great post, this was very helpful.

    • robindotnet Says:

      Thanks! Glad it was helpful to you.

      • Hamlia Says:

        Robin,

        I have been reading all day long about this topic, your blog post and I am still having more questions than answer. First of all, Thanks for the work you did in this post. Secondly, This is my first time deploying any applications and I am new to programming as whole and learning. Now, my question is this, I get your point of making a folder in LocalApplicationData but one think i don’t understand is, where to but the VBcode you have given here. Do I need to create some kind of class? where should I call that class, I tried in the appconfig and that is xml. I am using VB.net, 4.5, SQLServer express and my machine is windows 7 professional, and I am using VS 2010 professional with clickOnce deployement. Your step by step help will be greatly appreciated. I think you did a great job in this post but I don’t think it helps people who are beginners and very slow like me so Step by step will definitely help. Thank you very much in advance

        • robindotnet Says:

          The code to create the folder (and data) in LocalApplicationData needs to go in the application startup. In C#, it’s program.cs, but with VB, there’s a specific place to put application events that’s surfaced through Visual Studio. I used Bing and here is what I found.

          Bing is your friend, dude.

          Robin

  3. ronald brans Says:

    ehm.. so where do i put the code above in the code of mine below(link)??
    ehm kinda new(4months) to c#

    http://csharp.pastebin.com/m11c28929

    • robindotnet Says:

      Hi, I believe you are the same person who posted this thread in the MSDN Forum. Can you please post your followup question there, so others can benefit from the answer? Also, if you copy your code and paste it into Notepad and then copy it in Notepad and paste it into the forum, it will help with your formatting problem.
      Thanks,
      Robin

  4. Stack on Gun Safe Says:

    Hi, I can?t figure out how to add your site in my rss reader. Can you Help me, please? I really want to read your future posts.

    • robindotnet Says:

      Hi,
      If you click on this, it will take you to a page where you can subscribe to the RSS feed. (This is also at the bottom of my blog and is called ‘Entries (RSS)’.)
      Thanks,
      RobinDotNet

  5. How to deploy the SQLServer Compact Edition software locally « RobinDotNet's Blog Says:

    […] your database change only when you intend it to, you might want to check out my blog entry titled Where do I put my data to keep it safe from ClickOnce updates? I think the title is […]

  6. habutom Says:

    Thanks Robin. Your articles are very helpful.

  7. bob Says:

    If my sub-directory is empty, I get a File Not Found exception.

    It works fine pre-publish, and it even works if I click the .exe…but it won’t work if I use the “Application Manifest” file (The same one that clickonce puts in my start menu to start the program)

    • robindotnet Says:

      Why is your subdirectory empty? Are you creating the data there, or copying it over there? You should be checking, as noted in the article, to see if it’s there. Are you putting the data in LocalApplicationData? Please provide more details and I will try to help you.

  8. Jiminka Says:

    Hi , This blog post helped me to implement a clickonce application with a deployed Access DB file.
    I ran into a problem accessing my DB file on the deployed client side. I kept getting a ‘file not found error ‘when I tried to move the DB out of the deployed Application.StartupPath directory. I tracked the problem down to the ‘Publish Status’ setting in the project=>properties=>Publish=>Application Files VS2008 dialog.

    The problem was caused by my ‘Publish Status’ being set to ‘Data File’. If you set the ‘Publish Status’ to ‘Include’ then the DB file will be deployed to the Application.StartupPath directory.
    The DB file ends up in the app DATA DIRECTORY with a ‘Publish Status’ of ‘Data File’. This DATA DIRECTORY has special properties that guarantee a user will never lose their modified deployed DB on the next publish.

    The MS help system has a whole page on this functionality.
    if you have VS2008 See:
    ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/dv_fxdeploy/html/be5cbe12-6cb6-49c9-aa59-a1624e1eef3d.htm
    or search for ” Accessing Local and Remote Data in ClickOnce Applications” in help

    The help page is not very clear on the special properties. I have observed the following.

    Scenario 1: USER has modified their deployed DB locally. SERVER has NOT modified the DB file.
    Results of next publish: The new version deployed DATA DIRECTORY will contain the USER’s
    modified DB. The server does not overwrite the USER’s DB. The Deploy operation moves
    the USERS previous version to the new versions DATA DIRECTORY

    Scenario 2: USER has NOT modified their deployed DB locally. SERVER has modified the DB file.
    Results of next publish: The new version deployed DATA DIRECTORY will contain the SERVER ‘s
    modified DB.

    Scenario 3: USER has modified their deployed DB locally. SERVER has modified the DB file.
    Results of next publish: The new version deployed DATA DIRECTORY will contain the SERVER ‘s
    modified DB. The server does not overwrite the USER’s DB. The Deploy operation moves
    the USERS previous version to a subdirectory (.pre) of the new versions DATA DIRECTORY.

    In all cases the user does not loose any data in their local Db file. Scenario 3 allows the application to access the DATA DIRECTORY subdirectory ‘.pre’ to merge or update the USERS modified DB data with the new DB data added by the SERVER for the Version update. This seems like a powerful bit of functionality.

    In addition the System.Deployment.Application.ApplicationDeployment object allows a deployed application to check (IsNetworkDeployed() ) if it is running on a deployed instance, Check for first use with (IsFirstRun() ). ….

    The Data Directory is accessed by changing
    string sourceFilePath = Path.Combine(System.Windows.Forms.Application.StartupPath, “MyFile.txt”);
    to either of the following:
    string sourceFilePath = Path.Combine(
    System.Deployment.Application.ApplicationDeployment.CurrentDeployment.DataDirectory,
    “MyFile.txt”);
    string sourceFilePath = Path.Combine(
    System.Windows.Forms.Application.LocalUserAppDataPath, “MyFile.txt”);

    CONCLUSION: Using a Publish Status of ‘Data File’ might be an alternative choice for deployed clickonce application user modifiable files. The built-in functionality of the DATA DIRECTORY publishing updates allows one to avoid the application copy file scheme.

    • robindotnet Says:

      Hi. I am aware that this is the intention and design of handling data files in ClickOnce deployment. However, the problem with it is you can all too easily replace your database unintentionally and lose the customer’s data. For example, if you have a SQLCE database that you are deploying, and you open the database in Visual Studio to do something as simple as look at the structure of a table, it changes the date/time stamp on the database. It will then be deployed with the next version of the application. It then puts the new database in the DataDirectory and the old one in the .\pre folder. Chances are good that you won’t even realize a new version was deployed, because you just opened it to check the table structure — you didn’t add any fields or change anything about the database properties. If you don’t have code in place to handle the update you don’t know about, your user appears to have lost all their data. If you don’t realize it before the next version is released, the user’s data can be lost permanently. To me, this is too big of a risk to take, when you can just copy the database to a new location upon first install, and specifically handle the replacement of it, or the structural changes, yourself.
      Also, what if the user uninstalls the application and reinstalls it for some reason? The data is gone forever. If you copy it to the LocalApplicationData folders, it is still available when the user reinstalls the application.
      These are the primary reasons I recommend taking this approach rather than retaining your data in the ClickOnce cache.

      • Daniel T Says:

        Hi Robin,

        Thanks for the great answers as usual. Could you please elaborate on this response to those that struggled to follow the reader’s question?

        For example, by default an SQL Compact Edition database is published as a “Data File”, rather than an “Include” file. I didn’t quite understand whether it’s better to
        a) Change the publish status to “Include” (note-to-self: this will change the connection string) and use the code as you’ve written it.
        b) Leave the publishing as “Data File” and change the directory string to the data directory as Jiminika said.

        I mean, I know you said a) but don’t really get why. I didn’t even realize that there was a separate data directory until I looked in the AppData folder. I notice that it branches after ‘C:\Users\MyUserName\AppData\Local\Apps\2.0\’ into a data path and an application path…

        • robindotnet Says:

          Sorry. I meant to write a post about databases specifically, but haven’t gotten to it. Here’s the deal with the database deployment.

          If you include a database with your ClickOnce application and deploy it to the data directory, it puts it in the \data\ folder in the cache. Then when the user installs the next version, it checks the database for an update, and if there isn’t one, it copies the database forward to the folder for the new application version.

          If the database has changed, it copies it to a folder called .\pre UNDER the datadirectory, and you’re supposed to have code that handles transferring the data from the (previous) database in the .\pre folder to the new database in the datadirectory.

          That sounds ducky, doesn’t it? It’s not — it’s really quite dangerous. Why? Because if you so much as open that database included in your development project, even just to check a table structure, it will change the timestamp on it, and ClickOnce will think it’s a new copy and deploy it, and you won’t be handling it because you didn’t mean for that to happen, and your user will have lost his data at least temporarily. Oops.

          So in my opinion, it’s safer to move the database to LocalApplicationData and point to it there. Then if you inadvertently publish a new version of it, the user doesn’t lose his data. You can then handle changing the structure of it by using queries, or by copying the *new* database and migrating the data, but you will plan for this and know you have to do it.

          In fact, one cool thing you can do is include T-SQL statements in, for example, resources (with a version number) and if IsFirstRun is true, execute any that are found there for the current version. (IsFirstRun is true right after an update is installed or the application is installed the first time). This kind of automates updates to the database or database structure. You’d have to somehow put version numbers on them so you would know how many versions of them to run, right? So if the user went from 1.3 to 1.4, and his previous version was 1.3, you’d just run the 1.4 update queries. If his previous version was 1.2, you run the 1.3 and 1.4 queries. That kind of thing.

          Hope this helps!
          Robin

          • Daniel T Says:

            Thanks Robin.

            You mentioned changing the database on the developer’s machine, but doesn’t the database also (usually) change whenever the user accesses it via their app? i.e. saving their data? How does the data directory deal with this?

            Anyway, I also thought I’d point out something I mis-understood about the approach in this post, for those having a slow brain day like myself. Correct me if I’m wrong.

            Do this:
            The LocalAppData directory is the place that you put the database, and the place that the app uses it. That means put the database there AND use it from there too.

            Not this:
            Keep a master/latest version of the database in the LocalAppData folder and copy it back an forth to the deployment directory.

            Aha.

          • robindotnet Says:

            That’s right Daniel. There’s no point to copying the database back and forth repeatedly. You just need to move it the first time, and change your connection string to handle it from there.

            Another thing to remember — when you run your application in Visual Studio, it will move the database the first time and then not move it after that, so your data will essentially be persisted in LocalApplicationData and accessed there as well. So if you *want* a new database or *want* to test this a second time, you will have to drill down to ApplicationData and remove your folder and/or database file.

            Robin

          • Daniel T Says:

            Oops I see Jiminka’s post actually answers my first question about changing the database on the client side.

  9. amazon plugin Says:

    Very thrilling blog publish thank you for writing it I just added your site to my bookmarks and will examine back later 🙂 By the way that is truly a tiny off topic but I really like your websites layout.

    • robindotnet Says:

      Thanks! This is a (free) wordpress blog. I signed up for one of the themes and then messed around with it. CSS is not my skill, so there were some funky-looking versions before I stopped messing around with it. 🙂

  10. assimilater Says:

    Took me a while to get around to this but it was helpful. One note in the vb code, at least for vb 2010 you can’t use the old familiar c-based “!”, in basic it’s the lame English word “Not” (sad that I am more fluent in basic than a c-based language now, I’d prefer c# just haven’t had time to experiment).

    Wow, that turned into a little bit longer of a post than I planned…lol

    • robindotnet Says:

      Yikes, you’re right. I must have edited that on the fly; I’ll fix it. Thanks for letting me know! And there’s nothing wrong with VB. There’s not much difference between VB and C# nowadays, so it’s really just a matter of syntax and what makes you happy.

      • assimilater Says:

        C-based languages are just so much more structured. I’m so glad I’m converted back to my old c-based languages. I started out with c++ for MetaTrader4 (read as not useful anywhere else), then took a computer programming class in high school. They didn’t teach me squat about programming but they showed me where to download visual basic. I learned on my own from there. It wasn’t until recently when I got converted back to c#.

        For example: how does vb know that “=” is intended to compare two items instead of set one item to a given value? That bugged me when I first started. Another pet peeve as I was learning vb is the nature of object or in-explicit declarations…(it’s REALLY bad in vba).

        Anyways, that’s my rant. I’m glad I finally bucked up and learned c# :P.

        • robindotnet Says:

          Frankly, C# and VB are pretty much the same language. You can’t do XML Literals in C#, and the syntax is different, but with each release they get closer and closer together. The choice of one over the other is really mostly one of what people are comfortable with. I was a VB6 programmer, then VB.NET, and then C# because the job I was offered (that I really wanted, because it looked like so much fun) was C#. I had to do a little scrambling to pick up the C# syntax, but it wasn’t a huge problem. I still write my Office Add-Ins in VB because it makes sense. Also, VBA is a completely different ball of wax from VB.NET. I think Microsoft is looking at ways to let you write structured .NET code instead of VBA, which should be interesting. There are far more VB and VBA programmers in the world than C#, so being open-minded and understanding the underpinnings just makes for better relations. 🙂

  11. .net and click once and settings | LieberLieber Software TeamBlog Says:

    […] So if you can make sure, that none of the 3 reasons will ever appear, let click-once setup handle your settings files. Otherwise, you might consider moving the files to a location outside the click-once environment (e.g. the localappdata folder). Get an idea of how to do this in this article. […]

  12. Lavanya Says:

    Nice Article, I had used a similar approach to move sdf file using msi installer. Currently trying to do the achieve the same thing using Click once and i am curious How can i Copy my Sdf file into AppData since i don’t have any control over Installing the App i.e Custom Actions.

    • robindotnet Says:

      It’s not part of the installation itself, you have to put the code in the startup of your application. In C#, this would be in Program.cs; in VB it would be in the Application Start event. Check to see if the folder is there, and if it’s not, create it and copy the files. If the folder is there, check for the files, and if they are missing, copy them over there. This way, you don’t overwrite the files once they are set up. The other thing about this approach is if the user has to uninstall and reinstall the application, he doesn’t lose his data.
      Robin

      • Lavanya Says:

        Thanks for reply, How can i get the Installed Path i.e Application.exe path Programatically?

        • robindotnet Says:

          If it’s a Windows Forms application, look in System.Windows.Forms.Application.StartupPath. I don’t know if this will work for a WPF application, but you could try it. Or pull the assembly information and get the path to the executing assembly. If you look at this post, it shows how to find it for VSTO. I am pretty sure the same code will work for a non-VSTO application.

  13. Daniel T Says:

    Hi Robin,

    Given that the database changes (usually adding new data) between application startup and application shutdown, when do you recommend calling this method?

    Would you use it in both the Window_Loaded (i.e app start) and Window_Closing (i.e. app end) event handlers? Or maybe just the latter…

    Thanks,
    Daniel.

    • robindotnet Says:

      Hello Daniel,
      In C#, I would run the code in Program.cs before starting up the application. In VB, I would do it in the Application_Startup event handler. I only move the data from the C/O cache if it hasn’t been moved before. If you have a database and need to make updates, that would be the place to do it as well, checking IsFirst (means they just installed it or just for a new version) so you don’t try to do it repeatedly.
      Robin

  14. zafi Says:

    Hi Robin,

    A very useful information. A broder perspective of ClickOnce Deployment
    I would like to ask you a few questions on the codes that you gave.

    ‘if it’s not already there,
    ‘copy the file from the deployment location to the folder
    Dim sourceFilePath as String = Path.Combine( _
    System.Windows.Forms.Application.StartupPath, “MyFile.txt”)
    Dim destFilePath as String = _
    Path.Combine(userFilePath, “MyFile.txt”)
    If (Not File.Exists(destFilePath)) Then
    File.Copy(sourceFilePath, destFilePath)
    End If

    for the myfile.txt. Why do you create this?where do you put this in your computer?
    Based on my understanding I should create the myfile.txt and place it in my bin\debug folder?

    I am sorry for my silly questions. I am new to Vb and willing to learn. and I keep asking If I don’t understand. I hope to improve from time to time.

  15. zafi Says:

    Hi Robin,

    I forgot to add. MyCompany that you have shown in the codes. Is it means that It will be created in the folder and data from Myfile.txt will be copied there?

  16. Andy C. Says:

    Hi Robin,

    Is there any way to do database updates to a smart client’s local or network database fully transactionally with ClickOnce? For example, we don’t want to update the app until the database is up-to-date or we could rollback the app update (programmatically) if the database update fails? All samples I’ve seen (including Microsoft’s) just fire off SQL updates at start up if it’s the first run. What if they fail?

    Thanks,
    Andy C.

    • robindotnet Says:

      I have seen one idea about putting a T-SQL script into Resources and then executing it. If you wrote the script right, I think you could make it rollback the changes instead of commit them, but I’m no expert on that. The hard bit would be rolling back the C/O update. You can do that programmatically. I’d add a small exe and include it in the deployment, and if the database scripts failed, call the exe and exit. Or you can embed the code in the C/O app and have it uninstall the most recent version itself. If you check out my article on Certificate Expiration on MSDN, it shows how to uninstall a C/O app programmatically; it can be adapted pretty easily to do a rollback instead.

    • robindotnet Says:

      If you wanted to do the updates beforehand, you would have to do it using a prerequisite, which is clunky (plus, you would have to have your user run the exe specifically). Why not have the ClickOnce application update the database when it runs, and if it fails, back out the changes? The other thing you could do is copy the database to another location, make the updates to it, and if they are successful, copy it back, or something like that.

  17. BugMan Says:

    Wow… I was so bummed when I tested my first ClickOnce installation and realized everything was buried deep in subfolders. And I would have to provide the data files that my app uses separately…

    But you solved the problem with useful post. I am loving ClickOnce now, solves a world of headaches using traditional installations.

    thank you from a veteran VB programmer hack.

  18. rodsmusings Says:

    I’ve been referred to this post several times, and I almost think it is going to help, but then I run into a different problem. I want to have a SQL Server 2008 Express database, unique to the user. So, it was suggested that I check out your post here, which I did. I created a folder under the folder pointed to by LocalApplicationData. The folder’s name is the agency I work for. I then detached a SQL Express database, which I had created elsewhere, and moved it to this new folder under LocalApplicationData\MyAgency. However, when I tried to re-attach the database using SQL Server Management Studio 2008, it refused to go any further down the my profile under C:\Users\Rod on my Windows 7 machine. Do you have a work around for this situation?

  19. Tyler Says:

    Robin, great post! I picked up a lot of valuable information I wasn’t aware of before now. To sum up what you’ve done, you are almost mimicking the functionality of the ClickOnce ‘data’ directory. However, you maintain control of your ‘data’ directory instead of ClickOnce running amok and potentially invalidating your user’s data.

    Every application and every scenario calls for different solutions, so this is neither here nor there. But one comment I’ll make is that if you uninstall your application (for good), you never have a chance to delete your data directories. They will remain orphaned on your file system indefinitely. On the other hand, ClickOnce WILL delete its ‘data’ directory upon uninstall, (which you pointed out may not be a good thing.)

    A couple tips to possibly mitigate issues with ClickOnce’s management of the data directory. Always have an IsFirstRun block to deal with an update (intentional or not). At a minimum (if the update is not intentional), the block will copy anything in the ./pre directory back out to the data directory, and remove the ./pre directory. Another approach (which may or may not apply to a given situation) is to keep a user’s data directory “in sync” with a central repository. Probably more ideal for a trusted business type application, but you can use MS Sync Framework to keep a SQLCE database (or another data store) “in sync” with a SQL Server database (or another centralized data store). In this way, if the data directory is ever hosed or uninstalled, it can by “synced up” with the central data store and rebuilt for the user.

    Also, a possible alteration to your approach would be to use the “Isolated Storage” API instead of directly reading/writing to the user’s App Data directory within their profile. It’s pretty much the same thing, and maybe adds a little more complexity, but probably provides more stability and standardization across the various flavors of Windows.

    • robindotnet Says:

      Thank you for your feedback. Although it will leave the information behind, I still believe that segmenting the data out into a separate folder in the user’s cache is better than using ClickOnce’s data deployment strategy. There’s just too much risk that you can easily wipe out the data without even realizing it. The other advantage is when your users uninstall and reinstall for any reason (like you want to change the target CPU of your application), their data will remain intact. It will also work with online-only applications, where storing it in the DataDirectory will not.

      As for Isolated Storage, it doesn’t buy you anything over writing to the user’s profile except that it is a bit more complicated. When Windows Vista came out, Microsoft locked down the Program Files folder, and recommended that you store application data in the AppData folder, MyDocuments, or Isolated Storage. I’m not sure why you think using Isolated Storage would give you more stability and standardization across Windows than using AppData; I see no reason for that.

      Anyway, there are lots of variations available, so each person can pick which method works best for them.

      Robin

  20. D3M80L Says:

    Nice article: I found some post, that is related with your post.
    http://msdn.microsoft.com/en-us/library/aa730870(v=vs.80).aspx (Easy Deployment)

    • robindotnet Says:

      Yes, I’ve seen that. I still think it’s too risky to use the default behavior recommended by Microsoft. All you have to do is open that database and check the structure, and it changes the date/time stamp on the file and deploys it! If you’re really mindful, it might not ever impact you, but if it does, it will be at the worst time possible! (Murphy’s Law).

  21. Tharindu Says:

    how to attach sql database file to creating .exe setup in java

  22. shah Says:

    Hi there Robin. Great article!!I was looking for a way to overcome the database problem ClickOnce. May I know where to put the code because I put it in my Program.cs but it seems like it doesn’t working. When I deploy the new updated version, it still replace my current edited database with a new one(empty one). Sorry if the question sounds funny because I’m still new to programming.

    • robindotnet Says:

      Be sure to follow the directions carefully. YOu need to programmatically copy your database out of the ClickOnce cache to another folder under LocalApplicationData. Check to see if it exists before copying it so you don’t copy over it. You’ll also need to change your connection string to reflect the new location of the database. Make sure you do that, or you’ll be always be accessing the one included in the ClickOnce cache rather than the one you copied so it wouldn’t be overwritten.
      Robin

      • shah Says:

        well I did follow your directions as stated above carefully. By meaning of carefully I mean I did all those set the file properties and use the code you posted above. Technically I did understand what you meant but in terms of code, I am still quite lost. Sorry.

  23. Marc Says:

    I had a similar idea with regards to an application i am making at the moment. The program has a tray icon, and because of the way ClickOnce updates, if you set the tray icon to “show icon and notifications”, after an update the icon is hidden again because it thinks it’s a different program.

    So what i’ve done is create a “launcher” app which has the exe and dll of my actual app embedded in it as resources, and when running the launcher, it copies those files to a folder in Appdata and then runs the exe. Transparent to the user, and solves my problem. Just have to see if i can get version number from the exe file on the system to make sure if the user rolls back their ClickOnce install for some reason, that the launcher will downgrade the exe on the system.

  24. Jon Says:

    Would this work with a SQL Server Express Database as well? I used “Add Item” to include an express database in my project, but I would prefer to move the database to LocalApplicationData like you suggest. If my connection string is “Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\TestDatabase.mdf;Integrated Security=True;User Instance=True”
    What should I change it to?
    Thanks

    • robindotnet Says:

      Hi Jon,
      Yes, this will work with SQLServer Express. If you move your database to LocalApplicationData as recommended, you would change the AttachDBFilename to point to that location. |DataDirectory| is a ClickOnce directive and means the \Data directory under the ClickOnce cache.
      Robin

  25. Julio Says:

    hi,
    i’m using a access data base with my windows forms clickonce application; when the data changes locally and are updated, the next time i call the program the changes are not made; i need the changes can be made. It’s possible ? , i need help !!
    Julio

    • robindotnet Says:

      Are you seeing this with the deployed application, or the one you are testing locally? If you are running it in Visual Studio, and you have not implemented moving the database to LocalApplicationData, it will copy a new one into the \bin\debug folder every time you build, making it seem as if your changes have been lost. This is another advantage of moving the database the first time you run the application.

      If you are seeing it with the deployed application, are you moving your data to LocalApplicationData the first time the user runs the application, or leaving it in the Data Directory under the ClickOnce cache? If the former, be sure you are checking to see if the database already exists, and don’t copy and replace it if it does. If the latter, it should copy it forward, unless you changed the date/time stamp on the one in your project, at which point it would deploy it again.

      Robin

  26. tsgreg Says:

    Hi Robin,

    I just found your blog and I have found this very informative. I have been searching for a solution to stop user data loss upon the installation of an update.

    I have tried your code in my C# windows forms application with a connection string of C:\users\tom\AppData\Local\ ….. to connect to the local Sql Database that I successfully moved with your code and it works great in the debug mode.
    However, this connection string will not work for the published version. Do I need a different connection string for the published version?, Is there a connection string that will work for both the debug and published versions and how and where do I put this connection string in my application?

    Also, I forgot to mention that I want the application to be able to be deployed on any computer so the connection string would need to be universal.

    Thanks
    Tom

    • robindotnet Says:

      You need to be sure you’re programmatically creating the connection string, and definitely don’t have it hardcoded. If it works in debug mode when running it in Visual Studio, but not when deployed, then you either have the wrong connection string or the database isn’t where you think it is. If you use the code provided to access the Local Application Data folder, it will work on any Windows computer.

  27. Mehdi Says:

    HI Robin,

    I found your blog and I tried your code. Unfortunately my database will not be copied to the custom folder. I am using Windows 8. Is this the problem?

    my code:

    if (System.Deployment.Application.ApplicationDeployment.CurrentDeployment.IsFirstRun)
    {
    string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
    string userFilePath = Path.Combine(localAppData, “DaMedStundenApp”);

    if (!Directory.Exists(userFilePath))
    Directory.CreateDirectory(userFilePath);

    //if it’s not already there,
    //copy the file from the deployment location to the folder
    string sourceFilePath = Path.Combine(System.Windows.Forms.Application.StartupPath, “dbStunden.sdf”);
    string destFilePath = Path.Combine(userFilePath, “dbStunden.sdf”);
    if (!File.Exists(destFilePath))
    File.Copy(sourceFilePath, destFilePath);
    }

    regards,
    Mehdi

    • robindotnet Says:

      What error are you getting? Is the database in the same folder it’s looking for it in the sourceFilePath? I need more information before I can help you.
      Robin

  28. Roy Thompson Says:

    Hi Robin

    This is really useful but I have a problem.

    I am trying to deploy an ACCESS database and unless I set its deploy location to Data my click once deployment just hangs. It copies all the files up to and including the mdb but then gets stuck.

    I can deploy the mdb if I tell it to put it in the data folder but then what should my sourcefile path be? in your vb example you have it as Path.Combine(System.Windows.Forms.Application.StartupPath but this is not correct for a data file. What should I point it to?

    Thanks

    Roy

Leave a reply to Mehdi Cancel reply