gRPC for ASP.NET Core 3.0
gRPC is a high performance RPC framework. A faster and more efficient alternative to JSON based REST services. gRPC uses HTTP/2 protocol and by default Google's protocol buffer binary serialisation format to transfer messages. This is mature and a must technology in cloud native products. I will spare you from the introduction as I know you are here to quickly start gRPC using ASP.NET Core.
I have recently upgraded a gRPC service at work (that was using .NET Core 2.2) into .NET Core 3.0 Preview 7. It was such a smooth migration. gRPC in .NET Core 3.0 has first class support by the framework just like using a MVC Controller, SignalR Hub or Razor page.
Starting from ASP.NET Core 3 gRPC has first class support by the framework. It is supported into the framework starting from Kestrel up to the new Endpoint routing. You no longer need to use a separate binary to generate code. It's as simple as building the project. An ASP.NET application can expose gRPC, MVC, WebApi, SignalR Hub endpoint etc all at the same time. It integrates seamlessly into Endpoint routing, built-in IoC container and generated logs are just like any other logs - all out of the box.
A gRPC service has 3 elements. A server, bunch of clients and a
.proto file. If you are from JSON based service background then you know what I mean by server and client. What's new here is the proto file.
Protocol buffer file (protobuf) - The Contract
.proto file contains the scheme of your service endpoints and models (in protobuf's term - message). For our example we will need two RPC endpoints
SayHellothat takes a name and returns a
SayHelloToNobodythat does not take any parameter and returns a
Here is the proto file
If you can't see the code above switch to non-amp version of this post.
Each RPC required to take one message. Therefore we could add one or many properties in the
HelloRequest message and assign an unique number for each property. Since protobuf is designed for speed and efficiency in mind, it only sends the number over the wire in order to identify a property.
You can read more about protobuf files in the Language Guide for proto3 format.
The proto file is then used by gRPC compilers (available for many popular language) to generate code for a Client and a Server. In order to do that, we need to put the
proto file into a shared place to be accessed by both the client and server.
In a non-trivial C# project, you would create a NuGet package that would contain the generated code for Client and Server. For simplicity, we are going to put the
.proto files and generated code into a separate c# project and reference it from both client and server projects.
Here is a
netstandard2.0 project that references required NuGet packages and the proto file defined above.
GrpcServices="Both" (instead of
Server - we've asked for
Both). That's why once you build the project - it will generate code for both the client (for consumption) and server (for implementation). Also, by targeting
netstandard2.0 we have enabled wider compatibility from entire .NET ecosystem.
The generated code defines the contract defined in the
.proto file into programming language (in our case C#). We need to define the implementation. So we have a ASP.NET Core app that references the
Here is the
Program (the entry-point of a c# app),
Startup (convention based bootstrapping an ASP.NET Web/API) and an implementation of our
DemoService (defined in the
Once started, the gRPC service will be up in
http://localhost:5000 endpoint. You can use any gRPC client like grpcurl CLI or BloomRPC GUI to test the server.
The server automatically generates logs message like this
/usr/local/share/dotnet/dotnet /Users/mustakim/dev/grpc-dotnet-post/Server/bin/Debug/netcoreapp3.0/Server.dll warn: Microsoft.AspNetCore.Server.Kestrel Overriding address(es) 'https://localhost:5001, http://localhost:5000'. Binding to endpoints defined in UseKestrel() instead. info: Microsoft.Hosting.Lifetime Now listening on: http://0.0.0.0:5000 info: Microsoft.Hosting.Lifetime Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime Hosting environment: Development info: Microsoft.Hosting.Lifetime Content root path: /Users/mustakim/dev/grpc-dotnet-post/Server info: Microsoft.AspNetCore.Hosting.Diagnostics Request starting HTTP/2 POST http://localhost:5000/GrpcDotNetDemoPackage.DemoService/SayHello application/grpc info: Microsoft.AspNetCore.Routing.EndpointMiddleware Executing endpoint 'gRPC - /GrpcDotNetDemoPackage.DemoService/SayHello' info: Microsoft.AspNetCore.Routing.EndpointMiddleware Executed endpoint 'gRPC - /GrpcDotNetDemoPackage.DemoService/SayHello' info: Microsoft.AspNetCore.Hosting.Diagnostics Request finished in 60.1197ms 200 application/grpc
You are not limited to use a C# client. gRPC gives you the freedom to generate code in many popular programming language like Go, Java etc. All you need is the same proto file and the address of the server (http://localhost:5000) in our case. Here is a c# client that uses a
HttpClient and and extension methods defined in
Grpc.Net.Client nuget package to create a client using the generated client code in our
Running the client (while the serve is running - of course) works as expected.
Other ways of getting the gRPC client
If the client was an ASP.NET web application (or a console application bootstrapped using .NET Generic Host), you could use IHttpClientFactory to get a HttpClient (instead of
newing up) - which would be reused for improved performance.
Even better you can use
IServiceCollection.AddGrpcClient extension method like this (need
Grpc.Net.ClientFactory nuget package)
Then you can just request the IoC to inject
DemoService.DemoServiceClient whenever you need to consume the gRPC service.
Securing your gRPC server
You would never deploy a gRPC server (or any service) without securing it with TLS, so here is a quick overview of what needs to be done.
- In Server: Pass the server certificate (in
pfxform) to kestrel in
macOS does not support TLS over HTTP/2. So you will get an error if you try this. Alternatively you can use Docker.
- The client need to specify the
https://...endpoint and optionally pass the
cafile (if the server certificate is self-signed or signed using your own certification authority).
Go clone yourself
You can find all of these source code in github