[C#] .NET의 gRPC 서버 측 인터셉터

참고


Interceptor 란?

  • 인터셉터는 앱이 들어오는 또는 나가는 gRPC 호출과 상호 작용할 수 있도록 하는 gRPC 개념으로, 요청 처리 파이프라인을 보강하는 방법을 제공합니다.
  • 인터셉터는 채널 또는 서비스에 대해 구성되고 각 gRPC 호출에서 자동으로 실행됩니다.
  • 인터셉터는 사용자의 애플리케이션 논리에 투명하므로 로깅, 모니터링, 인증, 유효성 검사와 같은 공통 사례에 적합한 솔루션입니다.

Interceptor 형식

  • Interceptor 형식에서 상속되는 클래스를 만들어 gRPC 서버 및 클라이언트 모두에 대해 인터셉터를 구현할 수 있습니다.
public class ExampleInterceptor : Interceptor
{
}
  • 기본적으로, Interceptor 기본 클래스는 아무 동작도 하지 않습니다.
  • 인터셉터 구현에서 적절한 기본 클래스 메서드를 재정의 하여 인터셉터에 동작을 추가합니다.

gRPC 인터셉터 프로젝트 만들기

  • 실제로 예제 코드를 작성하여 인터셉터에 대한 이해를 높여 보도록 하겠습니다.
  • gRPC 예제 코드는 C# 프로젝트로 작성할 것이고, Server/Client 작성해 보겠습니다.


서버 측 인터셉터 작성

  • gRPC 서버 인터셉터는 들어오는 RPC 요청을 가로챕니다.

  • 들어오는 요청, 나가는 응답 및 클라이언트 쪽 호출의 컨텍스트에 대한 액세스를 제공합니다.

  • 서버에 대한 재정의할 Interceptor 메서드는 다음과 같습니다.

    • UnaryServerHandler : 단항 RPC를 가로챕니다.
    • ClientStreamingServerHandler : 클라이언트 스트리밍 RPC를 가로챕니다.
    • ServerStreamServerHandler : 서버 스트리밍 RPC를 가로챕니다.
    • DuplexStreamingServerHandler : 양방향 스트리밍 RPC를 가로챕니다.
  • 그럼 ASP.NET Core gRPC 서비스 프로젝트 하나를 생성 후, 인터셉터 내용을 작성해 보겠습니다.


gRPC 서비스 프로젝트 생성

  • Visual Studio 2022 를 실행 후, ASP.NET Core gRPC 서비스 프로젝트를 생성 후, ServerLoggingInterceptor 클래스를 생성합니다.
  • 그리고 아래와 같이 코드를 작성합니다.
  • 다음 코드는 Client 에서 Server 로 요청을 했을 때, 서버측에서 단항 RPC 를 가로채는 예제입니다.
using Grpc.Core;
using Grpc.Core.Interceptors;

namespace gRPCInterceptorSample.Interceptors
{
    public class ServerLoggingInterceptor : Interceptor
    {
        private readonly ILogger _logger;

        public ServerLoggingInterceptor(ILogger<ServerLoggingInterceptor> logger)
        {
            _logger = logger;
        }

        public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
            TRequest request,
            ServerCallContext context,
            UnaryServerMethod<TRequest, TResponse> continuation)
        {
            _logger.LogInformation($"Starting receiving call. Type: {MethodType.Unary}. " +
                $"Method: {context.Method}.");
            try
            {
                return await continuation(request, context);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error thrown by {context.Method}.");
                throw;
            }
        }
    }
}
  • ServerLoggingInterceptor 인터셉터의 역할은 Client 에서 Server 로 RPC 메서드로 특정 메시지를 요청 했을 때 ServerLoggingInterceptor 인터셉터가 해당 내용을 먼저 가로채서 내용을 보고 로그로 출력하는 역할을 합니다.

Interceptor 서비스 옵션 추가

  • 위에서 ServerLoggingInterceptor 라는 gRPC 서버 측 인터셉터를 구현하였습니다.
  • 이제 gRPC 서비스에서 ServerLoggingInterceptor 인터셉터 옵션을 추가해주어야 합니다.
  • 옵션을 추가하지 않으면, 인터셉터가 동작하지 않습니다.
  • Program.cs 코드에 다음과 같이 인터셉터 옵션을 추가합니다.
// Add services to the container.
builder.Services.AddGrpc(options =>
{
    options.Interceptors.Add<ServerLoggingInterceptor>();
});

Clinet gRPC 코드 작성

  • 앞서, 서버 측 인터셉터 코드를 작성하였습니다.
  • C# 콘솔 프로그램 생성 후, gRPC 클라이언트 프로그램을 구현 후 Server 측에게 RPC 메서드를 통해 메시지를 보낼 때, 실제로 인터셉터가 작동하여 RPC 메서드를 가로채는지 확인 진행합니다.
using Grpc.Net.Client;
using gRPCInterceptorSample;

using var channel = GrpcChannel.ForAddress("https://localhost:7081");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
    new HelloRequest { Name = "Beom" }
    );

Console.WriteLine($"Greeting {reply.Message}");

인터셉터 실행 결과

  • gRPC Server/Client 프로그램을 실행하고, 실제로 Client 가 Server 로 rpc 메서드로 메시지를 보낼 때, 인터셉터가 일어나는지 테스트 진행하였습니다.
  • 실행 결과, Client 가 Server 로 메시지를 보낼 떄 ServerLoggingInterceptor 인터셉터에서 먼저 request 내용을 가로채서 확인하는 것을 확인할 수 있습니다.
info: gRPCInterceptorSample.Interceptors.ServerLoggingInterceptor[0]
      Starting receiving call. Type: Unary. Method: /greet.Greeter/SayHello.
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY