Grpc-dotnet: Map route to proto file

Created on 29 Sep 2020  路  12Comments  路  Source: grpc/grpc-dotnet

First of all, if this feature exists, consider this a possible documentation issue, as I did not know how to achive it.

All documentation and code examples assume the proto files are pre-existing.

I would like to follow a pattern where each service documents itself. I use the Reflection service to be able to hook up e.g. grpc-ui and grpcurl to my services. I would also like to be able to download the proto file from the service itself (over plain vanilla HTTP).

Proposed solution

Add an extension method, e.g. MapProtobufMetadata("/my-metadata-endpoint.proto"). This serves the combined .proto file for all defined service.
As an alternative e.g. MapProtobufMetadata"/my-metadata-endpoint/myservice.proto"). This serves the proto file for a specific service.

The only reason I could think of for not having this is that there is a better way to do it, but I really couldn't find one.

question

All 12 comments

You can use the static files middleware to serve the proto files. Let us know if there is anything you need in addition to the functionality provided by that middleware.

How can I get hold of the contents of this file if I roll my own mapping? I can see how I could do this myself using custom build steps, running external tooling etc, but I was hoping it could be done by the library, since it already does this for the reflection API.

A proto file must be on disk.

So what I'm looking for is a simple way to define the protos as part of the serving project (.Proto files using the Protobuf item type), then expose the services, then having a metadata endpoint that I could point e.g Visual Studio (Add service reference) to.
Otherwise I would need to ship the proto through side channels (publish to a separate api docs server during build etc), which ideally I would avoid.
This is my use case. If this is entirely out of scope for this project and not supported I will code this myself, but I would expect this to be a common use case.

You can distribute a compiled client as a compiled NuGet package.

There is discussion about ways to distribute proto files in packages here - https://github.com/grpc/grpc-dotnet/issues/183

We considered moving the generated client to a separate NuGet package, but it wasn't a good fit with our release process (it added another redundant version for example).

If there is no tooling and considered not in the scope for this project, we can easily solve it with our already existing dev docs scheme (basically publish to object storage). But I just wanted to confirm before building something bespoke.

It is quite a common pattern to allow services to describe themselves (similar to the already existing metadata API), so I figured this might be something in scope for this project.

Some background: there's already a reflection protocol that services can use to describe themselves. It's currently considered an alpha feature. The C-core C# implementation has an implementation of this protocol. Skimming the code, it's not super complex. It looks like it could be adapted to gRPC .NET.

@rickardp, if you ever do end up creating generated client NuGet packages, you'll probably want to include the .proto files in them as well. That way, if one of your consumers can't use the generated clients for some reason, they have an escape hatch and can generate their own clients.

There is support for the reflection protocol in grpc-dotnet: https://www.nuget.org/packages/Grpc.AspNetCore.Server.Reflection/. Let us know if that's sufficient for your needs @rickardp

Thank you, yes I am using the reflection protocol, and it successfully powers the debug UI. So it can definitely be used to call the services.
However, to generate the client, I believe I have to somehow serve the .proto files, right? My end goal is to be able to use the "add service" functionality in Visual Studio to update the schema and client pointing to a URL of the latest deployed service.

I believe I have to somehow serve the .proto files, right?

The proto files need to be on disk to generate a client. How to get the proto files on disk is up to you. One way is using ASP.NET Core's static files feature: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1

protoc can also generate code using a FileDescriptorSet that the Reflection service returns. Here I've used grpcurl to interrogate a gRPC service that implements reflection and then generated C# code based on its response.

PS > grpcurl -plaintext '-protoset-out=greet.pb.bin' localhost:5000 describe greet.Greeter
greet.Greeter is a service:
service Greeter {
  rpc SayHello ( .greet.HelloRequest ) returns ( .greet.HelloReply );
}
PS > protoc '--descriptor_set_in=greet.pb.bin' --csharp_out=. greet.proto
PS > more Greet.cs
// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: greet.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = global::Google.Protobuf;
...

If you want to generate the client/service gRPC code as well, you'll also need to include the gRPC plugin and pass the relevant options.

Cool, didn't know that. I am not sure the code generator works that way in dotnet though. But strictly I don't need the text proto file as long as I can generate the client from the running service.

Anyway, my expectation from adding the metadata service as a user of the library is that I could use it to generate the client. I would want something better than serving static files manually as I would have to write code myself to automatically merge all the proto files into one etc, which means a lot of plumbing code. All I want is for "add service reference" to work :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vuggg picture vuggg  路  3Comments

shawnwildermuth picture shawnwildermuth  路  4Comments

JamesNK picture JamesNK  路  6Comments

davidfowl picture davidfowl  路  6Comments

JunTaoLuo picture JunTaoLuo  路  5Comments