{"id":38653,"date":"2020-03-18T06:00:56","date_gmt":"2020-03-18T13:00:56","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/premier-developer\/?p=38653"},"modified":"2020-03-16T11:45:06","modified_gmt":"2020-03-16T18:45:06","slug":"sharing-grpc-protobuf-contracts-using-a-rest-endpoint","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/sharing-grpc-protobuf-contracts-using-a-rest-endpoint\/","title":{"rendered":"Sharing gRPC ProtoBuf contracts using a REST endpoint"},"content":{"rendered":"<p>In this post, Premier Consultant <a href=\"https:\/\/www.linkedin.com\/in\/randyrpatterson\/\">Randy Patterson<\/a> explores ASP.NET Static File middleware as an option to distribute gRPC proto files.<\/p>\n<hr \/>\n<h2>Introduction<\/h2>\n<p>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# <em>(or language of your choice)<\/em> 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.<\/p>\n<h2>Create Project<\/h2>\n<p>Create a new project and choose the gRPC Service Template using the latest version of .Net Core<\/p>\n<p><img decoding=\"async\" width=\"1024\" height=\"710\" class=\"wp-image-38654\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-23.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-23.png 1024w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-23-300x208.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-23-768x533.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h2>Add Middleware<\/h2>\n<p>Open the <em>Startup.cs<\/em> file and modify the <em>Configure<\/em> method<\/p>\n<p>First, add the <strong>StaticFIles<\/strong> middleware before <em>app.UseRouting()<\/em> and configure it to only serve proto files located in the \/protos directory.<\/p>\n<pre class=\"lang:c# decode:true\">public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n{\r\n     . . . \r\n\r\n    \/\/only serve .proto files\r\n    var provider = new FileExtensionContentTypeProvider();\r\n    provider.Mappings.Clear();\r\n    provider.Mappings[\".proto\"] = \"text\/plain\";\r\n    app.UseStaticFiles(new StaticFileOptions\r\n    {\r\n        FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, \"Protos\")),\r\n        RequestPath = \"\/proto\",\r\n        ContentTypeProvider = provider\r\n\r\n    });\r\n\r\n    app.UseRouting();\r\n\r\n    . . .\r\n}}\r\n<\/pre>\n<h2>Update Project File<\/h2>\n<p>Next, update the project file to copy the protos directory to the <em>output<\/em> and publish <em>directories<\/em><\/p>\n<p>Before the final <strong>&lt;\/project&gt; <\/strong>element in the <em>.csproj<\/em> files add the following sections<\/p>\n<pre class=\"lang:default decode:true\">  &lt;ItemGroup&gt;\r\n    &lt;Content Update=\"Protos\\*\"&gt;\r\n      &lt;CopyToOutputDirectory&gt;Always&lt;\/CopyToOutputDirectory&gt;\r\n    &lt;\/Content&gt;\r\n  &lt;\/ItemGroup&gt;\r\n\r\n  &lt;ItemGroup&gt;\r\n    &lt;Content Include=\"Protos\\*\" CopyToPublishDirectory=\"PreserveNewest\" \/&gt;\r\n  &lt;\/ItemGroup&gt;\r\n<\/pre>\n<p>This will copy all the files in the <em>\/Protos<\/em> directory to your output and publish directories<\/p>\n<p>Run the application and navigate to <a href=\"http:\/\/localhost:5001\/proto\/greet.proto\">http:\/\/localhost:5001\/proto\/greet.proto<\/a> . You should see the following screen.<\/p>\n<p><img decoding=\"async\" width=\"977\" height=\"698\" class=\"wp-image-38655\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-24.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-24.png 977w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-24-300x214.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-24-768x549.png 768w\" sizes=\"(max-width: 977px) 100vw, 977px\" \/><\/p>\n<p>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.<\/p>\n<h2>Directory Browser<\/h2>\n<p>Optionally, you can add middleware to deliver a UI allowing a user to view all your <em>proto<\/em> files and clicking on any file will display the contents.<\/p>\n<p>Back in your <em>Startup.cs <\/em>files, add the following MiddleWare<\/p>\n<pre class=\"lang:c decode:true \">app.UseDirectoryBrowser(new DirectoryBrowserOptions\r\n{\r\n    FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, \"Protos\")),\r\n    RequestPath = \"\/proto\"\r\n});\r\n<\/pre>\n<p>Start your application and browse to the <a href=\"http:\/\/localhost:5001\/proto\">http:\/\/localhost:5001\/proto<\/a> URL and you should be presented with the following UI<\/p>\n<p><img decoding=\"async\" width=\"799\" height=\"401\" class=\"wp-image-38656\" src=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-25.png\" srcset=\"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-25.png 799w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-25-300x151.png 300w, https:\/\/devblogs.microsoft.com\/premier-developer\/wp-content\/uploads\/sites\/31\/2020\/03\/word-image-25-768x385.png 768w\" sizes=\"(max-width: 799px) 100vw, 799px\" \/><\/p>\n<h2>Conclusion<\/h2>\n<p>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 <a href=\"https:\/\/github.com\/ranpatterson\/GrpcEndpoints\">https:\/\/github.com\/ranpatterson\/GrpcEndpoints<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the challenges of implementing gRPC services is distributing the required ProtoBuf contracts and updates to clients. Delivering the contracts using a URL can make the services easier to use and discover. Learn how you can use ASP.NET Core static files middleware to distribute your proto files.<\/p>\n","protected":false},"author":582,"featured_media":37840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[80,6699,5940,1],"tags":[61],"class_list":["post-38653","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-c","category-development","category-permierdev","tag-asp-net-core"],"acf":[],"blog_post_summary":"<p>One of the challenges of implementing gRPC services is distributing the required ProtoBuf contracts and updates to clients. Delivering the contracts using a URL can make the services easier to use and discover. Learn how you can use ASP.NET Core static files middleware to distribute your proto files.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/38653","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=38653"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/38653\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=38653"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=38653"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=38653"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}