How to get grpc to throw the original exception like WCF does?

Sos*_*der 6 c# .net-core grpc

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);
}
Run Code Online (Sandbox Code Playgroud)

Server:

public async Task<Greeting> Greet()
{
    throw new ArgumentException();
}
Run Code Online (Sandbox Code Playgroud)

Running this, the following RpcException is raised:

Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler.")'
Run Code Online (Sandbox Code Playgroud)

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); 
Run Code Online (Sandbox Code Playgroud)

Result:

Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler. ArgumentException: Value does not fall within the expected range.")'
Run Code Online (Sandbox Code Playgroud)

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?

Ang*_*ang 6

您可以设置拦截器来捕获服务器端异常,序列化异常元数据,并将其打包到自定义的RpcException. 客户端可以反序列化元数据RpcException并重新创建异常。

这是我发现的一篇博客文章,详细介绍了该过程:ASP gRPC Custom Error Handling

正如您可以想象的那样,缺点是需要对每个异常执行此操作。我也一直在研究同样的问题,但没有找到任何直接的方法来将其应用于所有异常。

配置拦截器:

services.AddGrpc(options => 
{
    options.Interceptors.Add<GRPCInterceptor>();     
});
Run Code Online (Sandbox Code Playgroud)

简单的拦截器:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)