1

In the comments to this question it was noted that it was not always possible to convert a file path to the URI string by means of System.Uri class. This leaves a question: how can one represent an arbitrary file path as System.Uri?

Here are some details. If an app is targeting .Net version below 4.5, than the System.Uri constructors do not try to unescape the original string, even if .Net 4.5+ is installed. So the question relates to the code targeting .Net 4.5+. In those later versions, any method of creating a System.Uri instance from a string ends up in some messy internal code trying to "escape-unescape" the input. The result is that '%25' is never unescaped, but '%' followed by two hexadecimal digits coding any non-special ASCII character is always unescaped. For example,

var uri = new System.Uri(@"C:\%51.txt");

gives a uri with uri.LocalPath == @"C:\Q.txt", and

var uri = new System.Uri(@"C:\%2551.txt");

creates a uri with uri.LocalPath == @"C:\%2551.txt".

At first glance, it seems to be impossible to convert pretty valid local file name '%51.txt' to an equivalent System.Uri. But maybe someone knows a way?

Serge N
  • 96
  • 1
  • 7
  • `new Uri("file:///" + Convert.ToBase64String(Encoding.UTF8.GetBytes(@"C:\%51.txt")))`. I'm only half kidding. The only problem being, of course, that nobody but you can get a path back from that again. But you absolutely, positively, avoid all escaping issues whatsoever. – Jeroen Mostert Oct 09 '17 at 10:59
  • That's why I mentioned an equivalent System.Uri, i.e. URI representing the same path in the standard way. – Serge N Oct 10 '17 at 18:02
  • Equivalence merely implies a one-to-one mapping, which is easy to establish under your own scheme. If you just want better escaping than what the framework gives you, the question you linked to actually has [an answer](https://stackoverflow.com/a/35734486/4137916). I'm not sure why that wouldn't suffice. The important question seems to be what the intended consumer of the URI is. If you have to conform to some software's idea of how paths are to be escaped, use that, and code it yourself if you have to. Otherwise, there's no reason to even use the bad thing that is the `file://` scheme at all. – Jeroen Mostert Oct 10 '17 at 18:42
  • Well, I'll try to explain more carefully. There is a file C:\%51.txt. There is a class System.Uri that has a property LocalPath, which gets an unescaped local operating-system representation of a file name, according to MSDN. The task is to create an instance of System.Uri with LocalPath equal to @"C:\%51.txt". – Serge N Oct 10 '17 at 22:44
  • 1
    `new Uri(@"file:///C:/%2551.txt")` will accomplish exactly that (`new Uri(@"file:///C:/%252551.txt")` for the other case). `System.Uri` just won't do the escaping for you and it can't roundtrip, but it can represent it. – Jeroen Mostert Oct 11 '17 at 06:22
  • Thanks, this works as needed. Strangely, I have not tried what seemed obvious as an afterthought. – Serge N Oct 11 '17 at 22:38

1 Answers1

0

Adopting this comment as the answer. Pre-built URI string should be used as a parameter for System.Uri constructor instead of original local path to avoid conversion problems, e.g. new Uri("file:///C:%2551.txt") for the path "%51.txt".

Serge N
  • 96
  • 1
  • 7