Tuesday, July 5, 2011

Not so RelativeSearchPath

[Note: This post is based upon an old blog post that I'm migrating for reference purposes, so some of the content might be a bit out of date. Still, hopefully it might help someone sometime...]

Another .NET version compatibility issue encountered working with the same third party API as described in my earlier post When is String.Empty!= String.Empty?

Under certain conditions when calling this third party .NET 1.1 API from .NET 3.5 we were receiving an exception "Invalid directory on URL". Fortunately the stack trace included enough information for me to whip out my best friend Reflector to reflect inside the API code to see what was going on.

The exception occurred when the API was trying to dynamically load another DLL using Activator.CreateInstanceFrom. In particular, it constructed the path to the DLL using the following:

AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.RelativeSearchPath

This seems to be a fairly common practice where this type of dynamic loading is required, and you need to construct the path at run-time. Unfortunately most of the examples on the web that use this approach use exactly this approach, string concatenation, to construct the path, and don't construct it (or check that it's valid) using System.IO.Path (another of my favourite friends).

When I checked out what the result of the AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.RelativeSearchPath line was, I was somewhat bemused: It was something of the form "c:\projects\webapp\c:\projects\webapp\bin\" (with names changed to protect the innocent).

Huh? Surely that couldn't be right, otherwise it would never have worked!

I whipped up a simple ASP.NET 3.5 web app and examined the values of the two properties used to construct the path, and sure enough they were "c:\projects\webapp\"  and "c:\projects\webapp\bin\" respectively. By this stage, I was assuming that the .NET 1.1 API was expecting RelativeSearchPath to be simply "bin\"...

So, next stop, whip up a simple ASP.NET 1.1 web app and check out the values for the two properties... Hmm, interesting: as the API expected, they were "c:\projects\webapp\" and "bin\" respectively...

So, it would seem that under ASP.NET 2.0+, when the AppDomain is initialised for your web app, the RelativeSearchPath is actually evaluated to the complete physical path to the web app's bin folder... Yay... not so "relative"...

My work-around in this case (as I can't change the third-party API) is to change the AppDomain's RelativeSearchPath just before the call to the API to be "bin\", and just afterwards to be whatever it was before the call... Not pretty, but it works. What I'd really like to understand is why under ASP.NET 2.0+ it's not relative! My suspicion is that it may be initialised to "~/bin" by ASP.NET when the AppDomain starts, and is somehow evaluated to the absolute path as a result of the inclusion of the "~", but I can't be sure...

Anyway, thanks for listening...

No comments:

Post a Comment