Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于javascript消费的C#转义引号_C#_Escaping - Fatal编程技术网

用于javascript消费的C#转义引号

用于javascript消费的C#转义引号,c#,escaping,C#,Escaping,我有一个ASP.NETWeb处理程序,它以JSON格式返回查询结果 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 <

我有一个ASP.NETWeb处理程序,它以JSON格式返回查询结果

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;
}
我需要避开“所以我的回答应该是:

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

另外,我对C#(一般来说真的是编码)非常陌生,所以如果我的代码中有其他东西看起来很愚蠢,请告诉我。

为什么不这样做:

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

好吧,对于初学者来说,键周围不需要引号

{rows:[,]} is valid.

and you could dt.Table.Columns[i].ToString().Replace("\","")
但是如果您想保留双引号,单引号的工作原理与JS中双引号的工作原理相同

否则你可以

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

要正确转义Javascript的字符串文字,首先要转义所有反斜杠字符,然后转义引号(或撇号,如果将它们用作字符串分隔符)

因此,您需要的是:

value.Replace("\\","\\\\").Replace("\"","\\\"")
我还想知道的是,您正在循环中使用字符串连接。这很糟糕,因为它的伸缩性非常差。+=运算符不会在现有字符串的末尾添加字符(因为字符串是不可变的,永远无法更改),而是将字符串和添加的字符复制到新字符串中。当您每次复制越来越多的数据时,每增加一行都会使方法的执行时间大约翻倍。请改用StringBuilder来生成字符串

使用
ColumnName
属性来获取列的名称,而不是
ToString
方法。如果设置了
ToString
方法,则返回
表达式
属性值,只有未设置时,才返回
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();
}
公共静态字符串dt2JSON(数据表dt){
StringBuilder s=新的StringBuilder(“{\”行\“:[”);
bool firstLine=true;
foreach(数据行dr在dt.行中){
如果(第一线){
firstLine=false;
}否则{
s、 附加(',');
}
s、 附加('{');
for(int i=0;i0){
s、 附加(',');
}
string name=dt.Columns[i].ColumnName;
字符串值=dr[i].ToString();
s、 追加(“”)
.Append(name.Replace(“\\”,“\\\”)。Replace(“\\”,“\\\”))
.Append(“\”:\”)
.Append(value.Replace(“\\”,“\\\”)。Replace(“\\”,“\\\”))
.Append(“”);
}
s、 附加(“}”);
}
s、 附加(“]}”);
返回s.ToString();
}

这是我在

//
///对要表示为字符串文字的字符串进行编码
///本质上是一个JSON字符串。
/// 
///返回的字符串包含外部引号
///示例输出:“你好\“瑞克\”\r\n锁定“打开”
/// 
/// 
/// 
公共静态字符串EncodeJsString(字符串s)
{
StringBuilder sb=新的StringBuilder();
某人加上“\”;
foreach(字符c在s中)
{
开关(c)
{
案例“\”:
某人附加(“\\\”);
打破
案例“\\”:
某人加上“\\\”;
打破
案例'\b':
sb.附加(\\b”);
打破
案例'\f':
某人附加(\\f);
打破
案例“\n”:
某人附加(\\n);
打破
案例'\r':
某人附加(\\r);
打破
案例'\t':
某人附加(\\t);
打破
违约:
int i=(int)c;
如果(i<32 | i>127)
{
sb.AppendFormat(“\\u{0:X04}”,i);
}
其他的
{
sb.附加(c);
}
打破
}
}
某人加上“\”;
使某人返回字符串();
}

我认为您应该看看JavaScriptSerializer类。它更稳定,可以正确处理任何类型的数据或转义字符等。而且,您的代码看起来更干净

在您的情况下,您的类可以如下所示:

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 });
}
{"rows":[{"id":1,"name":"hello"},{"id":2,"name":"bye"}]}

玩得开心!:)

对于.NET4.0+来说,有一个标准
HttpUtility.JavaScriptStringEncode


对于早期的west wind,由Lone Coder描述的解决方案非常好

在我需要将字符串从C#发送到html标记时起作用

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

HttpUtility.HtmlEncode

HttpUtility.HtmlEncode

以下是@Bryan Legend对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();
        }}));
公共静态字符串编码JavaScriptString(字符串s)
=>string.Concat(s.Select(c=>{
开关(c)
{
大小写“\”:返回“\ \”;
大小写“\\”:返回“\\\”;
大小写“\b”:返回“\\b”;
大小写“\f”:返回“\\f”;
大小写“\n”:返回“\\n”;
大小写“\r”:返回“\\r”;
大小写“\t”:返回“\\t”;
默认值:返回(c<32 | | c>127)和&!char.isleterordigit(c)?$“\\u{(int)c:X04}”:c.ToString();
}}));

更改日志:

  • 删除双引号包装,因为我在js中这样做
  • 使用表达式体
  • 使用清洁开关
  • 使用Linq
  • 添加字母检查以允许
    é

使用这样的方法对于避免JSON求值时可能发生的XSS攻击非常重要。Nice。我确实添加了一个额外的case语句来编码单引号。我不认为单引号需要在双引号中编码。如果您愿意,这里是这个答案的Linq修改:不使用其他特殊的JS字符:反斜杠、换行符、回车符。做得不太好-正如David提到的,这对许多其他特殊字符都不起作用。@下面是Lone Coder的答案更好。如果JS中使用的字符串来自用户,这种方法是危险的。它会让您有机会,例如
,如果字符串被写入页面脚本,则会关闭字符串和脚本标记,后跟注入器想要执行的任何操作。@MonsterMMORPG:您不解码它,而是解析它。浦
{"rows":[{"id":1,"name":"hello"},{"id":2,"name":"bye"}]}
<buton onlick="alert('<< here >>')" />

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