Protobuf-net v3注册DateTimeOffset Surrogate仍报无序列化器错误
问题原因
你碰到的System.InvalidOperationException: No serializer defined for type: System.DateTimeOffset报错,核心原因是Protobuf-net v3的元数据预缓存机制和代理注册时机不匹配,你的Surrogate类写法本身没有逻辑错误。
- Protobuf-net v3默认会在首次识别到带
[ProtoContract]标记的类型时,一次性完成该类型所有序列化成员的元数据构建、全局缓存,构建完成后不会动态响应后续的Surrogate注册更新。你当前把Surrogate注册逻辑放在接口请求方法GetData()内部执行,大概率TestClass、Response<T>这些业务类型的序列化元数据,在你执行注册代码之前就已经被框架初始化完成,后续的注册操作完全不会生效。 - 补充说明:Protobuf-net v3已经原生支持
DateTimeOffset类型的序列化/反序列化,如果你不需要兼容v2版本生成的、采用Ticks+OffsetMinutes存储格式的老数据,完全不需要自定义Surrogate,直接使用该类型即可。
修复方案
按照以下步骤调整即可解决问题:
- 调整Surrogate注册时机:把代理注册逻辑移动到应用启动的最早期阶段,绝对不能放在业务请求方法内临时注册。如果是ASP.NET Core项目,就放到
Program.cs的服务注册最开头;如果是控制台项目,就放到Main方法第一行执行。
正确的注册代码如下:// 应用启动阶段、任何序列化操作执行前运行 RuntimeTypeModel.Default.Add(typeof(DateTimeOffset), false) .SetSurrogate(typeof(DateTimeOffsetSurrogate)); - 强制刷新元数据缓存:注册完成后添加如下代码,清空之前可能预生成的旧元数据,强制框架下次执行序列化操作时重新构建完整元数据:
RuntimeTypeModel.Default.CompileInPlace(); - 修正代码笔误:你贴出的
TestClass定义漏了class关键字,会导致编译错误,需要修正:[ProtoContract] public class TestClass // 补充缺失的class关键字 { [ProtoMember(1)] public DateTimeOffset Time { get; set; } }
注意事项
如果你在项目中使用了独立的Protobuf格式化组件(比如AspNetCore的Protobuf输出格式化器),这类组件通常会在服务注册阶段就扫描所有[ProtoContract]类型预构建序列化器,你必须在格式化器注册代码之前完成Surrogate配置,否则注册操作依然会失效。
内容的提问来源于stack exchange,提问作者Brandon
相关产品推荐
相关产品推荐

