ASP.NET中JsonResult序列化单条DataTable数据返回数组问题
问题原因
DataTable本身是多行数据的集合容器,序列化逻辑默认会遍历所有行生成JSON数组,哪怕表中只存在1条记录,最终输出也会带外层方括号,和你实际观察到的返回结果一致。
另外你当前代码中直接拼接用户传入的id到SQL语句的写法存在严重SQL注入风险,建议调整为参数化查询。
实现方案
你可以选以下任意一种方式修改,最终都会返回不带外层数组的单个JSON对象。
方案1:最小改动,从现有DataTable中提取首行返回
不需要调整现有查库逻辑,只需要在返回前提取DataTable的第一行数据,转成独立对象序列化即可,同时可以补充空结果判断:
把你原先代码里的return new JsonResult(table);替换成以下逻辑:
// 无匹配数据时返回404 if (table.Rows.Count == 0) { return NotFound(); } // 提取第一行数据转成匿名对象 DataRow firstRow = table.Rows[0]; var result = new { id = (int)firstRow["id"], number = (int)firstRow["number"], name = firstRow["name"].ToString(), lastName = firstRow["lastName"].ToString() }; return new JsonResult(result);
修改后返回结果格式就是你期望的:
{"id":4,"number":10,"name":"Peter","lastName":"Peterson"}
方案2:更规范的实现(推荐)
抛弃DataTable中转的写法,直接定义用户实体类,用参数化查询读取单条记录,从根源上避免数组序列化问题和SQL注入风险:
- 先定义对应实体类
public class User { public int Id { get; set; } public int Number { get; set; } public string Name { get; set; } public string LastName { get; set; } }
- 修改接口实现为以下逻辑
[HttpGet("{id:int}")] public async Task<IActionResult> GetUser(int id) { string sqlDataSource = _configuration.GetConnectionString("UsersDb"); User? targetUser = null; using (SqlConnection conn = new SqlConnection(sqlDataSource)) { await conn.OpenAsync(); // 用参数化写法替代字符串拼接,杜绝SQL注入 string query = "select id,number,name,lastName from dbo.Users where id=@UserId"; using (SqlCommand cmd = new SqlCommand(query, conn)) { cmd.Parameters.AddWithValue("@UserId", id); using (var reader = await cmd.ExecuteReaderAsync()) { if (await reader.ReadAsync()) { targetUser = new User { Id = reader.GetInt32(0), Number = reader.GetInt32(1), Name = reader.GetString(2), LastName = reader.GetString(3) }; } } } } // 无匹配结果返回404状态码 if (targetUser == null) return NotFound(); return new JsonResult(targetUser); }
这个方案的优势:
- 不存在多余的数组包裹问题,直接序列化单个实体对象
- 参数化查询彻底避免SQL注入漏洞
- 省去DataTable加载全表数据的内存开销,性能更好
- 状态码返回符合REST API设计规范,调用方更容易处理异常场景
内容的提问来源于stack exchange,提问作者Norex
相关产品推荐
相关产品推荐

