ASP.NET Core 6: Handling gRPC exception correctly server side
What an interesting subject! When we develop applications, it is necessary to manage errors well, that is to say that we must intercept them, log them and control the error message to the client in order to give him the exact time on what happened on the server side. In this article, we will see together how to use gRPC Interceptors to handle errors in the most efficient way (it is also the best practice to follow).
gRPC offers Interceptors, a kind of middleware that intercepts requests before they are sent to the client. To create an Interceptor, you will have to inherit from the Interceptor class and implement its interceptor for each type of gRPC request:
- Unary requests: UnaryServerHandler method
- Client streaming requests: ClientStreamingServerHandler method
- Server streaming requests: ServerStreamingServerHandler method
- Bi-directional streaming requests: DuplexStreamingServerHandler method
Each executes a delegate passed as a parameter named continuation to allow the execution of the current request to continue. The UnaryServerHandler and ClientStreamingServerHandler methods return a Task<Response> since the gRPC Unary and ClientStreaming service types return a message to the client. ServerStreamingServerHandler and DuplexStreamingServerHandler methods which return a Task and not a message at the end of the response since the services of type ServerStreaming and Bi-directional (Duplex) do not return a message. Each executes a delegate passed as a parameter to allow the execution of the current request to continue.
Before finishing the implementation of the interceptor, I suggest you create a static class, filled with method extensions, each managing a specific type of exception. For example, we can handle exceptions of type:
There are of course a whole bunch of types of exceptions, which you can find here if you wish: https://www.completecsharptutorial.com/basic/complete-system-exception.php.
For each method handling a very specific type of error, we go:
- Create a CorrelationId that we will include in the logs.
- Log the exception as well as a custom message with a CorrelationId.
- Return an RpcException with the correct gRPC status code (depends on the type of exception handled).
In the case of a RpcException, we will log the error, create a CorrelationId and rethrow the error without changing the status.
It gives the following:
After creating a Guid as CorrelationId in the its constructor and injecting ILogger<T> within, here is the final implementation of the ExceptionInterceptor class:
Don’t forget to register your Interceptor as follow:
Now let’s try it out!
In the following demo I will be using gRPCUI, a web tool that allows you to execute gRPC endpoints and see the result in a HTML page. To learn more about it you can visit my post here: https://anthonygiretti.com/2021/01/17/grpc-asp-net-core-5-discover-grpcui-the-gui-alternative-to-grpcurl/.
Let’s consider we faced a Timeout, while running our gRPC service, (a TimeoutException has been raised), we have generated a CorrelationId, the following code should run:
And give the following output:
It think it’s the best way to handle exceptions, if you wanna give your opinion, please leave me a comment ! 🙂