Saturday, July 24, 2010

Done in by the current working directory

I know I've said it before, but I hate computers. No, really. I wonder why I didn't get interested in a safe, risk-free profession like alligator wrestling.

Today's rant began with a threat, in a manner of speaking. My employer has a client, and they got served a notice of unsatisfactory service by their client. They came to the office, and since my boss wasn't around, they spoke to me. An application was required, they didn't have the manpower to build it. I decided to build the application as requested by them since continued business for them implies continued business for my employer.

The problem

Yesterday, we went to deploy the application. Then all hell broke loose. I ran the application, entered the settings, no problem. We loaded a list of numbers, clicked 'Send'. Nothing happened. I then tried to reload the settings and see if we had an issue, then...boom! Exception! I don't need to tell you we returned to my office, tails between legs. I later pinned down the problem to a single scenario: As long as you didn't try to load a list file, you could view the settings dialog. Once you did, however, you would get an exception which basically said the application couldn't find the settings table.

I couldn't make heads or tails of the situation, especially since my settings database file (I used a SQLite database file to store the application settings. When, later, in Freenode's C# channel, someone asked why, I didn't really have an answer — actually, I did: an application can't write to its own configuration file, and I hate parsing XML, and I haven't learned LINQ yet. This last experience is enough to migrate me to .NET 3.0 at least). Then I noticed, by chance — as it were — that I was seeing my database file on the desktop of my test system. File size? 0 bytes. Then, it hit me: I was loading my list from the desktop. That meant that Castle ActiveRecord, which was my data access layer (overkill. Yes, I know it all too well), somehow terminated the database connection, tried reconnecting it after the list was loaded, and (obviously) failed to.

This was the connection string: Data Source=app.bin;Version=3;New=True. Readers used to ADO.NET and SQLite will know this means the database file, app.bin, can be recreated if it doesn't exist. Also, it's supposed to be in the same directory as the running executable (the current working directory). On startup, my application checked if the settings file existed or had a size of zero bytes. If so, the application would automatically create the tables needed and populate them with defaults.

The problem, understood

Sadly, sometime during the application, the connection was closed. When the list file got selected, the current working directory was changed. On trying to load the settings dialog after the list file was selected, the connection was reopened (with the new working directory) and the database file was created. However, the schema would not be recreated, so the settings table would not exist, giving rise to the exception. My mistake was assuming the ActiveRecord would keep the connection open throughout the application's run. It didn't

Attempted solutions

  • In my ActiveRecord classes, I tried setting the current working directory just before any class method was used. Looking back, it wouldn't have worked, since ActiveRecord would already have a working connection to the database before trying to access the table. So it would still be trying to access the wrong file
  • I tried setting the current working directory somewhere before trying to access my ActiveRecord classes/instances. Probably due to the fact that I was hungry and indebted to sleep, I put it in a wrong place, and it didn't work (then again, it might not have worked).
  • Moving the ActiveRecord configuration from the application configuration file to code (using InPlaceConfigurationSource), and using the absolute path to the database file in the connection string, instead of a relative path. This 'solution' was the worst. The application didn't even run after this (again, not on my development machine — not once did I have problems running from my development machine, whether debugging with Visual Studio or running standalone), it just gave that Error Reporting dialog thingie.

Something I did NOT try was setting the working directory immediately after loading the list file. It might have worked. After everything, I scrapped the application and am rewriting it currently. I'm using XML serialization for the settings storage.

I'd like to appreciate the SlimTune developers — SlimTune helped out a great deal. When CLR Profiler failed me, I was able to use SlimTune to find out where my application was eating up some processor time on startup.

No comments: