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.
A quick reminder, after having spent too much time on it this morning:
When impersonating a client context (in this case through SSPI over Remoting), not only can you not access external network resources, you also can't access files and directories encrypted with EFS. I was stumped over this - WindowsIdentity.GetCurrent() returned the proper user, but trying to create a new file in an encrypted folder resulted in UnauthorizedAccessExceptions (Win32 error #5).
The solution - my Unimpersonator to the rescue!
Hmm. Remoting, impersonation, EFS and Access Denied - that should be enough for google to work with, right? :)