ASP.NET Core 3迁移:System.Text.Json是否有JRaw等效替代方案?
解决ASP.NET Core 3中System.Text.Json替代Newtonsoft.Json JRaw的方案
我之前在迁移ASP.NET Core 2到3.x的项目时,刚好遇到过和你一模一样的问题——原来用Newtonsoft.Json的JRaw可以直接输出预格式化的JSON字符串,不用转义,但System.Text.Json不兼容JRaw,而且用JsonElement会额外做反序列化+序列化的操作,对大数据场景不友好。下面给你两种高效的解决方案,完全避免不必要的JSON解析:
方法一:自定义RawJson标记类+JsonConverter(推荐)
这个方案和JRaw的思路完全一致,通过自定义一个标记类来标识哪些属性是原始JSON,然后写对应的Converter直接把字符串写入输出流,不做任何解析:
1. 定义RawJsonString标记类
public class RawJsonString { public string Value { get; } public RawJsonString(string value) { Value = value ?? throw new ArgumentNullException(nameof(value)); // 可选:可以在这里加一个JSON合法性校验,避免写入无效JSON // JsonDocument.Parse(value); } }
2. 实现对应的JsonConverter
public class RawJsonStringConverter : JsonConverter<RawJsonString> { // 如果不需要反序列化该属性,可以跳过Read方法的实现(或者抛出NotImplementedException) public override RawJsonString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var jsonDoc = JsonDocument.ParseValue(ref reader); return new RawJsonString(jsonDoc.RootElement.GetRawText()); } public override void Write(Utf8JsonWriter writer, RawJsonString value, JsonSerializerOptions options) { // 核心:直接写入原始JSON内容,不转义、不解析 writer.WriteRawValue(value.Value); } }
3. 修改你的Thing类并使用
public class Thing { public int Id { get; set; } public string Name { get; set; } // 给Data属性添加Converter标记 [JsonConverter(typeof(RawJsonStringConverter))] public RawJsonString Data { get; set; } } // 实例化和序列化 var thing = new Thing { Id = 1, Name = "Thing", Data = new RawJsonString("{\"key\":\"value\"}") }; var json = JsonSerializer.Serialize(thing); // 输出结果:{"Id":1,"Name":"Thing","Data":{"key":"value"}}
4. 全局注册(ASP.NET Core中)
如果你的项目中有很多地方需要用到这个功能,可以把Converter全局注册,不用每个属性都加标记:
services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new RawJsonStringConverter()); });
方法二:直接使用Utf8JsonWriter手动序列化(适合临时场景)
如果只是个别地方需要处理,不想自定义类和Converter,可以直接用Utf8JsonWriter手动控制序列化过程:
using var stream = new MemoryStream(); using var writer = new Utf8JsonWriter(stream); writer.WriteStartObject(); writer.WriteNumber("Id", thing.Id); writer.WriteString("Name", thing.Name); // 直接写入原始JSON writer.WritePropertyName("Data"); writer.WriteRawValue(thing.Data); writer.WriteEndObject(); writer.Flush(); var json = Encoding.UTF8.GetString(stream.ToArray());
为什么这个方案比JsonElement好?
- 使用自定义Converter时,完全跳过了JSON的解析和重新序列化步骤,直接把原始字符串写入输出流,性能和JRaw几乎一致,非常适合大数据场景;
- 而JsonElement需要先把字符串解析成DOM对象,序列化的时候再转成JSON,会额外消耗CPU和内存,数据越大差异越明显。
内容的提问来源于stack exchange,提问作者Jarru
相关产品推荐
相关产品推荐

