2009-04-30 12 views
52

Tengo un manejador web ASP.Net que devuelve resultados de una consulta en formato JSONescape en C# para el consumo Javascript

public static String dt2JSON(DataTable dt) 
{ 
    String s = "{\"rows\":["; 
    if (dt.Rows.Count > 0) 
    { 
     foreach (DataRow dr in dt.Rows) 
     { 
      s += "{"; 
      for (int i = 0; i < dr.Table.Columns.Count; i++) 
      { 
       s += "\"" + dr.Table.Columns[i].ToString() + "\":\"" + dr[i].ToString() + "\","; 
      } 
      s = s.Remove(s.Length - 1, 1); 
      s += "},"; 
     } 
     s = s.Remove(s.Length - 1, 1); 
    } 
    s += "]}"; 
    return s; 
} 

El problema es que a veces los datos devueltos tiene cotizaciones en ella y que necesitaría a javascript-escape estos para que pueda ser creado correctamente en un objeto js. Necesito una forma de encontrar citas en mis datos (las citas no están disponibles todas las veces) y colocar un carácter "/" delante de ellos.

texto Ejemplo de respuesta (mal):

{"rows":[{"id":"ABC123","length":"5""}, 
{"id":"DEF456","length":"1.35""}, 
{"id":"HIJ789","length":"36.25""}]} 

que tendría que escapar de la "así que mi respuesta debería ser:

{"rows":[{"id":"ABC123","length":"5\""}, 
{"id":"DEF456","length":"1.35\""}, 
{"id":"HIJ789","length":"36.25\""}]} 

Además, soy bastante nuevo en C# (codificación general, en realidad) por lo que si alguna otra cosa en mi código es el tonto que me haga saber

Respuesta

0

¿por qué no simplemente hacer esto:.

string correctResponseText = wrongResponseText.Replace("\"", "\\\""); 
+0

+1 Niza hecho. –

+8

No maneja datos con otros caracteres especiales JS: barra invertida, línea nueva, retorno de carro. –

+1

No muy bien hecho - como David mencionó, esto no funcionará para muchos otros caracteres especiales. La respuesta de @Lone Coder a continuación es mejor. – zcrar70

0
string.Replace(<mystring>, @"\"", @"\\""); 
+0

No funciona: 'CS1056 Carácter inesperado '\' 'y 'CS1003 Error de sintaxis,', 'expected' – Sandro

-1

Bueno, para empezar, no necesita cotizaciones para las teclas.

{rows:[,]} is valid. 

and you could dt.Table.Columns[i].ToString().Replace("\","") 

Pero si desea conservar las comillas dobles, comilla simple funciona del mismo modo comillas dobles hacen en JS

De lo contrario se podría hacer

String.Format("{name: \"{0}\"}",Columns[i].ToString().Replace("\","")) 
6

Para escapar correctamente una cadena literal para Javascript, primero escapa de todos los caracteres de barra diagonal inversa, luego se escapa de las comillas (o apóstrofes si los usa como delimitadores de cadena).

Por lo tanto, lo que necesita es:

value.Replace("\\","\\\\").Replace("\"","\\\"") 

¿Qué más salta a mí es que está utilizando la concatenación de cadenas en un bucle. Esto es malo, ya que se escala muy pobremente. El operador + = no agrega caracteres al final de la cadena existente (ya que las cadenas son inmutables y nunca se pueden cambiar), en su lugar copia la cadena y los caracteres agregados a una nueva cadena. A medida que copie más y más datos cada vez, cada fila adicional duplica aproximadamente el tiempo de ejecución del método. Use un StringBuilder para construir la cadena en su lugar.

Utilice la propiedad ColumnName para obtener el nombre de una columna en lugar del método ToString. El método ToString devuelve el valor de propiedad Expression si está configurado, solo si no se establece devuelve la propiedad ColumnName.

public static String dt2JSON(DataTable dt) { 
    StringBuilder s = new StringBuilder("{\"rows\":["); 
    bool firstLine = true; 
    foreach (DataRow dr in dt.Rows) { 
     if (firstLine) { 
     firstLine = false; 
     } else { 
     s.Append(','); 
     } 
     s.Append('{'); 
     for (int i = 0; i < dr.Table.Columns.Count; i++) { 
     if (i > 0) { 
      s.Append(','); 
     } 
     string name = dt.Columns[i].ColumnName; 
     string value = dr[i].ToString(); 
     s.Append('"') 
      .Append(name.Replace("\\","\\\\").Replace("\"","\\\"")) 
      .Append("\":\"") 
      .Append(value.Replace("\\","\\\\").Replace("\"","\\\"")) 
      .Append('"'); 
     } 
     s.Append("}"); 
    } 
    s.Append("]}"); 
    return s.ToString(); 
} 
+0

Cómo decodificar? – MonsterMMORPG

+0

@MonsterMMORPG: No lo decodifica, lo analiza. El propósito de escapar es que el código se puede analizar correctamente Una vez que se analizan los datos, las cadenas vuelven a su forma original. – Guffa

34

Aquí es un método eficiente y robusto que he encontrado en http://www.west-wind.com/weblog/posts/114530.aspx

/// <summary> 
/// Encodes a string to be represented as a string literal. The format 
/// is essentially a JSON string. 
/// 
/// The string returned includes outer quotes 
/// Example Output: "Hello \"Rick\"!\r\nRock on" 
/// </summary> 
/// <param name="s"></param> 
/// <returns></returns> 
public static string EncodeJsString(string s) 
{ 
    StringBuilder sb = new StringBuilder(); 
    sb.Append("\""); 
    foreach (char c in s) 
    { 
     switch (c) 
     { 
      case '\"': 
       sb.Append("\\\""); 
       break; 
      case '\\': 
       sb.Append("\\\\"); 
       break; 
      case '\b': 
       sb.Append("\\b"); 
       break; 
      case '\f': 
       sb.Append("\\f"); 
       break; 
      case '\n': 
       sb.Append("\\n"); 
       break; 
      case '\r': 
       sb.Append("\\r"); 
       break; 
      case '\t': 
       sb.Append("\\t"); 
       break; 
      default: 
       int i = (int)c; 
       if (i < 32 || i > 127) 
       { 
        sb.AppendFormat("\\u{0:X04}", i); 
       } 
       else 
       { 
        sb.Append(c); 
       } 
       break; 
     } 
    } 
    sb.Append("\""); 

    return sb.ToString(); 
} 
+3

Usar un método como este es importante para evitar posibles ataques XSS que podrían ocurrir cuando se evalúa JSON. –

+1

Bien. Agregué una declaración de caso adicional a codificar comillas simples también. –

+1

No creo que las comillas simples deben codificarse entre comillas dobles –

11

Creo que debería más bien mirar a la clase JavaScriptSerializer. Es mucho más estable y manejará correctamente cualquier tipo de datos o caracteres de escape, etc. Además, su código se verá mucho más limpio.

En el caso de que su clase puede tener este aspecto:

public static String dt2JSON(DataTable dt) { 
    var rows = new List<Object>(); 
    foreach(DataRow row in dt.Rows) 
    { 
     var rowData = new Dictionary<string, object>(); 
     foreach(DataColumn col in dt.Columns) 
      rowData[col.ColumnName] = row[col]; 
     rows.Add(rowData); 
    } 
    var js = new JavaScriptSerializer(); 
    return js.Serialize(new { rows = rows }); 
} 

Este método devolverá una cadena JSON serializado correctamente ... Por ejemplo, algo como esto:

{"rows":[{"id":1,"name":"hello"},{"id":2,"name":"bye"}]} 

Que se diviertan! :)

140

para .NET 4.0 + no es estándar HttpUtility.JavaScriptStringEncode

Para la solución viento del oeste anteriormente descrito por Lone Coder es bastante agradable

+5

esto me acaba de ayudar;) gracias –

+0

La mejor respuesta, gracias –

+0

Estaba trabajando en el software usando Uri.EscapeDataString que causó problemas cuando las comillas estaban en la cadena. Cambiar a HttpUtility.JavaScriptStringEncode fue la solución correcta. Ellos encubrieron los personajes de manera diferente. EscapeDataString ->% 25, ​​JavaScriptStringEncode -> \\ ".... Actualización. Al final necesitaba ambas, es decir, Url.EscapeDataString (HttpUtility.JavaScriptStringEncode (str)) para obtener una API para aceptar las comillas (") y el porcentaje personaje. Puede haber una manera mejor, pero espero que este comentario ayude a alguien. – HockeyJ

0

Obras cuando necesito enviar cadena de C# para etiqueta html.

<buton onlick="alert('<<here>>')" /> 

HttpUtility.HtmlEncode 
Cuestiones relacionadas