2010-05-27 13 views
68

Estoy tratando de pasar el resultado de una excepción de SQL Server al cliente utilizando el método RegisterStartUpScript de MS ScriptManager en .NET 3.5. Esto funciona bien para algunos errores, pero cuando la excepción contiene comillas simples, la alerta falla.¿Hay una forma estándar de codificar una cadena .NET en una cadena de JavaScript para usar en MS Ajax?

No quiero escapar solo entre comillas simples. ¿Existe una función estándar a la que pueda llamar para escapar de cualquier carácter especial para usar en JavaScript?

string scriptstring = "alert('" + ex.Message + "');";   
ScriptManager.RegisterStartupScript(this, this.GetType(), "Alert", scriptstring , true); 

EDITAR:

Gracias @tpeczek, el código casi trabajó para mí :) pero con una ligera modificación (el escape de comillas simples) funciona un convite.

He incluido mi versión modificada aquí ...

public class JSEncode 
{ 
    /// <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 '\\': 
        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(); 
    } 
} 

Como se menciona más adelante - fuente original: here

Respuesta

9

Un problema tomando con esta función es que no codifica caracteres que son típicamente fuera de banda encapsulando HTML ... por lo que tendría problemas si intentara incluir una cadena con " dentro de un valor de atributo, o si tenía una cadena con la secuencia </script> dentro de un elemento de script. Eso podría llevar a la inyección de scripts y XSS.

Se podría añadir:

  case '<': 
       sb.Append("\\x3C"); 
       break; 
      case '"': 
       sb.Append("\\x22"); 
       break; 
      case '&': 
       sb.Append("\\x26"); 
       break; 

En general, probablemente sería mejor utilizar un codificador JSON estándar de elaborar cerveza su propia cadena JS codificador literal. Esto le permitirá pasar cualquier tipo de datos simple a JS en lugar de solo cadenas.

En .NET 3.5 se obtiene JavaScriptSerializer, sin embargo tenga en cuenta que, si bien este hace codificar < a \u003C (lo que la salida será adecuado para su uso en un elemento <script>), que no se codificar & o ", por lo tanto, se necesitaría escaparse de HTML para incluir dicho contenido en un valor de atributo y se necesitaría un contenedor de CDATA para los elementos de guión XHTML.

(Al igual que muchos codificadores JSON, tampoco codifica los caracteres U + 2028 LINE SEPARATOR y U + 2029 PARAGRAPH SEPARATOR. El código anterior sí lo hace, debido a que se escapan todos los caracteres que no son ASCII. 'errores literales' cuando estos caracteres están incluidos en un literal de cadena JS, porque JavaScript los trata inofensivamente igual que una línea nueva ASCII.)

+1

Great write-up. Tenga en cuenta que 'JavaScriptSerializer' también está disponible en .NET 2 a través de la versión fuera de banda ASP.NET AJAX 1.0 (http://www.microsoft.com/downloads/es/details.aspx?FamilyID=ca9d90fa-e8c9- 42e3-aa19-08e2c027f5d6 & displaylang = en). – bdukes

+0

En ese caso, ¿no usaría 'HttpUtility.HtmlAttributeEncode (HttpUtility.JavaScriptStringEncode (unencodedString))' o 'HttpUtility.HtmlEncode (HttpUtility.JavaScriptStringEncode (unencodedString))' dependiendo del contexto? –

+0

@MartinBrown: puede usar cualquiera de esos para inyectar en el atributo JS-in-HTML, sí (aunque generalmente es una mala idea hacerlo). Los métodos 'HtmlEncode' y' HtmlAttributeEncode' son curiosamente nombrados; parece que uno debería funcionar mejor para los valores de los atributos y uno debería funcionar mejor para el contenido de texto, pero no existe tal distinción en la práctica a juzgar por la fuente de referencia. Son solo dos codificadores HTML implementados arbitrariamente de forma diferente. – bobince

163

¿Has echado un vistazo a HttpUtility.JavaScriptStringEncode?

+9

Upvoted porque es una gran respuesta, solo funciona en .NET 4 aunque –

+5

Creo que cuando hay una función de marco para una tarea específica (como esta) a menudo es más confiable y precisa que la del bricolaje, entonces es mejor seguir con eso ... – Luke

+0

¿Hay una solución como esa en 3.5? –

Cuestiones relacionadas