In this post, Premier Consultant Randy Patterson explores ASP.NET Static File middleware as an option to distribute gRPC proto files.
Introduction
gRPC services require a service contract usually defined using the Protocol Buffer Language in proto files. The service contract is then used to generate your C# (or language of your choice) server-side classes and your client side proxies. Sharing these proto contract files is necessary for generating these classes. However, there is no easy way to share these files other than copying them from the server to the client. Sharing files like this can be especially difficult in a Microservices architecture where there can be many different clients developed by many different teams. This post will walk you through the process of adding middleware to a gRPC server to deliver your proto files using a URL instead of files.
Create Project
Create a new project and choose the gRPC Service Template using the latest version of .Net Core
Add Middleware
Open the Startup.cs file and modify the Configure method
First, add the StaticFIles middleware before app.UseRouting() and configure it to only serve proto files located in the /protos directory.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { . . . //only serve .proto files var provider = new FileExtensionContentTypeProvider(); provider.Mappings.Clear(); provider.Mappings[".proto"] = "text/plain"; app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Protos")), RequestPath = "/proto", ContentTypeProvider = provider }); app.UseRouting(); . . . }}
Update Project File
Next, update the project file to copy the protos directory to the output and publish directories
Before the final </project> element in the .csproj files add the following sections
<ItemGroup> <Content Update="Protos\*"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <Content Include="Protos\*" CopyToPublishDirectory="PreserveNewest" /> </ItemGroup>
This will copy all the files in the /Protos directory to your output and publish directories
Run the application and navigate to http://localhost:5001/proto/greet.proto . You should see the following screen.
Much like WCF WSDL Endpoints to REST API Swagger endpoints, you now have gRPC endpoints that deliver the contract files to any client that needs them.
Directory Browser
Optionally, you can add middleware to deliver a UI allowing a user to view all your proto files and clicking on any file will display the contents.
Back in your Startup.cs files, add the following MiddleWare
app.UseDirectoryBrowser(new DirectoryBrowserOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Protos")), RequestPath = "/proto" });
Start your application and browse to the http://localhost:5001/proto URL and you should be presented with the following UI
Conclusion
One of the challenges of implementing gRPC endpoints is distributing the required ProtoBuf contracts and updates to clients. There are several ways of accomplishing this including brute force method of copying the files to the client, NuGet Packages or network file shares. Delivering the contracts using a URL can make the services easier to use and discover. This can be crucial in a large micro-service architecture where you could have hundreds of contracts to manage. To view the full source code please visit https://github.com/ranpatterson/GrpcEndpoints
Isn’t this exactly what server reflection is for? https://github.com/grpc/grpc/blob/master/doc/server-reflection.md
After we make the .proto files available for consumption, how does the client generate its C# proxies from this as part of the build process?
In Visual Studio it’s the same approach as selecting the .proto files from disk. You click on the “Connected Services”-Node in your project, select Service References in the opened form, then you click on “Add new gRPC service reference” and a dialog shows up. Here you have the option between File and URL. That’s it. 🙂