简体   繁体   English

如何在 gRPC 原型文件中支持 C# 动态类型

[英]How to support C# dynamic types in an gRPC proto file

We have a POST action in our asp.net core application that accepts a dynamic object.我们的 asp.net 核心应用程序中有一个 POST 操作,它接受dynamic object。

[HttpPost]
public Task<ActionResult> SubmitAsync(dynamic unitOfWork)

We'd like to transform this POST action to a gRPC server and we'd like to continue receiving dynamic objects in the gRPC service.我们希望将此 POST 操作转换为 gRPC 服务器,并且我们希望继续在 gRPC 服务中接收dynamic对象。 What is the equivalent of C# dynamic definition in gRPC protobuf file definition? gRPC protobuf文件定义中C# dynamic定义的等价物是什么? Or if that cannot be achieved what's the best way to receive a dynamic object?或者,如果无法实现,接收动态 object 的最佳方式是什么?

That isn't really a thing right now.现在这不是真正的事情。 In protobuf terms, Any is the closest thing, but I have not yet implemented that in protobuf.net (it is on my short term additions list).在 protobuf 术语中, Any是最接近的东西,但我还没有在 protobuf.net 中实现它(它在我的短期添加列表中)。 The legacy "dynamic types" feature in protobuf.net (that sends type metadata) is actively being phased out, with Any being the preferred route since it allows cross-platform usage and doesn't have the same metadata dependencies. protobuf.net 中遗留的“动态类型”功能(发送类型元数据)正在被积极淘汰, Any是首选路由,因为它允许跨平台使用并且没有相同的元数据依赖性。

Frankly, though, I'd probably say "just don't do this";不过,坦率地说,我可能会说“只是不要这样做”; instead, prefer oneof ;相反,更喜欢oneof ; it isn't likely that you actually mean "anything" - you probably just mean "one of these things that I expect, but I don't know which", and oneof expresses that intent.实际上不太可能是指“任何东西”-您可能只是指“我期望的这些东西之一,但我不知道是哪个”,而oneof一个表达了该意图。 More: protobuf.net implements inheritance via oneof , so a good option is something like:更多:protobuf.net 通过oneof实现inheritance ,所以一个不错的选择是这样的:

[ProtoContract]
[ProtoInclude(1, typeof(FooRequest))]
[ProtoInclude(2, typeof(BarRequest))]
public abstract class RequestBase {}

[ProtoContract]
public class FooRequest {} 
[ProtoContract]
public class BarRequest {} 

You can pass messages with fields whose type was not known in advance.您可以传递带有事先未知类型的字段的消息。 You can also pass messages with fields that are not typed, such as dynamic objects that can take any scalar values, and collections null values are allowed.您还可以传递具有未键入字段的消息,例如可以采用任何标量值的动态对象,并且允许 collections null 值。 To do so, import the proto file "google/protobuf/struct.proto" and declare the dynamic type as google.protobuf.Value .为此,导入原型文件"google/protobuf/struct.proto"并将动态类型声明为google.protobuf.Value

So, first add bellow line at the top of your proto file:所以,首先在你的原型文件的顶部添加波纹管行:

import "google/protobuf/struct.proto";

Here my sample message with two dynamic fields:这是我的带有两个动态字段的示例消息:

message BranchResponse {
 google.protobuf.Value BranchId = 1;
 google.protobuf.Value BranchLevel = 2;
}

Note that: the generated type in C# is Value and belongs to the Google.Protobuf.WellKnownTypes namespace, which belongs itself to the Google.Protobuf assembly.注意:C#中生成的类型是Value,属于Google.Protobuf.WellKnownTypes命名空间,它本身属于Google.Protobuf程序集。 This type inherits from the IMessage, IMessage, IEquatable, IDeepCloneable, and IBufferMessage interfaces that all belong to the Google.Protobuf assembly, except for IEquatable, which comes from the .NET System.Runtime assembly.此类型继承自 IMessage、IMessage、IEquatable、IDeepCloneable 和 IBufferMessage 接口,它们都属于 Google.Protobuf 程序集,但 IEquatable 除外,它来自 .NET System.Runtime 程序集。 To write and read dynamic values, we have a set of methods available that shown bellow: (these are write static functions)要写入和读取动态值,我们有一组可用的方法,如下所示:(这些是写入 static 函数)

在此处输入图像描述

We can fill BranchResponse model like this:我们可以这样填写 BranchResponse model:

var branch = new BranchResponse();
branch.BranchId = Value.ForNumber(1);
branch.BranchLevel = Value.ForStruct(new Struct
{
 Fields = {
 ["LevelId"] = Value.ForNumber(1),
 ["LevelName"] = Value.ForString("Gold"),
 ["IsProfessional"] = Value.ForBool(true)}
});

The read Value type is straightforward.读取值类型很简单。 The Value type has a set of properties that exposes its value in the wanted type. Value 类型具有一组属性,这些属性在所需类型中公开其值。 (these are read static functions) (这些都是读取static的函数)

在此处输入图像描述

At the end, you need to read data from your response model like this:最后,您需要像这样从响应 model 中读取数据:

Here my c# classes that my response model is supposed to bind to them.这是我的 c# 类,我的响应 model 应该绑定到它们。

public class BranchModel
{
 public int BranchId { get; set; }
 public LevelModel Level { get; set; }
}
public class LevelModel
{
 public int LevelId{ get; set; }
 public string LevelName{ get; set; }
 public bool IsProfessional { get; set; }
}

Finally:最后:

var branch = new BranchResponse(); // Received filled from a gRPC call
// Read
var branchModel = new BranchModel
{
 BranchId = Convert.ToInt32(branch.BranchId.NumberValue),
 Level= new LevelModel
   {
      LevelId = Convert.ToInt32(branchModel.Level.StructValue.
      Fields["LevelId"].NumberValue),
      LevelName = branchModel.Level.StructValue.
      Fields["LevelName"].StringValue,
      IsProfessional = branchModel.Level.StructValue.
      Fields["IsProfessional"].BoolValue,
   }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM