Assembly.CodeBase looks promising, but it's a UNC path:
Do note that it is something approximating a file uri, not an UNC path.
You solve this by doing string manipulation by hand. Seriously.
Try all other methods you can find on SO with the following directory (verbatim):
C:\Test\Space( )(h#)(p%20){[a&],t@,p%,+}.,\Release
This is a valid, if somewhat unusual, Windows path. (Some people will have either one of these characters in there paths, and you would want you method to work for all of those, right?)
The available code base (we do not want Location
, right?) properties are then (on my Win7 with .NET 4):
assembly.CodeBase -> file:///C:/Test/Space( )(h#)(p%20){[a&],t@,p%,+}.,/Release
assembly.EscapedCodeBase -> file:///C:/Test/Space(%20)(h%23)(p%20)%7B%5Ba%26%5D,t@,p%,+%7D.,/Release
You will note:
CodeBase
is not escaped at all, it's just the regular local path prefixed with file:///
and the backslashes replaced. As such, it does not work to feed this to System.Uri
.
EscapedCodeBase
is not escaped completely (I do not know if this is a bug or if this is a shortcoming of the URI scheme):
- Note how the space character (
) translates to %20
- but the
%20
sequence also translates to %20
! (percent %
is not escaped at all)
- No one can rebuild the original from this mangled form!
For local files (And that's really all I'd care about for the CodeBase
stuff, because if the file ain't local, you probably want to use .Location
anyway, the following works for me (note that it isn't the prettiest either:
public static string GetAssemblyFullPath(Assembly assembly)
{
string codeBasePseudoUrl = assembly.CodeBase; // "pseudo" because it is not properly escaped
if (codeBasePseudoUrl != null) {
const string filePrefix3 = @"file:///";
if (codeBasePseudoUrl.StartsWith(filePrefix3)) {
string sPath = codeBasePseudoUrl.Substring(filePrefix3.Length);
string bsPath = sPath.Replace('/', '\\');
Console.WriteLine("bsPath: " + bsPath);
string fp = Path.GetFullPath(bsPath);
Console.WriteLine("fp: " + fp);
return fp;
}
}
System.Diagnostics.Debug.Assert(false, "CodeBase evaluation failed! - Using Location as fallback.");
return Path.GetFullPath(assembly.Location);
}
I am sure one can come up with better solutions, probably one could even come up with a solution that does proper URL en-/decoding of the CodeBase
property if it's a local path, but given that one can just strip off the file:///
and be done with it, I'd say this solution stands as good enough, if certainly really ugly.