前言

说起.NET开发中的JSON处理,Newtonsoft.Json绝对是个老朋友了!这个库从2007年就开始服务开发者,到现在依然是最受欢迎的JSON处理库之一。虽然.NET Core后来推出了System.Text.Json,但Newtonsoft.Json凭借其强大的功能和灵活性,依然占据着重要地位。

今天咱们就来聊聊这个经典库,看看它到底有什么魅力,能让这么多开发者爱不释手!

什么是Newtonsoft.Json

Newtonsoft.Json,也叫JSON.NET,是一个高性能的.NET JSON框架。它能够轻松地在.NET对象和JSON之间进行转换,支持序列化和反序列化操作。

这个库的创建者James Newton-King(没错,库名就是从他的姓氏来的)真的是个天才!他创造了一个既强大又易用的工具。

主要特性

  • 高性能 - 比其他JSON库快很多
  • 灵活的API - 提供多种使用方式
  • LINQ to JSON - 可以像操作XML一样操作JSON
  • 丰富的序列化选项 - 各种自定义设置
  • 跨平台支持 - .NET Framework、.NET Core、Mono等都支持

安装与配置

NuGet包管理器安装

最简单的方式就是通过NuGet安装:

Install-Package Newtonsoft.Json

或者在Visual Studio的包管理器UI中搜索"Newtonsoft.Json"直接安装。

项目文件配置

如果你用的是.NET Core/.NET 5+项目,也可以直接在csproj文件中添加:

<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

然后restore一下就好了。

基础用法

序列化:对象转JSON

最基本的操作就是把C#对象转换成JSON字符串:

using Newtonsoft.Json;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

// 创建对象
var person = new Person
{
    Name = "张三",
    Age = 25,
    Email = "zhangsan@example.com"
};

// 序列化为JSON
string json = JsonConvert.SerializeObject(person);
Console.WriteLine(json);
// 输出:{"Name":"张三","Age":25,"Email":"zhangsan@example.com"}

简单吧!一行代码就搞定了。

反序列化:JSON转对象

反过来,我们也可以把JSON字符串转换成C#对象:

string jsonString = @"{
    'Name': '李四',
    'Age': 30,
    'Email': 'lisi@example.com'
}";

Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"姓名:{person.Name}, 年龄:{person.Age}");

注意这里用的是泛型方法,直接指定了目标类型,超级方便!

处理复杂对象

实际项目中,我们经常要处理嵌套对象、集合等复杂结构:

public class Company
{
    public string Name { get; set; }
    public List<Person> Employees { get; set; }
    public Dictionary<string, object> Metadata { get; set; }
}

var company = new Company
{
    Name = "科技公司",
    Employees = new List<Person>
    {
        new Person { Name = "王五", Age = 28, Email = "wangwu@tech.com" },
        new Person { Name = "赵六", Age = 32, Email = "zhaoliu@tech.com" }
    },
    Metadata = new Dictionary<string, object>
    {
        ["founded"] = 2020,
        ["location"] = "北京",
        ["isPublic"] = false
    }
};

string json = JsonConvert.SerializeObject(company, Formatting.Indented);

这里用了Formatting.Indented参数,让输出的JSON格式更好看,方便阅读。

高级特性

自定义序列化设置

有时候默认的序列化行为不能满足我们的需求,这时候就需要自定义设置了:

var settings = new JsonSerializerSettings
{
    // 忽略null值
    NullValueHandling = NullValueHandling.Ignore,
    // 日期格式化
    DateFormatString = "yyyy-MM-dd HH:mm:ss",
    // 属性命名策略(驼峰命名)
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};

string json = JsonConvert.SerializeObject(person, settings);

使用特性标记

通过特性(Attribute)可以更精细地控制序列化行为:

public class User
{
    [JsonProperty("user_name")]
    public string Name { get; set; }
    
    [JsonIgnore]
    public string Password { get; set; }
    
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Phone { get; set; }
    
    [JsonConverter(typeof(StringEnumConverter))]
    public UserType Type { get; set; }
}

public enum UserType
{
    Regular,
    Premium,
    Admin
}

这样设置后:

  • Name属性在JSON中会显示为"user_name"
  • Password属性完全不会出现在JSON中
  • Phone属性如果为null就不显示
  • Type枚举会显示为字符串而不是数字

LINQ to JSON

这是Newtonsoft.Json的一个杀手锏功能!可以像操作XML一样动态处理JSON:

string jsonText = @"{
    'users': [
        { 'name': '小明', 'age': 25, 'city': '上海' },
        { 'name': '小红', 'age': 23, 'city': '北京' },
        { 'name': '小刚', 'age': 27, 'city': '深圳' }
    ]
}";

JObject json = JObject.Parse(jsonText);

// 查询年龄大于24的用户
var adults = json["users"]
    .Where(u => (int)u["age"] > 24)
    .Select(u => new { 
        Name = (string)u["name"], 
        City = (string)u["city"] 
    });

foreach (var user in adults)
{
    Console.WriteLine($"{user.Name} 来自 {user.City}");
}

这种方式特别适合处理结构不固定的JSON数据。

动态处理JSON

有时候我们不知道JSON的具体结构,可以用dynamic来处理:

string json = @"{ 'name': '动态对象', 'count': 42, 'active': true }";
dynamic obj = JsonConvert.DeserializeObject(json);

Console.WriteLine($"名称:{obj.name}");
Console.WriteLine($"数量:{obj.count}");
Console.WriteLine($"状态:{obj.active}");

虽然这样很灵活,但要注意类型安全问题。

性能优化技巧

重用JsonSerializer

如果要进行大量的序列化操作,创建一个JsonSerializer实例重复使用会更高效:

var serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;

using (var writer = new StringWriter())
{
    serializer.Serialize(writer, person);
    string json = writer.ToString();
}

流式处理大文件

处理大JSON文件时,使用流式API可以避免内存溢出:

using (var reader = new JsonTextReader(new StringReader(largeJsonString)))
{
    while (reader.Read())
    {
        if (reader.TokenType == JsonToken.PropertyName)
        {
            string propertyName = reader.Value.ToString();
            // 处理属性
        }
    }
}

实际应用场景

Web API开发

在ASP.NET Web API中,Newtonsoft.Json经常用于配置序列化行为:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ContractResolver = 
                new CamelCasePropertyNamesContractResolver();
            options.SerializerSettings.DateFormatString = "yyyy-MM-dd";
            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        });
}

配置文件处理

读写JSON配置文件也是常见场景:

public class AppConfig
{
    public string DatabaseConnection { get; set; }
    public int TimeoutSeconds { get; set; }
    public bool EnableLogging { get; set; }
}

// 读取配置
string configText = File.ReadAllText("appsettings.json");
AppConfig config = JsonConvert.DeserializeObject<AppConfig>(configText);

// 保存配置
string updatedJson = JsonConvert.SerializeObject(config, Formatting.Indented);
File.WriteAllText("appsettings.json", updatedJson);

缓存序列化

把对象序列化后存到Redis等缓存系统:

public void CacheUser(User user)
{
    string json = JsonConvert.SerializeObject(user);
    // 存储到Redis
    cache.Set($"user:{user.Id}", json, TimeSpan.FromHours(1));
}

public User GetCachedUser(int userId)
{
    string json = cache.Get($"user:{userId}");
    return json != null ? JsonConvert.DeserializeObject<User>(json) : null;
}

常见问题与解决方案

循环引用问题

当对象之间存在循环引用时,序列化会出错:

var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};

string json = JsonConvert.SerializeObject(objectWithCircularReference, settings);

时区处理

处理DateTime时要注意时区问题:

var settings = new JsonSerializerSettings
{
    DateTimeZoneHandling = DateTimeZoneHandling.Utc,
    DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ"
};

大小写敏感

JSON属性名大小写不匹配时:

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
};

与System.Text.Json对比

虽然.NET Core引入了System.Text.Json,但两者各有优劣:

Newtonsoft.Json优势:

  • 功能更丰富,支持更多数据类型
  • LINQ to JSON功能强大
  • 自定义选项更多
  • 社区支持更好

System.Text.Json优势:

  • 性能更好
  • 内存占用更少
  • 更安全(默认不支持循环引用)

选择哪个主要看项目需求。如果需要复杂的JSON操作,Newtonsoft.Json依然是首选!

总结

Newtonsoft.Json确实是个优秀的库,它的强大之处在于:

  1. 简单易用 - 基础功能一行代码搞定
  2. 功能丰富 - 各种高级特性应有尽有
  3. 灵活性高 - 可以精细控制序列化行为
  4. 性能不错 - 虽然不是最快的,但够用了
  5. 稳定可靠 - 经过多年验证,bug很少

对于.NET开发者来说,掌握Newtonsoft.Json是必备技能。无论是写Web API、处理配置文件,还是做数据交换,都能派上用场。

当然,随着.NET生态的发展,System.Text.Json也在快速进步。但Newtonsoft.Json的地位短期内还是很难撼动的。毕竟,一个经过十多年打磨的库,真的不是盖的!

学会了这些基础知识,你就可以在项目中愉快地使用Newtonsoft.Json了。记住,实践是最好的老师,多写代码,多踩坑,才能真正掌握这个强大的工具!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐