如何使grpc像WCF一样抛出原始异常?

8

我想知道是否有一种方法可以让Grpc .Net Core将服务器端的原始异常抛回给客户端。

问题如下。当调用grpc服务时,例如:

客户端:

using (var channel = GrpcChannel.ForAddress("http://localhost:10042"))
{
    var greeterService = channel.CreateGrpcService<IGreetService>();
    var result = await greeterService.Greet();

    Console.WriteLine(result.Greet);
}

服务器:

public async Task<Greeting> Greet()
{
    throw new ArgumentException();
}

运行此代码,将会引发以下的RpcException异常:
Grpc.Core.RpcException: 'Status(StatusCode=Unknown, Detail="Exception was thrown by handler.")'

现在,我非常希望能够使其朝着在客户端引发 ArgumentException 的方向发展,以便更好地处理该问题。

据我所知,可以在 Startup.cs 中执行以下操作:

services.AddCodeFirstGrpc(options => options.EnableDetailedErrors = true); 

结果:

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

这已经更好了,但还不够完美。

我的问题是 - 我能否在客户端上提升服务器的异常?我所了解到的是,grpc允许“拦截器”来拦截grpc调用。这是可能在这里做些什么吗?


标准解决方案是使用status.proto来表示错误(以一种与语言无关的方式),并将错误详细信息编码为二进制响应尾部,作为您的错误响应:https://grpc.io/docs/guides/error/ - Jan Tattermusch
1个回答

6
你可以设置一个拦截器来捕获服务器端的异常,将异常元数据序列化并打包到自定义的RpcException中。客户端可以从RpcException中反序列化元数据并重新创建异常。
这里有一篇博客文章,详细介绍了该过程:ASP gRPC自定义错误处理
不过,缺点是需要针对每个异常都进行这样的操作。我也一直在寻找同样的问题,但没有找到任何简单的方法可以将其应用于所有异常。
配置一个拦截器:
services.AddGrpc(options => 
{
    options.Interceptors.Add<GRPCInterceptor>();     
});

基础拦截器:

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;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接