Как заставить grp c генерировать исходное исключение, как это делает WCF? - PullRequest
4 голосов
/ 09 июля 2020

Мне было интересно, есть ли способ, чтобы Grp c. Net Core возвращал клиенту исходное исключение на стороне сервера.

Проблема в следующем. При вызове службы grp c, например:

Клиент:

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.")'

Это лучше, но все же не идеально.

Мой вопрос - Могу ли я как-то поднять исключение серверов на стороне клиента? Я прочитал кое-что о том, что grp c позволяет «Перехватчикам» перехватывать вызовы grp c. Есть ли возможность здесь что-то сделать?

1 Ответ

1 голос
/ 17 июля 2020

Вы можете настроить Interceptor для перехвата серверных исключений, сериализации метаданных исключения и упаковки их в пользовательский RpcException. Клиент может десериализовать метаданные из RpcException и воссоздать исключение.

Вот сообщение в блоге, которое, как я обнаружил, проходит через весь процесс: ASP gRP C Пользовательская обработка ошибок

Обратной стороной, как вы понимаете, является то, что это нужно делать для каждого исключения. Я также изучал тот же вопрос и не нашел никаких простых способов применить это ко всем исключениям.

Настроить перехватчик:

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