首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用protobuf-net.Grpc生成通用服务的.proto文件

使用protobuf-net.Grpc生成通用服务的.proto文件
EN

Stack Overflow用户
提问于 2021-09-12 19:28:23
回答 2查看 605关注 0票数 1

我试图生成这个结构的.proto:

--模型--

基模型

代码语言:javascript
复制
[DataContract]
public abstract class Base
{
   [ProtoMember(1)]
   public string Id { get; set; }

   [ProtoMember(2, DataFormat = DataFormat.WellKnown)]
   public DateTime CreatedDate { get; private set; } = DateTime.UtcNow;

   [ProtoMember(3, DataFormat = DataFormat.WellKnown)]
   public DateTime UpdatedDate { get; set; } = DateTime.UtcNow;
}         

Todo模型

代码语言:javascript
复制
[ProtoContract]
public class Todo : Base
{
   [ProtoMember(1)]
   public string Title { get; set; }

   [ProtoMember(2)]
   public string Content { get; set; }
 
   [ProtoMember(3)]
   public string Category { get; set; }
}      

加上这一行:

代码语言:javascript
复制
RuntimeTypeModel.Default[typeof(Base)].AddSubType(42, typeof(Todo));

--合同--

基地合同

代码语言:javascript
复制
[ServiceContract]
public interface IBaseService<T>
{
   // CREATE
   [OperationContract]
   Task<RStatus> CreateOneAsync(T request,CallContext context = default);
   
   // FIND
   [OperationContract]
   ValueTask<T> GetById(UniqueIdentification request,CallContext context = default);
}        

Todo合同

代码语言:javascript
复制
[ServiceContract]
public interface ITodoService : IBaseService<Todo>
{
   // FIND        
   [OperationContract]
   ValueTask<Todo> GetOneByQueryAsync(Query query, CallContext context = default);
}          

使用这种通用方法,我试图防止重复代码。

-- Startup.cs --

代码语言:javascript
复制
     ...
endpoints.MapGrpcService<TodoService>();
endpoints.MapCodeFirstGrpcReflectionService();
     ...       

所以,当我运行这个:

代码语言:javascript
复制
var schema = generator.GetSchema<ITodoService>();

我在.proto文件中获得了这个输出:

代码语言:javascript
复制
syntax = "proto3";
package Nnet.Contracts;
import "google/protobuf/timestamp.proto";

message Base {
   string Id = 1;
   .google.protobuf.Timestamp CreatedDate = 2;
   .google.protobuf.Timestamp UpdatedDate = 3;
   oneof subtype {
     Todo Todo = 42;
   }
}
message IEnumerable_Todo {
   repeated Base items = 1;
}
message Query {
   string Filter = 1;
}
message Todo {
   string Title = 1;
   string Content = 2;
   string Category = 3;
}
service TodoService {
   rpc GetOneByQuery (Query) returns (Base);
}

在.proto文件部分service Todoservice中,我缺少了Base中的其他两个函数。另外,函数rpc GetOneByQuery (Query) returns (Base);的返回类型是错误的,应该是Todo。

有什么建议吗?

EN

回答 2

Stack Overflow用户

发布于 2021-09-13 06:25:18

此外,

函数的返回类型rpc GetOneByQuery (查询)返回(基本);是错误的,应该是Todo。

不,这是正确的;protobuf本身没有继承的概念-- protobuf-net必须使用封装的方式对它进行压缩,因此Base具有一个具有Todooneof subtype。在您的例子中,我们期望传递的东西实际上总是以Todo的形式解析,但是.proto模式语言没有语法来表达这一点。我们在这里所能做的绝对最好的就是在生成的.proto中添加一个额外的注释,表示// return type will always be a Todo或类似的内容。

我缺少了基本合同中的另外两个函数

服务继承和泛型服务目前在这里得不到很好的支持;同样,这些概念在.proto或gRPC中没有匹配的隐喻,而且protobuf-net需要发明一些合适的东西;到目前为止,我还没有坐下来仔细考虑过任何这样的方案或其中的含义。从根本上讲,这里的问题是,服务契约和名称用于构建路由/url;在谈论单个服务契约和方法时,这是很好的--但在谈到服务继承和泛型时,唯一地确定您正在谈论的服务,以及应该如何映射到路由和实现(实际上,还有.proto语法),就变得更加复杂了。我对这里的想法是完全开放的--到目前为止,这还不是一个关键的路径要求。

票数 1
EN

Stack Overflow用户

发布于 2021-09-13 19:59:14

现在,我的所有服务都在C#中,但是将来支持接口继承的模式是很好的,以防我们不得不将.proto文件共享给其他人,而不是c#应用程序。我不确定是否可以粘贴代码来帮助您支持此功能.所以,这是代码:

我要跳过模特

--合同--

代码语言:javascript
复制
//Base Contract
public interface IBaseService<T>
{
    Task<RStatus> CreateOne(T request);

    ValueTask<T> GetById(UniqueIdentification request);
}

//Product Contract
public interface IProductService<T> : IBaseService<T>
{
    Task<T> GetByBrandName(string request);

    ValueTask<T> GetByName(string request);
}

    //Audio Contract
public interface IAudioService<T>
{
    Task<T> GetBySoundQuality(int request);
}


//Headphones Contract
public interface IHeadphonesService : IProductService<Headphones>, IAudioService<Headphones>
{
    Task<Headphones> GetByBluetoothOption(bool request);
}             

-- PROGRAM.CS --

代码语言:javascript
复制
static void Main(string[] args)
{
    foreach (var type in TypesToGenerateForType(typeof(IHeadphonesService)))
    {
        Console.WriteLine($"Type: {type} \n");
    }
}

public static IEnumerable<Type> TypesToGenerateForType(Type type)
{
    foreach (var interfaceType in type.FindInterfaces((ignored, data) => true, null))
    {
        foreach (var dm in interfaceType.GetMethods())
        {
            Console.WriteLine($"Method Name: {dm}");
        }
        yield return interfaceType;
    }
    foreach (var tm in type.GetMethods())
    {
        Console.WriteLine($"Method Name: {tm}");
    }
    yield return type;
}      

产出:

代码语言:javascript
复制
Method Name: System.Threading.Tasks.Task`1[TestIntInh.Shared.Models.Headphones] GetByBrandName(System.String)
Method Name: System.Threading.Tasks.ValueTask`1[TestIntInh.Shared.Models.Headphones] GetByName(System.String)
Type: TestIntInh.Shared.Contracts.IProductService`1[TestIntInh.Shared.Models.Headphones 

Method Name: System.Threading.Tasks.Task`1[TestIntInh.Shared.Models.RStatus] CreateOne(TestIntInh.Shared.Models.Headphones)
Method Name: System.Threading.Tasks.ValueTask`1[TestIntInh.Shared.Models.Headphones] GetById(TestIntInh.Shared.Models.UniqueIdentification)
Type: TestIntInh.Shared.Contracts.IBaseService`1[TestIntInh.Shared.Models.Headphones] 

Method Name: System.Threading.Tasks.Task`1[TestIntInh.Shared.Models.Headphones] GetBySoundQuality(Int32)
Type: TestIntInh.Shared.Contracts.IAudioService`1[TestIntInh.Shared.Models.Headphones] 

Method Name: System.Threading.Tasks.Task`1[TestIntInh.Shared.Models.Headphones] GetByBluetoothOption(Boolean)
Type: TestIntInh.Shared.Contracts.IHeadphonesService        

我认为有了这个,您可以构建适当的.proto文件。FindInterfaces为您提供了您可能需要的几乎所有东西。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69154599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档