In this post I will show how I created a gRPC based api using Asp.Net Core.
gRPC is a remote procedure call based framework for creating highly optimized api endpoints with focus on low network latency. Unlike rest where the api is explicitly url based, gRPC implementations abstract away the details of remote communication. Instead of explicitly specifying a remote address to a remote server when invoking a remote function, the api is invoked much like local functions.
The local api acts like a facade on top of the underlying implementation, but how does this get wired together?
Luckily for us, we don’t have to hand code any of the remote protocol implementation. Instead we can generate most of the code based on a standard called protocol buffers. Protocol buffers are basically language agnostic schema definitions that can be used for code generation.
I have included my sample protocol buffer file below:
As is often the case, my demos represent some feature I’m building for my blog.
In my schema definition I have included two service methods for saving and retrieving blog articles. This is the service I use when editing or creating new blog posts, like the one you are reading right now.
Each service method comes with a request/response object pair for defining the shape of the request and response payloads. The properties on the objects are typed with standard programming types, but what is the sequential number listed next to the properties? It turns out this number is just used for internal serialization, so we don’t really have to worry about it. Just make sure to avoid duplicates when specifying new properties.
Now, whenever we build the project, the protocol definitions will be converted to actual code that can be used to create our service implementation.
I have included the implementations of my two service methods below:
ArticleServiceBase is an example of generated code. The only custom code here is the MongoDB specific code for retrieving and saving articles.
I have included my web api methods below:
In order to call the remote procedure I have to set up a channel and create a client object that will give me the function to call. In this implementation I am re-creating the channel for every call, but there might be a more optimal way to handle this. I would appreciate any feedback on better patterns here.