2009-04-30 12 views
52

Mam obsługi ASP.NET sieci Web, która zwraca wyniki kwerendy w formacie JSONUcieczka Cytat w C# do spożycia 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; 
} 

Problem polega na tym, że czasami dane zwracane ma w nim cytaty i musiałbym do javascript-uciec z nich, aby można było poprawnie utworzyć obiekt js. Potrzebuję sposobu, aby znaleźć cytaty w moich danych (cytaty nie są za każdym razem) i umieścić przed nimi znak "/".

tekst Przykład odpowiedzi (źle):

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

musiałbym uciec ", więc moja odpowiedź powinna być:

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

Ponadto, jestem całkiem nowy, C# (kodowanie w ogólnie naprawdę) więc jeśli coś innego w moim kodzie wygląda głupio, daj mi znać:

Odpowiedz

0

Po prostu nie rób tego:

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

+1 Ładnie wykonane. –

+8

Nie obsługuje danych z innymi specjalnymi znakami JS: odwrotny ukośnik, nowa linia, powrót karetki. –

+1

Naprawdę nie tak ładnie wykonane - jak David wspomniał, to nie zadziała dla wielu innych znaków specjalnych. Odpowiedź @Lone Coder poniżej jest lepsza. – zcrar70

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

Nie działa:' CS1056 Nieoczekiwany znak '\' i 'CS1003 Błąd składniowy, ',' oczekiwano' – Sandro

-1

Cóż, na początek nie potrzebujesz cytatów wokół klawiszy.

{rows:[,]} is valid. 

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

Ale jeśli chcesz zachować cudzysłów, apostrof działa w ten sam sposób cudzysłowy zrobić w JS

przeciwnym razie można zrobić

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

Aby poprawnie ucieczki ciąg dosłownego dla JavaScript, najpierw unikasz wszystkich znaków ukośnika, a następnie unikasz cudzysłowów (lub apostrofów, jeśli używasz ich jako ograniczników ciągów znaków).

Więc, czego potrzebujesz to:

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

Co innego wyskakuje mi to, że używasz ciąg konkatenacji w pętli. Jest to złe, ponieważ skaluje się bardzo słabo. Operator + = nie dodaje znaków na końcu istniejącego łańcucha (ponieważ ciągi są niezmienne i nie można ich zmienić), zamiast tego kopiuje ciąg znaków i dodane znaki do nowego ciągu. Podczas kopiowania coraz więcej danych za każdym razem, każdy dodatkowy wiersz z grubsza podwaja czas wykonania metody. Zamiast tego użyj StringBuilder, aby zbudować ciąg.

Użyj właściwości ColumnName, aby uzyskać nazwę kolumny zamiast metody ToString. Metoda ToString zwraca wartość właściwości Expression, jeśli jest ustawiona, tylko jeśli nie jest ona ustawiona, zwraca właściwość 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

Jak rozszyfrować? – MonsterMMORPG

+0

@MonsterMMORPG: Nie dekodujesz go, lecz go analizujesz, a celem jego usunięcia jest prawidłowe przetworzenie kodu Gdy dane są analizowane, łańcuchy powracają do swojej pierwotnej postaci – Guffa

34

Oto skuteczny i solidny sposób, że znalazłem w 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

Używanie takiej metody jest ważne, aby uniknąć możliwych ataków XSS, które mogłyby się zdarzyć, gdy JSON zostanie wykryty –

+1

Dobrze. Dodałem dodatkowe kodują również pojedyncze cudzysłowy –

+1

Nie sądzę, aby pojedyncze cudzysłowy wymagały zakodowania w podwójnych cudzysłowach –

11

myślę, że należy raczej szukać w klasie JavaScriptSerializer. Jest o wiele bardziej stabilny i poprawnie obsługuje wszelkiego rodzaju dane lub znaki ucieczki itp. Twój kod będzie wyglądał dużo czystszy.

W twoim przypadku klasa może wyglądać następująco:

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 }); 
} 

Ta metoda zwróci poprawnie zserializowaną json ciąg ... Na przykład czegoś takiego:

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

Miłej zabawy! :)

140

dla .NET 4.0 + jest standardem HttpUtility.JavaScriptStringEncode

Dla wcześniejszego rozwiązania West Wind opisanej przez Lone Coder jest całkiem ładny

+5

to właśnie mi pomogło;) dziękuję –

+0

Najlepsza odpowiedź, dziękuję –

+0

Pracowałem nad oprogramowaniem wykorzystującym Uri.EscapeDataString, które powodowało problemy, gdy w łańcuchu były cytaty. Zmiana na HttpUtility.JavaScriptStringEncode było właściwym rozwiązaniem. One inaczej ukrywają postacie. EscapeDataString ->% 25, ​​JavaScriptStringEncode -> \\ ".... Aktualizacja. W końcu potrzebowałem obu, tj. Url.EscapeDataString (HttpUtility.JavaScriptStringEncode (str)), aby uzyskać api do akceptowania cudzysłowów (") i procent postać. Może być lepszy sposób, ale mam nadzieję, że ten komentarz pomoże komuś. – HockeyJ

0

Works kiedy muszę wysłać ciąg z C# do tagu HTML.

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

HttpUtility.HtmlEncode