提问人:Campbell 提问时间:5/4/2023 最后编辑:Campbell 更新时间:5/10/2023 访问量:791
Protobufs Timestamp 作为 RFC 3339 字符串
Protobufs Timestamp as RFC 3339 string
问:
我目前有两个应用程序,它们使用 REST API 相互通信。第一个是 .NET 7 Web API 项目,第二个是使用 HTTP 客户端连接到 API 的 Java 桌面应用。
在当前的实现中,我被迫将所有REST模型编写为Java类和C#类,这有点麻烦。
我已经对 Protobufs 进行了一些研究,我相信我可以利用它的编译器为我创建这个类。我没有编写特定于语言的类,而是编写一个文件并编译它以创建类。值得重申的是,这两个应用程序都没有使用 gRPC,而只是使用 REST。.proto
我的解决方案中的一个文件允许用户搜索指定日期范围内的事件:
message SearchParameters {
google.protobuf.Timestamp date_range_start = 1;
google.protobuf.Timestamp date_range_end = 2;
}
以前,这是通过以 RFC 3339 格式(例如)将两个日期传递给 API 来工作的,但是现在我已经引入了 Protobufs,我的 API 希望日期采用以下格式:2020-12-09T16:09:53Z
{
"seconds": 11223344,
"nanos": 0
}
我想继续将日期作为 RFC 3339 字符串传递,而不是 /。seconds
nanos
我试图向 C# 项目添加一个,但它在日期被包装在一组额外的引号中(即 )方面存在一些问题,并且它只“修复”了返回类型,如果我以 RFC 3339 格式传递日期,它们最终会成为 .JsonConverter
"\"2020-12-09T16:09:53Z\""
null
此外,Protobufs 文档中还指出,映射到 JSON 时使用的 RFC 3339 格式是预期的行为:
在 JSON 格式中,Timestamp 类型编码为 RFC 3339 格式的字符串。
裁判:
https://cloud.google.com/ruby/docs/reference/google-cloud-dlp-v2/latest/Google-Protobuf-Timestamp
https://protobuf.dev/reference/java/api-docs/com/google/protobuf/Timestamp
https://protobuf.dev/reference/php/api-docs/Google/Protobuf/Timestamp
正因为如此,我不太确定写一个是正确的方法。JsonConverter
有没有办法让 Protobuf Timestamps 像我想要的那样工作,或者是否有 Timestamp 或 Protobuf 本身的替代方案可以解决在语言之间共享 REST API 模型的问题
答:
听起来你只是将默认的 JSON 序列化与 System.Text.Json 或 Newtonsoft.Json 一起使用。我建议你不要对 protobuf 消息这样做,这些消息有自己的 JSON 表示形式。
相反,假设您使用的是 Google.Protobuf,只需调用消息即可获得 JSON 表示形式,或者使用 JsonFormatter
- 您可以根据所需的任何格式选项创建不同的实例。ToString()
JsonFormatter
同样,在解析时,只需使用 JsonParser
- 或 on 的方法,例如 .ParseJson
MessageParser<T>
SearchParameters.Parser.ParseJson(json)
评论
ModelBinderAttribute
IModelBinderProvider
In the end I was able to solve my issue by creating a , to convert the RFC 3339 string to a .TypeConverter
Timestamp
Using a was much more versatile than a custom Model Binder, as it only needed to be defined once, rather than manually specifying the custom model binder any time I used a in my API.TypeConverter
Timestamp
TypeDescriptor.AddAttributes(typeof(Timestamp), new TypeConverterAttribute(typeof(TimestampTypeConverter)));
public class TimestampTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, System.Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return Timestamp.FromDateTime(DateTime.Parse(value.ToString()!, null, DateTimeStyles.RoundtripKind));
}
}
评论