URIs are not local paths.

Tags: .NET

It's easy to forget that even though a local filesystem path ("C:\MyDir\MyFile.dll") can be represented as a Uri (file://C:/MyDir/MyFile.dll), these two entities are different, and have different rules for validations.

The problem du jour, the reason I even got into this, was a simple piece of code that was to set the Current Directory to that of the currently executing assembly:

Uri assemblyPath = new Uri(Assembly.GetExecutingAssembly().CodeBase);
if (assemblyPath.Scheme == Uri
.UriSchemeFile)
{
   string dllPath = Path
.GetDirectoryName(assemblyPath.PathAndQuery);
   Directory
.SetCurrentDirectory(dllPath);
}

The CodeBase property of the Assembly class gives us the path as a Uri, since assemblies can also be loaded from HTTP paths.

This worked fine on most machines, but seemed to break on one. The reason? His path was a valid file system path, but not a valid URI:

G:\C#_Projects\MyFile.dll

The problem is that the # sign is a valid path, but a delimiter for URIs - it marks the start of a URI fragment, like a named anchor in an HTML file.  Getting PathAndQuery for the URI simply returned "G:/C", and dropped everything after the #.

The simple solution - rather than attempting to join the URI's Fragment and Path together, is to remove the scheme (file://) from the beginning and consider that a local path:

Uri assemblyPath = new Uri("file://c:/c#_path/file.dll");
if (assemblyPath.Scheme == Uri
.UriSchemeFile)
{
   // This gives us "c:/c#_path/file.dll".
   string dllPath = assemblyPath.OriginalString.Replace(assemblyPath.Scheme + Uri.SchemeDelimiter, ""
);

   // This gives us "c:\\c#_path".
      
   dllPath = Path
.GetDirectoryName(dllPath);
   Directory
.SetCurrentDirectory(dllPath);
}

1 Comment

Comments have been disabled for this content.