serialization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSerialization in .NET
.NET中的序列化
When to Use This Skill
何时使用该技能
Use this skill when:
- Choosing a serialization format for APIs, messaging, or persistence
- Migrating from Newtonsoft.Json to System.Text.Json
- Implementing AOT-compatible serialization
- Designing wire formats for distributed systems
- Optimizing serialization performance
当你遇到以下场景时可使用该技能:
- 为API、消息传输或持久化选择序列化格式
- 从Newtonsoft.Json迁移到System.Text.Json
- 实现兼容AOT的序列化能力
- 为分布式系统设计传输格式
- 优化序列化性能
Serialization Format Comparison
序列化格式对比
| Format | Library | AOT-Safe | Human-Readable | Relative Size | Relative Speed | Best For |
|---|---|---|---|---|---|---|
| JSON | System.Text.Json (source gen) | Yes | Yes | Largest | Good | APIs, config, web clients |
| Protobuf | Google.Protobuf | Yes | No | Smallest | Fastest | Service-to-service, gRPC wire format |
| MessagePack | MessagePack-CSharp | Yes (with AOT resolver) | No | Small | Fast | High-throughput caching, real-time |
| JSON | Newtonsoft.Json | No (reflection) | Yes | Largest | Slower | Legacy only -- do not use for AOT |
| 格式 | 依赖库 | AOT兼容 | 人类可读 | 相对体积 | 相对速度 | 适用场景 |
|---|---|---|---|---|---|---|
| JSON | System.Text.Json (源生成器) | 是 | 是 | 最大 | 良好 | APIs、配置、Web客户端 |
| Protobuf | Google.Protobuf | 是 | 否 | 最小 | 最快 | 服务间通信、gRPC传输格式 |
| MessagePack | MessagePack-CSharp | 是(搭配AOT解析器) | 否 | 小 | 快 | 高吞吐量缓存、实时场景 |
| JSON | Newtonsoft.Json | 否(依赖反射) | 是 | 最大 | 较慢 | 仅用于遗留项目 -- AOT场景请勿使用 |
When to Choose What
选型建议
- System.Text.Json with source generators: Default choice for APIs, configuration, and any scenario where human-readable output or web client consumption matters. AOT-safe.
- Protobuf: Default wire format for gRPC. Best throughput and smallest payload size for service-to-service communication. Schema-first development with files.
.proto - MessagePack: When you need binary compactness without schema management. Good for caching layers, real-time messaging, and high-throughput scenarios.
.proto
- 带源生成器的System.Text.Json:API、配置,以及所有需要人类可读输出或供Web客户端消费场景的默认选择,兼容AOT。
- Protobuf:gRPC的默认传输格式,服务间通信场景下吞吐量最高、payload体积最小,基于文件的schema优先开发模式。
.proto - MessagePack:当你需要二进制紧凑格式但不想管理schema时使用,适合缓存层、实时消息传输和高吞吐量场景。
.proto
Schema-Based vs Reflection-Based
基于Schema vs 基于反射的序列化
| Aspect | Schema-Based | Reflection-Based |
|---|---|---|
| Examples | Protobuf, MessagePack, System.Text.Json (source gen) | Newtonsoft.Json, BinaryFormatter |
| Type info in payload | No (external schema) | Yes (type names embedded) |
| Versioning | Explicit field numbers/names | Implicit (type structure) |
| Performance | Fast (no reflection) | Slower (runtime reflection) |
| AOT compatible | Yes | No |
| Wire compatibility | Excellent | Poor |
Recommendation: Use schema-based serialization for anything that crosses process boundaries.
| 对比项 | 基于Schema | 基于反射 |
|---|---|---|
| 示例 | Protobuf、MessagePack、System.Text.Json (源生成器) | Newtonsoft.Json、BinaryFormatter |
| payload中的类型信息 | 无(依赖外部schema) | 有(嵌入类型名称) |
| 版本兼容性 | 显式字段编号/名称 | 隐式(依赖类型结构) |
| 性能 | 快(无反射) | 较慢(运行时反射) |
| AOT兼容 | 是 | 否 |
| 跨版本传输兼容性 | 优秀 | 差 |
建议:所有跨进程边界的场景都使用基于Schema的序列化。
Formats to Avoid
不推荐使用的格式
| Format | Problem |
|---|---|
| BinaryFormatter | Security vulnerabilities, deprecated, never use |
| Newtonsoft.Json default | Type names in payload break on rename |
| DataContractSerializer | Complex, poor versioning |
| XML | Verbose, slow, complex |
| 格式 | 问题 |
|---|---|
| BinaryFormatter | 存在安全漏洞,已废弃,禁止使用 |
| 默认配置的Newtonsoft.Json | payload中的类型名称会在类重命名时失效 |
| DataContractSerializer | 配置复杂,版本兼容性差 |
| XML | 冗余度高、速度慢、配置复杂 |
System.Text.Json with Source Generators
搭配源生成器的System.Text.Json
For JSON serialization, use System.Text.Json with source generators for AOT compatibility and performance.
对于JSON序列化,请使用搭配源生成器的System.Text.Json来实现AOT兼容性和高性能。
Basic Setup
基础配置
csharp
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(List<Order>))]
[JsonSerializable(typeof(OrderStatus))]
public partial class AppJsonContext : JsonSerializerContext
{
}csharp
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(List<Order>))]
[JsonSerializable(typeof(OrderStatus))]
public partial class AppJsonContext : JsonSerializerContext
{
}Using the Generated Context
使用生成的上下文
csharp
// Serialize
string json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);
// Deserialize
Order? result = JsonSerializer.Deserialize(json, AppJsonContext.Default.Order);
// With options
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
TypeInfoResolver = AppJsonContext.Default
};
string json = JsonSerializer.Serialize(order, options);csharp
// 序列化
string json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);
// 反序列化
Order? result = JsonSerializer.Deserialize(json, AppJsonContext.Default.Order);
// 自定义配置
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
TypeInfoResolver = AppJsonContext.Default
};
string json = JsonSerializer.Serialize(order, options);ASP.NET Core Integration
ASP.NET Core集成
csharp
var builder = WebApplication.CreateBuilder(args);
// Minimal APIs
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});
// MVC Controllers
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});csharp
var builder = WebApplication.CreateBuilder(args);
// Minimal APIs
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});
// MVC控制器
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});Combining Multiple Contexts
合并多个上下文
csharp
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolver = JsonTypeInfoResolver.Combine(
AppJsonContext.Default,
CatalogJsonContext.Default,
InventoryJsonContext.Default
);
});csharp
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolver = JsonTypeInfoResolver.Combine(
AppJsonContext.Default,
CatalogJsonContext.Default,
InventoryJsonContext.Default
);
});Common Configuration
通用配置
csharp
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false)]
[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(List<Order>))]
public partial class AppJsonContext : JsonSerializerContext
{
}csharp
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false)]
[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(List<Order>))]
public partial class AppJsonContext : JsonSerializerContext
{
}Handling Polymorphism
处理多态
csharp
[JsonDerivedType(typeof(CreditCardPayment), "credit_card")]
[JsonDerivedType(typeof(BankTransferPayment), "bank_transfer")]
[JsonDerivedType(typeof(WalletPayment), "wallet")]
public abstract class Payment
{
public decimal Amount { get; init; }
public string Currency { get; init; } = "USD";
}
public class CreditCardPayment : Payment
{
public string Last4Digits { get; init; } = "";
}
[JsonSerializable(typeof(Payment))]
public partial class AppJsonContext : JsonSerializerContext
{
}csharp
[JsonDerivedType(typeof(CreditCardPayment), "credit_card")]
[JsonDerivedType(typeof(BankTransferPayment), "bank_transfer")]
[JsonDerivedType(typeof(WalletPayment), "wallet")]
public abstract class Payment
{
public decimal Amount { get; init; }
public string Currency { get; init; } = "USD";
}
public class CreditCardPayment : Payment
{
public string Last4Digits { get; init; } = "";
}
[JsonSerializable(typeof(Payment))]
public partial class AppJsonContext : JsonSerializerContext
{
}Protocol Buffers (Protobuf)
Protocol Buffers (Protobuf)
Best for: Actor systems, gRPC, event sourcing, any long-lived wire format.
适用场景:Actor系统、gRPC、事件溯源,所有需要长期稳定的传输格式场景。
Packages
依赖包
xml
<PackageReference Include="Google.Protobuf" Version="3.*" />
<PackageReference Include="Grpc.Tools" Version="2.*" PrivateAssets="All" />xml
<PackageReference Include="Google.Protobuf" Version="3.*" />
<PackageReference Include="Grpc.Tools" Version="2.*" PrivateAssets="All" />Proto File
Proto文件
protobuf
syntax = "proto3";
import "google/protobuf/timestamp.proto";
option csharp_namespace = "MyApp.Contracts";
message OrderMessage {
int32 id = 1;
string customer_id = 2;
repeated OrderItemMessage items = 3;
google.protobuf.Timestamp created_at = 4;
}
message OrderItemMessage {
string product_id = 1;
int32 quantity = 2;
double unit_price = 3;
}protobuf
syntax = "proto3";
import "google/protobuf/timestamp.proto";
option csharp_namespace = "MyApp.Contracts";
message OrderMessage {
int32 id = 1;
string customer_id = 2;
repeated OrderItemMessage items = 3;
google.protobuf.Timestamp created_at = 4;
}
message OrderItemMessage {
string product_id = 1;
int32 quantity = 2;
double unit_price = 3;
}Standalone Protobuf (Without gRPC)
独立使用Protobuf(无需gRPC)
csharp
using Google.Protobuf;
// Serialize to bytes
byte[] bytes = order.ToByteArray();
// Deserialize from bytes
var restored = OrderMessage.Parser.ParseFrom(bytes);
// Serialize to stream
using var stream = File.OpenWrite("order.bin");
order.WriteTo(stream);csharp
using Google.Protobuf;
// 序列化为字节数组
byte[] bytes = order.ToByteArray();
// 从字节数组反序列化
var restored = OrderMessage.Parser.ParseFrom(bytes);
// 序列化为流
using var stream = File.OpenWrite("order.bin");
order.WriteTo(stream);Proto File Registration in .csproj
.csproj中注册Proto文件
xml
<ItemGroup>
<Protobuf Include="Protos\*.proto" GrpcServices="Both" />
</ItemGroup>xml
<ItemGroup>
<Protobuf Include="Protos\*.proto" GrpcServices="Both" />
</ItemGroup>Versioning Rules
版本规则
protobuf
// SAFE: Add new fields with new numbers
message Order {
string id = 1;
string customer_id = 2;
string shipping_address = 5; // NEW - safe
}
// SAFE: Remove fields (keep the number reserved)
message Order {
string id = 1;
reserved 2; // customer_id removed
}
// UNSAFE: Change field types
message Order {
int32 id = 1; // Was: string - BREAKS!
}
// UNSAFE: Reuse field numbers
message Order {
reserved 2;
string new_field = 2; // Reusing 2 - BREAKS!
}protobuf
// 安全:使用新编号添加新字段
message Order {
string id = 1;
string customer_id = 2;
string shipping_address = 5; // 新增 - 安全
}
// 安全:删除字段(保留编号占位)
message Order {
string id = 1;
reserved 2; // customer_id已删除
}
// 不安全:修改字段类型
message Order {
int32 id = 1; // 原类型: string - 会破坏兼容性!
}
// 不安全:复用字段编号
message Order {
reserved 2;
string new_field = 2; // 复用编号2 - 会破坏兼容性!
}MessagePack
MessagePack
Best for: High-performance scenarios, compact payloads, actor messaging.
适用场景:高性能场景、紧凑payload、Actor消息传输。
Packages
依赖包
xml
<PackageReference Include="MessagePack" Version="3.*" />
<PackageReference Include="MessagePack.SourceGenerator" Version="3.*" />xml
<PackageReference Include="MessagePack" Version="3.*" />
<PackageReference Include="MessagePack.SourceGenerator" Version="3.*" />Basic Usage with Source Generator (AOT-Safe)
源生成器基础用法(兼容AOT)
csharp
using MessagePack;
[MessagePackObject]
public partial class Order
{
[Key(0)]
public int Id { get; init; }
[Key(1)]
public string CustomerId { get; init; } = "";
[Key(2)]
public List<OrderItem> Items { get; init; } = [];
[Key(3)]
public DateTimeOffset CreatedAt { get; init; }
[Key(4)]
public string? Notes { get; init; }
}csharp
using MessagePack;
[MessagePackObject]
public partial class Order
{
[Key(0)]
public int Id { get; init; }
[Key(1)]
public string CustomerId { get; init; } = "";
[Key(2)]
public List<OrderItem> Items { get; init; } = [];
[Key(3)]
public DateTimeOffset CreatedAt { get; init; }
[Key(4)]
public string? Notes { get; init; }
}Serialization
序列化
csharp
// Serialize
byte[] bytes = MessagePackSerializer.Serialize(order);
// Deserialize
var restored = MessagePackSerializer.Deserialize<Order>(bytes);
// With compression (LZ4)
var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(
MessagePackCompression.Lz4BlockArray);
byte[] compressed = MessagePackSerializer.Serialize(order, lz4Options);csharp
// 序列化
byte[] bytes = MessagePackSerializer.Serialize(order);
// 反序列化
var restored = MessagePackSerializer.Deserialize<Order>(bytes);
// 开启LZ4压缩
var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(
MessagePackCompression.Lz4BlockArray);
byte[] compressed = MessagePackSerializer.Serialize(order, lz4Options);AOT Resolver Setup
AOT解析器配置
csharp
MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard
.WithResolver(GeneratedResolver.Instance);csharp
MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard
.WithResolver(GeneratedResolver.Instance);Wire Compatibility Patterns
传输兼容性最佳实践
Tolerant Reader
宽容读取
Old code must safely ignore unknown fields:
csharp
// Protobuf/MessagePack: Automatic - unknown fields skipped
// System.Text.Json: Configure to allow
var options = new JsonSerializerOptions
{
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip
};旧版本代码必须能够安全忽略未知字段:
csharp
// Protobuf/MessagePack:自动忽略未知字段
// System.Text.Json:手动配置开启
var options = new JsonSerializerOptions
{
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip
};Introduce Read Before Write
先实现读能力再实现写能力
Deploy deserializers before serializers for new formats:
csharp
// Phase 1: Add deserializer (deployed everywhere)
public Order Deserialize(byte[] data, string manifest) => manifest switch
{
"Order.V1" => DeserializeV1(data),
"Order.V2" => DeserializeV2(data), // NEW - can read V2
_ => throw new NotSupportedException()
};
// Phase 2: Enable serializer (after V1 deployed everywhere)
public (byte[] data, string manifest) Serialize(Order order) =>
_useV2Format
? (SerializeV2(order), "Order.V2")
: (SerializeV1(order), "Order.V1");部署新格式时,先全量部署反序列化逻辑,再部署序列化逻辑:
csharp
// 阶段1:添加反序列化逻辑(全量部署)
public Order Deserialize(byte[] data, string manifest) => manifest switch
{
"Order.V1" => DeserializeV1(data),
"Order.V2" => DeserializeV2(data), // 新增:可读取V2格式
_ => throw new NotSupportedException()
};
// 阶段2:启用序列化逻辑(V1反序列化全量部署后开启)
public (byte[] data, string manifest) Serialize(Order order) =>
_useV2Format
? (SerializeV2(order), "Order.V2")
: (SerializeV1(order), "Order.V1");Never Embed Type Names
不要嵌入类型名称
csharp
// BAD: Type name in payload - renaming class breaks wire format
{
"$type": "MyApp.Order, MyApp",
"id": 123
}
// GOOD: Explicit discriminator - refactoring safe
{
"type": "order",
"id": 123
}csharp
// 错误:payload中携带类型名称 - 类重命名会破坏传输兼容性
{
"$type": "MyApp.Order, MyApp",
"id": 123
}
// 正确:显式类型标识 - 重构安全
{
"type": "order",
"id": 123
}Performance Comparison
性能对比
Approximate throughput (higher is better):
| Format | Serialize | Deserialize | Size |
|---|---|---|---|
| MessagePack | ★★★★★ | ★★★★★ | ★★★★★ |
| Protobuf | ★★★★★ | ★★★★★ | ★★★★★ |
| System.Text.Json (source gen) | ★★★★☆ | ★★★★☆ | ★★★☆☆ |
| System.Text.Json (reflection) | ★★★☆☆ | ★★★☆☆ | ★★★☆☆ |
| Newtonsoft.Json | ★★☆☆☆ | ★★☆☆☆ | ★★★☆☆ |
近似吞吐量(越高越好):
| 格式 | 序列化性能 | 反序列化性能 | 体积 |
|---|---|---|---|
| MessagePack | ★★★★★ | ★★★★★ | ★★★★★ |
| Protobuf | ★★★★★ | ★★★★★ | ★★★★★ |
| System.Text.Json (源生成器) | ★★★★☆ | ★★★★☆ | ★★★☆☆ |
| System.Text.Json (反射) | ★★★☆☆ | ★★★☆☆ | ★★★☆☆ |
| Newtonsoft.Json | ★★☆☆☆ | ★★☆☆☆ | ★★★☆☆ |
Optimization Tips
优化建议
- Reuse -- creating options is expensive
JsonSerializerOptions - Use -- eliminates warm-up cost
JsonSerializerContext - Use /
Utf8JsonWriterfor streaming scenariosUtf8JsonReader - Use Protobuf for binary data instead of base64-encoded strings
ByteString - Enable MessagePack LZ4 compression for large payloads
- 复用-- 创建Options实例的开销很高
JsonSerializerOptions - 使用-- 消除预热成本
JsonSerializerContext - 流式场景下使用/
Utf8JsonWriterUtf8JsonReader - 二进制数据使用Protobuf ,而非base64编码的字符串
ByteString - 大payload启用MessagePack LZ4压缩
Anti-Patterns: Reflection-Based Serialization
反模式:基于反射的序列化
Do not use reflection-based serializers in Native AOT or trimming scenarios.
禁止在Native AOT或裁剪场景下使用基于反射的序列化器。
Newtonsoft.Json (JsonConvert)
Newtonsoft.Json (JsonConvert)
csharp
// BAD: Reflection-based -- fails under AOT/trimming
var json = JsonConvert.SerializeObject(order);
var order = JsonConvert.DeserializeObject<Order>(json);
// GOOD: Source-generated -- AOT-safe
var json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);
var order = JsonSerializer.Deserialize(json, AppJsonContext.Default.Order);csharp
// 错误:基于反射 -- AOT/裁剪场景下会失败
var json = JsonConvert.SerializeObject(order);
var order = JsonConvert.DeserializeObject<Order>(json);
// 正确:源生成 -- 兼容AOT
var json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);
var order = JsonSerializer.Deserialize(json, AppJsonContext.Default.Order);System.Text.Json Without Source Generators
未使用源生成器的System.Text.Json
csharp
// BAD: No context -- uses runtime reflection
var json = JsonSerializer.Serialize(order);
// GOOD: Explicit context -- uses source-generated code
var json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);csharp
// 错误:未指定上下文 -- 会使用运行时反射
var json = JsonSerializer.Serialize(order);
// 正确:显式指定上下文 -- 使用源生成的代码
var json = JsonSerializer.Serialize(order, AppJsonContext.Default.Order);Migration Path from Newtonsoft.Json
从Newtonsoft.Json迁移路径
- Replace /
JsonConvert.SerializeObjectwithDeserializeObject/JsonSerializer.SerializeDeserialize - Replace with
[JsonProperty][JsonPropertyName] - Replace base class with
JsonConverterfrom System.Text.JsonJsonConverter<T> - Create a with
JsonSerializerContextfor all serialized types[JsonSerializable] - Replace /
JObjectdynamic access withJToken/JsonDocumentor strongly-typed modelsJsonElement - Test serialization round-trips -- attribute semantics differ
- 将/
JsonConvert.SerializeObject替换为DeserializeObject/JsonSerializer.SerializeDeserialize - 将替换为
[JsonProperty][JsonPropertyName] - 将JsonConverter基类替换为System.Text.Json提供的
JsonConverter<T> - 为所有需要序列化的类型添加注解,创建
[JsonSerializable]JsonSerializerContext - 将/
JObject动态访问替换为JToken/JsonDocument或者强类型模型JsonElement - 测试序列化往返 -- 注解语义存在差异
Akka.NET Serialization
Akka.NET序列化
For Akka.NET actor systems, use schema-based serialization:
hocon
akka {
actor {
serializers {
messagepack = "Akka.Serialization.MessagePackSerializer, Akka.Serialization.MessagePack"
}
serialization-bindings {
"MyApp.Messages.IMessage, MyApp" = messagepack
}
}
}对于Akka.NET Actor系统,使用基于Schema的序列化:
hocon
akka {
actor {
serializers {
messagepack = "Akka.Serialization.MessagePackSerializer, Akka.Serialization.MessagePack"
}
serialization-bindings {
"MyApp.Messages.IMessage, MyApp" = messagepack
}
}
}Key Principles
核心原则
- Default to System.Text.Json with source generators for all JSON serialization
- Use Protobuf for service-to-service binary serialization
- Use MessagePack for high-throughput caching and real-time
- Never use Newtonsoft.Json for new AOT-targeted projects
- Always register in ASP.NET Core
JsonSerializerContext - Annotate all serialized types -- source generators only generate code for listed types
- 所有JSON序列化默认使用带源生成器的System.Text.Json
- 服务间二进制序列化使用Protobuf
- 高吞吐量缓存和实时场景使用MessagePack
- 面向AOT的新项目禁止使用Newtonsoft.Json
- ASP.NET Core中务必注册
JsonSerializerContext - 所有序列化类型都要添加注解 -- 源生成器只会为显式列出的类型生成代码
Agent Gotchas
注意事项
- Do not use without a context in AOT projects -- it falls back to reflection.
JsonSerializer.Serialize(obj) - Do not forget to list collection types in --
[JsonSerializable]does not cover[JsonSerializable(typeof(Order))].List<Order> - Do not use Newtonsoft.Json attributes with System.Text.Json -- they are silently ignored.
[JsonProperty] - Do not mix MessagePack integer keys with
[Key]string keys in the same type hierarchy.[Key] - Do not omit attribute on
GrpcServicesitems -- without it, both client and server stubs are generated.<Protobuf>
- AOT项目中不要不带上下文直接使用-- 会回退到反射实现
JsonSerializer.Serialize(obj) - 不要忘记在中列出集合类型 --
[JsonSerializable]不会覆盖[JsonSerializable(typeof(Order))]List<Order> - 不要在System.Text.Json中使用Newtonsoft.Json的注解 -- 会被静默忽略
[JsonProperty] - 同一类型层级中不要混用MessagePack的整数键和
[Key]字符串键[Key] - 不要省略节点的
<Protobuf>属性 -- 不配置的话会同时生成客户端和服务端存根GrpcServices
Resources
参考资源
- System.Text.Json Source Generation: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation
- Migrate from Newtonsoft.Json to System.Text.Json: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft
- Protocol Buffers: https://protobuf.dev/
- MessagePack-CSharp: https://github.com/MessagePack-CSharp/MessagePack-CSharp
- Akka.NET Serialization: https://getakka.net/articles/networking/serialization.html
- Wire Compatibility: https://getakka.net/community/contributing/wire-compatibility.html
- Native AOT deployment: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
- System.Text.Json源生成器: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation
- 从Newtonsoft.Json迁移到System.Text.Json: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft
- Protocol Buffers: https://protobuf.dev/
- MessagePack-CSharp: https://github.com/MessagePack-CSharp/MessagePack-CSharp
- Akka.NET序列化: https://getakka.net/articles/networking/serialization.html
- 传输兼容性: https://getakka.net/community/contributing/wire-compatibility.html
- Native AOT部署: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/