I was wondering whether there is a way to have Grpc .Net Core throw the original exception of the server side back to the client.
The problem is the following. When calling a grpc service, for example:
Client:
using (var channel = GrpcChannel.ForAddress("http://localhost:10042"))
{
var greeterService = channel.CreateGrpcService<IGreetService>();
var result = await greeterService.Greet();
Console.WriteLine(result.Greet);
}
Server:
public async Task<Greeting> Greet()
{
throw new ArgumentException();
}
Running this, the following RpcException is raised:
Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler.")'
Now, I would very much like to get this in a direction of actually raising an ArgumentException on the client side so this can be handled better.
What is possible, so I figured, is to do the following in my Startup.cs:
services.AddCodeFirstGrpc(options => options.EnableDetailedErrors = true);
Result:
Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler. ArgumentException: Value does not fall within the expected range.")'
That's better, but still not perfect.
My question is - Can I somehow raise the servers exception on the client side? Something I read up on was the fact that grpc allows "Interceptors" to intercept grpc calls. Is this a possibility to maybe do something here?
With WCF (Windows Communication Foundation) no longer being actively developed, gRPC (remote procedure call) appears to be the natural replacement when it comes to developing greenfield service applications on . NET Core and .
grpc itself is a protocol that can be transported over basically anything, but http1.
gRPC uses HTTP/2, which multiplexes multiple calls on a single TCP connection.
You can set up an Interceptor to catch server-side exceptions, serialize the exception metadata, and pack it into a custom RpcException
. The client can deserialize the metadata from the RpcException
and recreate the exception.
Here is a blog post I found that steps through the process: ASP gRPC Custom Error Handling
The downside, as you can imagine, is that this needs to be done for every exception. I've also been looking into the same question, and haven't found any straightforward ways to apply this to all exceptions.
Configure an interceptor:
services.AddGrpc(options =>
{
options.Interceptors.Add<GRPCInterceptor>();
});
Bare-bones interceptor:
public class GRPCInterceptor : Interceptor
{
private readonly ILogger logger;
public GRPCInterceptor(ILogger logger)
{
this.logger = logger;
}
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
logger.Debug($"starting call");
var response = await base.UnaryServerHandler(request, context, continuation);
logger.Debug($"finished call");
return response;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With