我试图生成这个结构的.proto:
--模型--
基模型
[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模型
[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; }
} 加上这一行:
RuntimeTypeModel.Default[typeof(Base)].AddSubType(42, typeof(Todo));--合同--
基地合同
[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合同
[ServiceContract]
public interface ITodoService : IBaseService<Todo>
{
// FIND
[OperationContract]
ValueTask<Todo> GetOneByQueryAsync(Query query, CallContext context = default);
} 使用这种通用方法,我试图防止重复代码。
-- Startup.cs --
...
endpoints.MapGrpcService<TodoService>();
endpoints.MapCodeFirstGrpcReflectionService();
... 所以,当我运行这个:
var schema = generator.GetSchema<ITodoService>();我在.proto文件中获得了这个输出:
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。
有什么建议吗?
发布于 2021-09-13 06:25:18
此外,
函数的返回类型rpc GetOneByQuery (查询)返回(基本);是错误的,应该是Todo。
不,这是正确的;protobuf本身没有继承的概念-- protobuf-net必须使用封装的方式对它进行压缩,因此Base具有一个具有Todo的oneof subtype。在您的例子中,我们期望传递的东西实际上总是以Todo的形式解析,但是.proto模式语言没有语法来表达这一点。我们在这里所能做的绝对最好的就是在生成的.proto中添加一个额外的注释,表示// return type will always be a Todo或类似的内容。
我缺少了基本合同中的另外两个函数
服务继承和泛型服务目前在这里得不到很好的支持;同样,这些概念在.proto或gRPC中没有匹配的隐喻,而且protobuf-net需要发明一些合适的东西;到目前为止,我还没有坐下来仔细考虑过任何这样的方案或其中的含义。从根本上讲,这里的问题是,服务契约和名称用于构建路由/url;在谈论单个服务契约和方法时,这是很好的--但在谈到服务继承和泛型时,唯一地确定您正在谈论的服务,以及应该如何映射到路由和实现(实际上,还有.proto语法),就变得更加复杂了。我对这里的想法是完全开放的--到目前为止,这还不是一个关键的路径要求。
发布于 2021-09-13 19:59:14
现在,我的所有服务都在C#中,但是将来支持接口继承的模式是很好的,以防我们不得不将.proto文件共享给其他人,而不是c#应用程序。我不确定是否可以粘贴代码来帮助您支持此功能.所以,这是代码:
我要跳过模特
--合同--
//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 --
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;
} 产出:
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为您提供了您可能需要的几乎所有东西。
https://stackoverflow.com/questions/69154599
复制相似问题