Escape Quote in C# for javascript consumption

C#Escaping

C# Problem Overview


I have a ASP.Net web handler that returns results of a query in JSON format

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

The problem is that sometimes the data returned has quotes in it and I would need to javascript-escape these so that it can be properly created into a js object. I need a way to find quotes in my data (quotes aren't there every time) and place a "/" character in front of them.

Example response text (wrong):

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

I would need to escape the " so my response should be:

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

Also, I'm pretty new to C# (coding in general really) so if something else in my code looks silly let me know.

C# Solutions


Solution 1 - C#

For .net 4.0 + there is standard HttpUtility.JavaScriptStringEncode

For earlier west wind solution described by Lone Coder is quite nice

Solution 2 - C#

Here is an efficient and robust method that I found at 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();
}

Solution 3 - C#

I think you should rather look at the JavaScriptSerializer class. It's a lot more stable, and will correctly handle any kind of data or escape characters etc. Also, your code will look a lot cleaner.

In your case your class can look like this:

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

This method will return a correctly serialized json string... For example, sth like this:

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

Have fun! :)

Solution 4 - C#

To correctly escape a string literal for Javascript, you first escape all backslash characters, then you escape the quotation marks (or apostrophes if you use them as string delimiters).

So, what you need is:

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

What else jumps out to me is that you are using string concatenation in a loop. This is bad, as it scales very poorly. The += operator does not add characters at the end of the existing string (as strings are immutable and can never be changed), instead it copies the string and the added characters to a new string. As you copy more and more data each time, eEvery additional row roughly doubles the execution time of the method. Use a StringBuilder to build the string instead.

Use the ColumnName property to get the name of a column rather than the ToString method. The ToString method returns the Expression property value if it's set, only if that is not set does it return the ColumnName property.

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

Solution 5 - C#

Here is a rework of @Bryan Legend's answer with Linq:

public static string EncodeJavaScriptString(string s)
	=> string.Concat(s.Select(c => {
		switch (c)
		{
			case '\"': return "\\\"";
			case '\\': return "\\\\";
			case '\b': return "\\b";
			case '\f': return "\\f";
			case '\n': return "\\n";
			case '\r': return "\\r";
			case '\t': return "\\t";
			default: return (c < 32 || c > 127) && !char.IsLetterOrDigit(c) ? $"\\u{(int)c:X04}" : c.ToString();
		}}));

Try it Online!

changelog:

  • Remove double quoting wrapping since I do it in the js
  • Use expression body
  • Use a cleaner switch
  • Use Linq
  • Add a check for Letter to allow é

Solution 6 - C#

Why don't you just do this:

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

Solution 7 - C#

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

Solution 8 - C#

Works when i need send string from C# to html tag.

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

HttpUtility.HtmlEncode

Solution 9 - C#

Well, for starters you do not need quotes around the keys.

{rows:[,]} is valid.

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

But if you want to retain the double quotes, single quote works the same way double quotes do in JS

Otherwise you could do

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasonView Question on Stackoverflow
Solution 1 - C#Yauhen.FView Answer on Stackoverflow
Solution 2 - C#Bryan LegendView Answer on Stackoverflow
Solution 3 - C#Artiom ChilaruView Answer on Stackoverflow
Solution 4 - C#GuffaView Answer on Stackoverflow
Solution 5 - C#aloisdgView Answer on Stackoverflow
Solution 6 - C#KonView Answer on Stackoverflow
Solution 7 - C#KirtanView Answer on Stackoverflow
Solution 8 - C#Sergio CabralView Answer on Stackoverflow
Solution 9 - C#Chad GrantView Answer on Stackoverflow