Working with files can be quite fun in ASP.NET, especially when some of the tools provided by the framework don't always work as expected. I came across an issue recently with
System.IO.Path.Combine() that had me scratching my head for quite a while. I've used this method previously without issue but this particular case was cause for concern. For instance, the following code:
System.IO.Path.Combine("c:\root\", "\directory\file.txt");
Returns the path:
\directory\file.txt
I was hoping for something more along the lines of:
c:\root\directory\file.txt
I'm not sure why it doesn't work as intended. After doing a few quick Google searches I found out that I wasn't alone in my troubles with this. It turns out that a lot of people are a little upset with the lack of functionality with this particular method. This
blog in particular helps to highlight some of the unusual concatenation attempts when combining two relatively simple paths.
Some examples of this (duplicated from the
thingsihateaboutmicrosoft blog):
Example | Path1 | Path2 | Result |
A | c:\path\ | dir\file.txt | c:\path\dir\file.txt |
B | c:\path\ | \dir\file.txt | \dir\file.txt |
C | c:\path | dir\file.txt | c:\path\dir\file.txt |
D | c:\path | \dir\file.txt | \dir\file.txt |
E | c: | dir\file.txt | c:dir\file.txt |
F | c: | \dir\file.txt | \dir\file.txt |
You can see that in B, D, E and F we don't get the response we would expect. In fact only two of these provide a result that would pass as valid. We shouldn't really have to do lots of string manipulation (i.e. removing or appending leading and trailing slashes) before passing our paths to Path.Combine() because that's what it's for, right?
After realising that I didn't want to have to do extra string manipulation for every path I ever pass to Path.Combine() I decided to write my own wrapper method that would do some of the hard work for me, so here it is:
namespace BaseFour.IO
{
public static class Path
{
public static string Combine(string path1, string path2)
{
// Ensure neither end of path1 or beginning of path2 have slashes
path1 = path1.Trim().TrimEnd(System.IO.Path.DirectorySeparatorChar);
path2 = path2.Trim().TrimStart(System.IO.Path.DirectorySeparatorChar);
// Handle drive letters
if (path1.Substring(path1.Length - 1, 1) == ":")
path1 += System.IO.Path.DirectorySeparatorChar;
return System.IO.Path.Combine(path1, path2);
}
}
}
Use it in exactly the same way as the System.IO.Path.Combine() method, but remember to put it in it's own namespace first or it is likely to clash if you're referencing System.IO in the same class.
And some test results:
Example | Path1 | Path2 | Result |
A | c:\path\ | dir\file.txt | c:\path\dir\file.txt |
B | c:\path\ | \dir\file.txt | c:\path\dir\file.txt |
C | c:\path | dir\file.txt | c:\path\dir\file.txt |
D | c:\path | \dir\file.txt | c:\path\dir\file.txt |
E | c: | dir\file.txt | c:\path\dir\file.txt |
F | c: | \dir\file.txt | c:\path\dir\file.txt |
Works nicely. The code still uses the Path.Combine() method but it ensures that it'll always be in a format that Path.Combine() expects.