ASP.NET Core 6 Web API混合返回JSON的问题及修复方案咨询
ASP.NET Core 6 Web API混合返回JSON字符串与C#对象的问题修复方案
问题描述
开发ASP.NET Core 6 Web API控制器时,尝试在接口中同时返回JSON字符串与普通C#对象,遇到两个问题:
- JObject类型字段值丢失;
- 字符串类型的JSON数据被自动编码,无法直接作为JSON结构使用。
复现代码
[HttpGet("GetMixedJson")] public IActionResult GetMixedJson() { string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; string json = JsonConvert.SerializeObject(Summaries, Formatting.Indented); JObject jsonObject = new JObject(); jsonObject["thisFiledValueWillBeMissing"] = "JObject won't serialize :("; var resultObject = new { PlainCSharpFiled = "plain c# fields showing fine", jsonObject = jsonObject, TunneledJsonString = json }; return new JsonResult(resultObject); }
错误返回结果
{ "plainCSharpFiled": "plain c# fields showing fine", "jsonObject": { "thisFiledValueWillBeMissing": [] }, "tunneledJsonString": "[\n \"Freezing\",\n \"Bracing\",\n \"Chilly\",\n \"Cool\",\n \"Mild\",\n \"Warm\",\n \"Balmy\",\n \"Hot\",\n \"Sweltering\",\n \"Scorching\"\n]" }
问题原因
- JObject是Newtonsoft.Json的类型,而ASP.NET Core默认使用System.Text.Json序列化,两者兼容性不足,导致JObject字段被错误解析为空数组;
- 直接返回预序列化的JSON字符串时,System.Text.Json会将其视为普通字符串进行转义编码,无法保留原生JSON结构。
修复方案
方案一:统一使用Newtonsoft.Json序列化(推荐,低内存开销)
替换ASP.NET Core默认序列化器为Newtonsoft.Json,完美兼容JObject,同时避免重复序列化操作,降低内存占用。
- 安装NuGet包:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
- 在Program.cs中配置服务:
builder.Services.AddControllers().AddNewtonsoftJson();
- 修改控制器方法:
[HttpGet("GetMixedJson")] public IActionResult GetMixedJson() { string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; // 直接转换为JArray,避免先序列化字符串再解析,节省内存 JArray jsonArray = JArray.FromObject(Summaries); JObject jsonObject = new JObject(); jsonObject["thisFiledValueWillBeMissing"] = "JObject will serialize correctly :)"; var resultObject = new { PlainCSharpFiled = "plain c# fields showing fine", JsonObject = jsonObject, TunneledJson = jsonArray }; return new JsonResult(resultObject); }
如果必须使用已有的JSON字符串,可解析为JToken再加入结果:
string json = JsonConvert.SerializeObject(Summaries, Formatting.Indented); JToken jsonToken = JToken.Parse(json);
方案二:使用System.Text.Json的JsonElement替代JObject(无需切换序列化库)
保留默认System.Text.Json序列化器,用JsonElement处理动态JSON结构:
[HttpGet("GetMixedJson")] public IActionResult GetMixedJson() { string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; // 将数组序列化为JsonElement,避免字符串编码 using var doc = JsonDocument.Parse(JsonSerializer.Serialize(Summaries)); JsonElement jsonElement = doc.RootElement.Clone(); // 构建动态JSON对象 var jsonObject = new Dictionary<string, object> { ["thisFiledValueWillBeMissing"] = "JsonElement works correctly" }; var resultObject = new { PlainCSharpFiled = "plain c# fields showing fine", JsonObject = jsonObject, TunneledJson = jsonElement }; return new JsonResult(resultObject); }
方案三:直接写入响应流(最低内存开销,适合大数据量)
跳过中间对象构建,直接将JSON内容写入响应流,避免内存中生成完整JSON对象:
[HttpGet("GetMixedJson")] public async Task GetMixedJson() { string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; Response.ContentType = "application/json"; await using var writer = new Utf8JsonWriter(Response.Body); writer.WriteStartObject(); // 写入普通C#字段 writer.WriteString("PlainCSharpFiled", "plain c# fields showing fine"); // 写入动态JSON对象 writer.WriteStartObject("JsonObject"); writer.WriteString("thisFiledValueWillBeMissing", "Direct writing works"); writer.WriteEndObject(); // 直接写入数组,避免预序列化 writer.WriteStartArray("TunneledJson"); foreach (var summary in Summaries) { writer.WriteStringValue(summary); } writer.WriteEndArray(); writer.WriteEndObject(); await writer.FlushAsync(); }
内容的提问来源于stack exchange,提问作者Allan Xu
相关产品推荐
相关产品推荐

