2011-07-14 69 views
25

Estoy usando framework compacto/C# en Windows Mobile.Uri.EscapeDataString() - URI no válido: la cadena Uri es demasiado larga

En mi aplicación, estoy cargando datos en el servidor serializando objetos y utilizando una solicitud HttpWebRequest/POST para enviar la información. En el servidor, los datos de la publicación se deserializan y se guardan en la base de datos.

El otro día me di cuenta de que tenía un problema con los caracteres especiales en los datos de la publicación (ampersands, etc.). Así que introduje Uri.EscapeDataString() en el método y todo estaba bien.

Sin embargo, hoy he descubierto que hay un problema cuando la aplicación intenta cargar una gran cantidad de datos (no estoy seguro de lo que denota exactamente "grande" en el momento!)

Código existente (tipo de)

var uploadData = new List<Things>(); 

uploadData.Add(new Thing() { Name = "Test 01" }); 
uploadData.Add(new Thing() { Name = "Test 02" }); 
uploadData.Add(new Thing() { Name = "Test with an & Ampersand " }); // Do this a lot!! 

var postData = "uploadData=" + Uri.EscapeDataString(JsonConvert.SerializeObject(uploadData, new IsoDateTimeConverter())); 

Problema

la llamada a Uri.EscapeDataString() está causando la siguiente excepción:

System.UriFormatException: URI no válido: la cadena Uri es demasiado larga.

Pregunta

¿Hay otras maneras de preparar los datos para la carga?

Por lo que puedo ver, HttpUtility (que tiene sus propios métodos Encode/Decode) no está disponible para el marco compacto.

+1

¿Podría escribir que es su propia implementación? 'EscapeDataString()' parece en su mayoría convincente ... hacer un 'String.Replace' normal basado en una biblioteca de caracteres que necesitan escaparse? – Smudge202

+0

Estados Msdn: UriFormatException: la longitud de stringToEscape supera 32766 caracteres. – fluent

+0

Como sugirió Smudge202, simplemente escribí mi propia implementación. – ETFairfax

Respuesta

30

O simplemente puede dividir su cadena y llamar al Uri.EscapeDataString(string) para cada bloque, con el fin de evitar la reimplementación de la función.

Código de ejemplo:

 String value = "large string to encode"; 
     int limit = 2000; 

     StringBuilder sb = new StringBuilder(); 
     int loops = value.Length/limit; 

     for (int i = 0; i <= loops; i++) 
     { 
      if (i < loops) 
      { 
       sb.Append(Uri.EscapeDataString(value.Substring(limit * i, limit))); 
      } 
      else 
      { 
       sb.Append(Uri.EscapeDataString(value.Substring(limit * i))); 
      } 
     } 
+4

el límite en .net 4.5 para EscapeDataString es de 65520 caracteres, por lo que podría usarse para reducir las iteraciones necesarias. –

+0

Cool. ¿Hay algún tipo de problema con Uri.Unescape? Parece que no, pero me pregunto por qué en el caso –

+0

@Knagis no estoy seguro de por qué mencionas el número de iteraciones aquí, ya que difícilmente puede ser una gran parte del tiempo de ejecución. Inicializar StringBuilder con el tamaño del valor. La longitud definitivamente parece un mejor impulso de rendimiento. –

1
StringBuilder stringBuilder = new StringBuilder(); 
for (int i = 0; i < originalString.Length; i++) 
{ 
    if ((originalString[i] >= 'a' && originalString[i] <= 'z') || 
     (originalString[i] >= 'A' && originalString[i] <= 'Z') || 
     (originalString[i] >= '0' && originalString[i] <= '9')) 
    { 
     stringBuilder.Append(originalString[i]); 
    } 
    else 
    { 
     stringBuilder.AppendFormat("%{0:X2}", (int)originalString[i]); 
    } 
} 

string result = stringBuilder.ToString(); 
1

He estado usando System.Web.HttpUtility.UrlEncode y parece manejar las cadenas más largas mucho mejor.

0

La respuesta de "Alberto de Paola" es buena.

Sin embargo, para desactivar el escapado de datos es un poco más complicado, porque debe evitar cortar la cadena codificada en el medio de un carácter codificado (o romperá la integridad de la cadena original).

Aquí es mi manera de solucionar este problema:

public static string EncodeString(string str) 
{ 
    //maxLengthAllowed .NET < 4.5 = 32765; 
    //maxLengthAllowed .NET >= 4.5 = 65519; 
    int maxLengthAllowed = 65519; 
    StringBuilder sb = new StringBuilder(); 
    int loops = str.Length/maxLengthAllowed; 

    for (int i = 0; i <= loops; i++) 
    { 
     sb.Append(Uri.EscapeDataString(i < loops 
      ? str.Substring(maxLengthAllowed * i, maxLengthAllowed) 
      : str.Substring(maxLengthAllowed * i))); 
    } 

    return sb.ToString(); 
} 

public static string DecodeString(string encodedString) 
{ 
    //maxLengthAllowed .NET < 4.5 = 32765; 
    //maxLengthAllowed .NET >= 4.5 = 65519; 
    int maxLengthAllowed = 65519; 

    int charsProcessed = 0; 
    StringBuilder sb = new StringBuilder(); 

    while (encodedString.Length > charsProcessed) 
    { 
     var stringToUnescape = encodedString.Substring(charsProcessed).Length > maxLengthAllowed 
      ? encodedString.Substring(charsProcessed, maxLengthAllowed) 
      : encodedString.Substring(charsProcessed); 

     // If the loop cut an encoded tag (%xx), we cut before the encoded char to not loose the entire char for decoding 
     var incorrectStrPos = stringToUnescape.Length == maxLengthAllowed ? stringToUnescape.IndexOf("%", stringToUnescape.Length - 4, StringComparison.InvariantCulture) : -1; 
     if (incorrectStrPos > -1) 
     { 
      stringToUnescape = encodedString.Substring(charsProcessed).Length > incorrectStrPos 
       ? encodedString.Substring(charsProcessed, incorrectStrPos) 
       : encodedString.Substring(charsProcessed); 
     } 

     sb.Append(Uri.UnescapeDataString(stringToUnescape)); 
     charsProcessed += stringToUnescape.Length; 
    } 

    var decodedString = sb.ToString(); 

    // ensure the string is sanitized here or throw exception if XSS/SQL Injection is found 
    SQLHelper.SecureString(decodedString); 
    return decodedString; 
} 

Para probar estas funciones:

var testString = "long string to encode"; 
var encodedString = EncodeString(testString); 
var decodedString = DecodeString(encodedString); 

Console.WriteLine(decodedString == testString ? "integrity respected" : "integrity broken"); 

Hope esto puede ayudar a evitar algunos dolores de cabeza;)

0

Uso System.Web.HttpUtility.UrlEncode (basado en this answer):

 value = HttpUtility.UrlEncode(value) 
      .Replace("!", "%21") 
      .Replace("(", "%28") 
      .Replace(")", "%29") 
      .Replace("*", "%2A") 
      .Replace("%7E", "~"); // undo escape 
Cuestiones relacionadas