dotnet 将一个 JSON 字符串嵌入到另一个对象且不被序列化

DotNetCore实战

共 5464字,需浏览 11分钟

 ·

2024-01-05 09:43

有时候我们会将一段 JSON 字符串存入数据库,以期在某个接口被调用时将其返回给客户端。这种返回一般不是原样返回:我们可能需要对结果包装一下,比如将数据包在 data 字段里同时提供 code 和 message 字段。

      
        {
      
      
          "code": 200,
      
      
          "message": "OK",
      
      
          "data": []
      
      
        }
      
    

很好办,只要设计一个带泛 型参数的 Result 即可:

      
        public class Result<TData>
      
      
        {
      
      
          public int Code { get; set; }
      
      
          public string Message { get; set; }
      
      
          public TData Data { get; set; }
      
      
        }
      
    

使用方法如下(用 Newtonsoft.Json 处理 JSON 数据):

      
        public class Article
      
      
        {
      
      
          public string Title { get; set; }
      
      
          public string Content { get; set; }
      
      
        }
      
      
        var json = "从数据库拿到的 JSON 字符串";
      
      
        var article = JsonConvert.DeserializeObject<Article>(json);
      
      
        var ret = new Result<Article> { Code = 200, Data = article, Message = "OK" };
      
    

以上代码在实际使用中存在几个问题:

  1. 类型必须明确指定。如果存取数据的模型不一致,接口返回的数据可能会丢失字段(也许也是个优点?)。

  2. 不必要的性能损失。 因为不会处理数据,反序列化后再序列化就显得很没有必要。


使用 Newtonsoft.Json 中的 JRaw 类型

JRaw 是 Newtonsoft.Json 库中的一种特殊类型,用于表示 JSON 中的原始(raw)数据。 它允许你在 JSON 中嵌入原始的 JSON 字符串,而不进行序列化或反序列化。 当你使用 JRaw 类型时,类库不会尝试解析该字符串,而是将其保留为原始的 JSON 数据。

改进后的 Result 可以直接将 Data 字段设置为 JRaw 类型:

      
        public class Result
      
      
        {
      
      
          public int Code { get; set; }
      
      
          public string Message { get; set; }
      
      
          public JRaw Data { get; set; }
      
      
        }
      
    

使用方式:

      
        var json = "{\"Id\":1,\"Name\":\"码农很忙\",\"Url\":\"https://www.coderbusy.com\"}";
      
      
        var ret = new Result { Code = 0, Message = "OK", Data = new JRaw(json) };
      
      
        Console.WriteLine(JsonConvert.SerializeObject(ret));
      
    

输出结果:

      
        {
      
      
          "Code": 0,
      
      
          "Message": "OK",
      
      
          "Data": {"Id":1,"Name":"码农很忙","Url":"https://www.coderbusy.com"}
      
      
        }
      
    


如果我使用的是 System.Text.Json 怎么办?

System.Text.Json 是由 微软官方开发在 .NET Core 3.0 之后引入的库,并在后续版本的 ASP.NET CORE 中默认使用。

虽然在 System.Text.Json 中,没有与 Newtonsoft.Json 中的 JRaw 直接对应的类。

但是微软在 .NET 6.0 中引入了 Utf8JsonWriter.WriteRawValue(string json, bool skipInputValidation = false) 方法,因此可以使用一个转换器来实现类似的功能:

      
        
          /// <summary>
        
      
      
        
          /// 将字符串值的内容序列化为原始 JSON。将验证字符串是否符合 RFC 8259 标准。
        
      
      
        
          /// </summary>
        
      
      
        public class RawJsonConverter : JsonConverter<string>
      
      
        {
      
      
            public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
      
      
        {
      
      
                using var doc = JsonDocument.ParseValue(ref reader);
      
      
                return doc.RootElement.GetRawText();
      
      
            }
      
      
        
          
// 是否跳过输入验证,默认为 false protected virtual bool SkipInputValidation => false;
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => // skipInputValidation : true 可提高性能,但仅在确保值表示格式良好的 JSON 时使用! writer.WriteRawValue(value, skipInputValidation: SkipInputValidation); }
/// <summary> /// 将字符串值的内容序列化为原始 JSON。不验证字符串是否符合 RFC 8259 标准。 /// </summary> public class UnsafeRawJsonConverter : RawJsonConverter { // 跳过输入验证,默认为 true protected override bool SkipInputValidation => true; }

与之对应的 Result 类型也要进行一些修改,Data 字段需要改为 string 类型,并设置转换器:

      
        public class Result
      
      
        {
      
      
          public int Code { get; set; }
      
      
          public string Message { get; set; }
      
      
          [JsonConverter(typeof(UnsafeRawJsonConverter))]
      
      
          public string Data { get; set; }
      
      
        }
      
    

使用方式:

      
        var json = "{\"Id\":1,\"Name\":\"码农很忙\",\"Url\":\"https://www.coderbusy.com\"}";
      
      
        var ret = new Result { Code = 0, Message = "OK", Data = json };
      
      
        Console.WriteLine(JsonSerializer.Serialize(ret, new JsonSerializerOptions { WriteIndented = true }));
      
    

输出结果:

      
        {
      
      
          "Code": 0,
      
      
          "Message": "OK",
      
      
          "Data": {"Id":1,"Name":"码农很忙","Url":"https://www.coderbusy.com"}
      
      
        }
      
    


结束语

通过本文介绍的方法,你可以巧妙地将一个 JSON 字符串嵌入到另一个对象中。这种技术不仅让你更好地掌控数据结构,而且能够绕过默认的序列化规则,为你的应用程序提供更大的灵活性和可扩展性。

希望本文对你在 dotnet 开发中的 JSON 处理有所帮助。在实际项目中,根据具体情况选择合适的方法,并善用 dotnet 生态系统中提供的工具和技术,将有助于提升你的开发效率和代码质量。祝愿你在 dotnet 的探索之旅中取得更多成功!


浏览 15
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报