Come ottenere Uri.EscapeDataString per conformarsi a RFC 3986

La class Uri ha come valore predefinito RFC 2396. Per OpenID e OAuth, ho bisogno di Uri che scappi coerentemente con RFC 3986.

Dalla documentazione della class System.Uri :

Per impostazione predefinita, qualsiasi carattere riservato nell’URI viene scappato secondo la RFC 2396. Questo comportamento cambia se gli identificatori di risorse internazionali o l’analisi del nome di dominio internazionale sono abilitati, nel qual caso i caratteri riservati nell’URI vengono sfuggiti in conformità con RFC 3986 e RFC 3987.

La documentazione afferma anche che l’triggerszione di questa modalità IRI e quindi il comportamento di RFC 3986 significa aggiungere un elemento di sezione uri a machine.config e questo al file app / web.config:

      

Ma se questo è presente nel file .config o no, sto ottenendo lo stesso comportamento di escape (non-3986) per un’app .NET 3.5 SP1. Cos’altro devo fare per far Uri.EscapeDataString che Uri.EscapeDataString usi le regole RFC 3986? (in particolare, per evitare i caratteri riservati come definiti in quella RFC)

Non essendo stato in grado di far sì che Uri.EscapeDataString assumesse il comportamento di RFC 3986, ho scritto il mio metodo di escaping conforms a RFC 3986. Sfrutta Uri.EscapeDataString e quindi “aggiorna” l’escaping alla conformità RFC 3986.

 ///  /// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986. ///  private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" }; ///  /// Escapes a string according to the URI data string rules given in RFC 3986. ///  /// The value to escape. /// The escaped value. ///  /// The  method is supposed to take on /// RFC 3986 behavior if certain elements are present in a .config file. Even if this /// actually worked (which in my experiments it doesn't), we can't rely on every /// host actually having this configuration element present. ///  internal static string EscapeUriDataStringRfc3986(string value) { // Start with RFC 2396 escaping by calling the .NET method to do the work. // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation). // If it does, the escaping we do that follows it will be a no-op since the // characters we search for to replace can't possibly exist in the string. StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value)); // Upgrade the escaping to RFC 3986, if necessary. for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) { escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0])); } // Return the fully-RFC3986-escaped string. return escaped.ToString(); } 

In realtà questo è stato corretto in .NET 4.5 per funzionare, vedi qui .

Ho appena creato una nuova libreria chiamata PUrify (dopo aver eseguito questo problema) che gestirà il funzionamento di .NET pre 4.5 (funziona per 3.5) e Mono attraverso una variazione dell’approccio in questo post . PUrify non cambia EscapeDataString ma ti permette di avere Uris con caratteri riservati che non saranno sfuggiti.

Quale versione del framework stai usando? Sembra che molte di queste modifiche siano state apportate nel timeframe ( da MSDN ) “.NET Framework 3.5. 3.0 SP1 e 2.0 SP1”.

Non sono riuscito a trovare una risposta migliore (struttura al 100% o reimplementazione al 100%), quindi ho creato questo abominio. Sembra funzionare con OAuth.

 class al_RFC3986 { public static string Encode(string s) { StringBuilder sb = new StringBuilder(s.Length*2);//VERY rough estimate byte[] arr = Encoding.UTF8.GetBytes(s); for (int i = 0; i < arr.Length; i++) { byte c = arr[i]; if(c >= 0x41 && c <=0x5A)//alpha sb.Append((char)c); else if(c >= 0x61 && c <=0x7A)//ALPHA sb.Append((char)c); else if(c >= 0x30 && c <=0x39)//123456789 sb.Append((char)c); else if (c == '-' || c == '.' || c == '_' || c == '~') sb.Append((char)c); else { sb.Append('%'); sb.Append(Convert.ToString(c, 16).ToUpper()); } } return sb.ToString(); } } 

Mi rendo conto che questa domanda e le risposte hanno alcuni anni, ma ho pensato di condividere le mie scoperte quando ho avuto problemi a ottenere la conformità con .Net 4.5 .

Se il tuo codice è in esecuzione su asp.net, semplicemente impostando il progetto su target 4.5 ed eseguendo su una macchina con 4.5 o versioni successive, potresti comunque ottenere il comportamento 4.0. È necessario assicurarsi che sia impostato in web.config.

Da questo articolo del blog su msdn ,

Se non esiste alcun attributo presente in Web.config, si assume che l’applicazione volesse un comportamento di quirk 4.0.