Visual Studio 2005, WinForms designer and the DataDirectory.
Why, oh why must the simplest things be plagued with the most annoying problems?
Finally gotten around to messing with Visual Studio 2005, I started a long-overdue project I promised someone. A very simple affair - MDB database, WinForms front-end, no tiers, no nothing. Just a simple customer-management app for 1-2 users.
My first impressions from using the new Studio were excellent - the new WinForms designer is nothing short of wondrous (lines! Give me more lines on the canvas!) and the databinding wizards worked great, straight out of the box. I created my main form, created a user-control that covers most of the input fields, and things went great.
The problems started when I innocently went back to my main form class, to add a toolbar and maybe some menus. I was immediately greeted by a full-screen error message detailing the IDE's failure to find my MDB file, along with a long and detailed call stack leading back to my control's static constructor. The interesting info, though, was in the path - it seems that when in Design Mode, Visual Studio attempts to find my MDB in the "C:\Program Files\Microsoft Visual Studio 8\Common7\IDE" directory - apparently the current directory during development. In runtime things work fine.
I tried cheating, setting the Current Directory in the .cctor - no such luck. I tried checking the connection string that VS created for my MDB, and saw it has a |DataDirectory| token embedded in it, even though editing it showed the full path. This DataDirectory variable is expanded to the wrong path during development. Googling proved remarkably useless here. It's mentioned in one MS blog entry (here) but doesn't show where this is defined in an actual project. Rummaging through the various Settings.settings and Settings.designer.cs files also didn't yield any place where the token is defined. This especially annoying since it was automatically introduced by Visual Studio which does NOT allow me to manually change it to an absolute (or even a relative) path, but also doesn't mention this token anywhere in the documentation.
Additionally, I am miffed that doing the simplest things possible by the book with no fancy business gives me a totally useless error message and no tools to bypass it. How did this one get by the testers? I may have done something really stupid to get here, but I really don't see what I could have done differently.
Currently I think I'll manually edit the .settings and .cs files in Notepad and see if VS doesn't mangle that, too.
EDIT: Forgot to mention - the Settings.settings file does have seperate entries for the runtime and design-time connection strings, which seemed encouraging at first. They both use the |DataDirectory| token, though, which doesn't give me much info. Changing this setting to an absolute path doesn't seem to change anything.
EDIT 2: The Smart Client blog at MS has more info on this DataDirectory macro, but the behavior they're describing (design-time behavior defaulting to My Project directory) doesn't match what I'm seeing. The blog entry is dated August 26th, so it might be a bit out of date.
Even manually setting the DataDirectory variable in the AppDomain (in my Program.cs constructor) doesn't seem to help.
EDIT 3: No only does this code look ugly as hell, it also doesn't WORK:
if (this.DesignMode)
AppDomain.CurrentDomain.setData("DataDirectory", @"C:\Code\MyProject");
Apparently this doesn't change the behavior at runtime, either - that keeps on working even if I set DataDirectory to a non-existant folder.
EDIT 4: Even replacing every single instance of |DataDirectory| with an absolute path didn't help. My choices were to either stop using a ConnectionString-type resource and just save a string and use it myself (and probably lose a lot of IDE support for data sources) or make a copy of the MDB in my Visual Studio IDE directory. So guess what I did.
Interestingly, even though I have a copy of the MDB in the IDE folder, all design-time interaction with the data (through the Server Explorer and Data Sources panels) work with the true, updated data in the proper place. I have to say I am far from pleased with this workaround.
6 Comments
Comments have been disabled for this content.
Tommy Frichot said
I am experiencing the excact same problem, which is driving me nuts!!!
It is in no way possible for me to find a work around for this problem, which means I can't finish the dialogs and controls I am working on. Some things, of course, I can manually alter in the designer.cs files, but how do I for instance alter an Imagelist added to a dialog?
I am in desperate need for a solution on this problem, so if you have come any further with it, please post it.
Avner Kashtan said
Simplest, hackiest workaround is to simply give VS what it wants - if it's missing a file in a directory, simply put a copy of that file there. Simple, ugly but effective.
do0g said
If the IDE is not going to resolve the |DataDirectory| var, resolve it yourself! Right click on the project, select "Properties", go to the settings tab, and in the value for your connection string replace "|DataDirectory|" with "App_Data". Eg: Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\md.mdb;Persist Security Info=True becomes Provider=Microsoft.Jet.OLEDB.4.0;Data Source=App_Data\md.mdb;Persist Security Info=True Also remove any duplicate App_Data entries in the string. Et voila! Instant design and run-time support.
john chen said
It's 2008 now and I am using VS2008. I am having the same problem.
bd said
Sorry do0g, your method does not work - App_Data does not resolve to the project path and you'll just get an error. Test before you post!
mc9000 said
"If the IDE is not going to resolve the |DataDirectory| var, resolve it yourself! ..." Unfortunately, that does not work at all! There is no way to get this to work using the application settings because it is impossible to change the |DataDirectory| token. To make matters worse, if you put in the path to bin/debug, it will append another "bin/debug" to the path at runtime and you will get an error. The only way around is to use an actual database and not a file OR create your own resource string with the database connection string. Using application settings will never allow you use a stand-alone database file for development as it will always READ the database from the folder you specify and always WRITE to either the bin/debug or the bin/release folder where the database is copied. Incredibly stupid design. Why on earth would any programmer want his database moved/copied around indiscriminately while trying to develop an application?!?!?