.NET의 gRPC 클라이언트 팩터리 통합

작성자: James Newton-King

HttpClientFactory와 gRPC 통합은 중앙에서 gRPC 클라이언트를 만드는 방법을 제공합니다. 독립 실행형 gRPC 클라이언트 인스턴스를 구성하는 대신 이 방법을 사용할 수 있습니다. 팩터리 통합은 Grpc.Net.ClientFactory NuGet 패키지에서 사용할 수 있습니다.

팩터리는 다음과 같은 이점을 제공합니다.

  • 논리적 gRPC 클라이언트 인스턴스를 구성하기 위한 중앙 위치를 제공합니다.
  • 기본 HttpClientMessageHandler의 수명을 관리합니다.
  • ASP.NET Core gRPC 서비스에서 최종 기한 및 취소를 자동 전파합니다.

gRPC 클라이언트 등록

gRPC 클라이언트를 등록하기 위해서 Program.cs의 앱 진입점에 있는 WebApplicationBuilder 인스턴스 내에서 gRPC 형식 클라이언트 클래스 및 서비스 주소를 지정하여 제네릭 AddGrpcClient 확장 메서드를 사용할 수 있습니다.

builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
    o.Address = new Uri("https://localhost:5001");
});

gRPC 클라이언트 형식은 DI(종속성 주입)를 사용하여 일시적으로 등록됩니다. 이제 클라이언트는 DI를 사용하여 만든 형식으로 직접 주입하고 사용할 수 있습니다. ASP.NET Core MVC 컨트롤러, SignalR 허브 및 gRPC 서비스는 gRPC 클라이언트가 자동으로 주입될 수 있는 위치입니다.

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(Greeter.GreeterClient client)
    {
        _client = client;
    }

    public override async Task SayHellos(HelloRequest request,
        IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        // Forward the call on to the greeter service
        using (var call = _client.SayHellos(request))
        {
            await foreach (var response in call.ResponseStream.ReadAllAsync())
            {
                await responseStream.WriteAsync(response);
            }
        }
    }
}

HttpHandler 구성

HttpClientFactory는 gRPC 클라이언트에서 사용하는 HttpMessageHandler를 만듭니다. 표준 HttpClientFactory 메서드는 나가는 요청 미들웨어를 추가하거나 HttpClient의 기본 HttpClientHandler를 구성하는 데 사용할 수 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ClientCertificates.Add(LoadCertificate());
        return handler;
    });

자세한 내용은 IHttpClientFactory를 사용하여 HTTP 요청 만들기를 참조하세요.

인터셉터 구성

gRPC 인터셉터는 AddInterceptor 메서드를 사용하여 클라이언트에 추가할 수 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>();

앞의 코드가 하는 역할은 다음과 같습니다.

  • GreeterClient 형식을 등록합니다.
  • 이 클라이언트에 대한 LoggingInterceptor를 구성합니다. LoggingInterceptor는 한 번 만들어지고 GreeterClient 인스턴스 간에 공유됩니다.

기본적으로 인터셉터를 한 번 만들어져 클라이언트 간에 공유됩니다. 인터셉터를 등록할 때 범위를 지정하여 이 동작을 재정의할 수 있습니다. InterceptorScope.Client를 지정하여 각 클라이언트마다 새 인터셉터를 만들도록 클라이언트 팩터리를 구성할 수 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);

범위가 지정된 클라이언트 인터셉터를 만드는 것은 인터셉터에 DI에서 범위가 지정된 서비스 또는 임시 서비스가 필요한 경우에 유용합니다.

gRPC 인터셉터 또는 채널 자격 증명을 사용하여 각 요청과 함께 Authorization 메타데이터를 보낼 수 있습니다. 인증 구성에 대한 자세한 내용은 gRPC 클라이언트 팩터리를 사용하여 전달자 토큰 보내기를 참조하세요.

채널 구성

ConfigureChannel 메서드를 사용하여 채널에 추가 구성을 적용할 수 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

ConfigureChannelGrpcChannelOptions 인스턴스에 전달됩니다. 자세한 내용은 클라이언트 옵션 구성을 참조하세요.

참고 항목

일부 속성은 ConfigureChannel 콜백이 실행되기 전에 GrpcChannelOptions에 설정됩니다.

이러한 값은 ConfigureChannel로 재정의할 수 있습니다.

호출 자격 증명

AddCallCredentials 메서드를 사용하여 gRPC 호출에 인증 헤더를 추가할 수 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddCallCredentials((context, metadata) =>
    {
        if (!string.IsNullOrEmpty(_token))
        {
            metadata.Add("Authorization", $"Bearer {_token}");
        }
        return Task.CompletedTask;
    });

호출 자격 증명 구성에 대한 자세한 내용은 gRPC 클라이언트 팩터리를 사용한 전달자 토큰을 참조하세요.

최종 기한 및 취소 전파

gRPC 서비스에서 팩터리로 만든 gRPC 클라이언트는 최종 기한 및 취소 토큰을 자식 호출에 자동으로 전파하도록 EnableCallContextPropagation()를 사용하여 구성할 수 있습니다. EnableCallContextPropagation() 확장 메서드는 Grpc.AspNetCore.Server.ClientFactory NuGet 패키지에서 사용할 수 있습니다.

호출 컨텍스트 전파는 현재 gRPC 요청 컨텍스트에서 최종 기한 및 취소 토큰을 읽고 gRPC 클라이언트에서 수행한 나가는 호출에 자동으로 전파하는 방식으로 작동합니다. 호출 컨텍스트 전파는 복잡한 중첩 gRPC 시나리오가 항상 최종 기한 및 취소를 전파하도록 하는 유용한 방법입니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation();

기본적으로 클라이언트를 gRPC 호출 컨텍스트의 외부에서 사용하는 경우 EnableCallContextPropagation 오류가 발생합니다. 이 오류는 전파할 호출 컨텍스트가 없다는 경고를 표시하기 위한 것입니다. 호출 컨텍스트 외부에서 클라이언트를 사용하려는 경우 SuppressContextNotFoundErrors를 사용하여 클라이언트를 구성하면 오류가 표시되지 않습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

최종 기한 및 RPC 취소에 대한 자세한 내용은 최종 기한 및 취소를 사용하는 안정적인 gRPC 서비스를 참조하세요.

명명된 클라이언트

일반적으로 gRPC 클라이언트 형식은 한 번 등록된 다음, DI를 통해 형식의 생성자에 직접 삽입됩니다. 그러나 하나의 클라이언트에 대해 여러 구성을 사용하는 것이 유용한 시나리오가 있습니다. 예를 들어, gRPC를 호출할 때 인증을 사용하거나 사용하지 않는 클라이언트가 있습니다.

각 클라이언트에 이름을 지정하여 동일한 형식의 여러 클라이언트를 등록할 수 있습니다. 명명된 각 클라이언트에는 자체 구성을 지정할 수 있습니다. 제네릭 AddGrpcClient 확장 메서드에는 name 매개 변수를 포함하는 오버로드가 있습니다.

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>("Greeter", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    });

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>("GreeterAuthenticated", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

앞의 코드가 하는 역할은 다음과 같습니다.

  • GreeterClient 형식을 두 번 등록하고 각각에 고유한 이름을 지정합니다.
  • 명명된 각 클라이언트에 대해 서로 다른 설정을 구성합니다. GreeterAuthenticated 등록은 자격 증명이 있는 gRPC 호출이 인증되도록 채널에 자격 증명을 추가합니다.

명명된 gRPC 클라이언트는 GrpcClientFactory를 사용하여 앱 코드에서 만들어집니다. 원하는 클라이언트의 형식과 이름은 제네릭 GrpcClientFactory.CreateClient 메서드를 사용하여 지정됩니다.

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(GrpcClientFactory grpcClientFactory)
    {
        _client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
    }
}

추가 리소스

HttpClientFactory와 gRPC 통합은 중앙에서 gRPC 클라이언트를 만드는 방법을 제공합니다. 독립 실행형 gRPC 클라이언트 인스턴스를 구성하는 대신 이 방법을 사용할 수 있습니다. 팩터리 통합은 Grpc.Net.ClientFactory NuGet 패키지에서 사용할 수 있습니다.

팩터리는 다음과 같은 이점을 제공합니다.

  • 논리적 gRPC 클라이언트 인스턴스를 구성하기 위한 중앙 위치를 제공합니다.
  • 기본 HttpClientMessageHandler의 수명을 관리합니다.
  • ASP.NET Core gRPC 서비스에서 최종 기한 및 취소 자동 전파

gRPC 클라이언트 등록

gRPC 클라이언트를 등록하기 위해서 Startup.ConfigureServices에서 gRPC 형식 클라이언트 클래스 및 서비스 주소를 지정하여 제네릭 AddGrpcClient 확장 메서드를 사용할 수 있습니다.

services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
    o.Address = new Uri("https://localhost:5001");
});

gRPC 클라이언트 형식은 DI(종속성 주입)를 사용하여 일시적으로 등록됩니다. 이제 클라이언트는 DI를 사용하여 만든 형식으로 직접 주입하고 사용할 수 있습니다. ASP.NET Core MVC 컨트롤러, SignalR 허브 및 gRPC 서비스는 gRPC 클라이언트가 자동으로 주입될 수 있는 위치입니다.

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(Greeter.GreeterClient client)
    {
        _client = client;
    }

    public override async Task SayHellos(HelloRequest request,
        IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        // Forward the call on to the greeter service
        using (var call = _client.SayHellos(request))
        {
            await foreach (var response in call.ResponseStream.ReadAllAsync())
            {
                await responseStream.WriteAsync(response);
            }
        }
    }
}

HttpHandler 구성

HttpClientFactory는 gRPC 클라이언트에서 사용하는 HttpMessageHandler를 만듭니다. 표준 HttpClientFactory 메서드는 나가는 요청 미들웨어를 추가하거나 HttpClient의 기본 HttpClientHandler를 구성하는 데 사용할 수 있습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        var handler = new HttpClientHandler();
        handler.ClientCertificates.Add(LoadCertificate());
        return handler;
    });

자세한 내용은 IHttpClientFactory를 사용하여 HTTP 요청 만들기를 참조하세요.

인터셉터 구성

gRPC 인터셉터는 AddInterceptor 메서드를 사용하여 클라이언트에 추가할 수 있습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>();

앞의 코드가 하는 역할은 다음과 같습니다.

  • GreeterClient 형식을 등록합니다.
  • 이 클라이언트에 대한 LoggingInterceptor를 구성합니다. LoggingInterceptor는 한 번 만들어지고 GreeterClient 인스턴스 간에 공유됩니다.

기본적으로 인터셉터를 한 번 만들어져 클라이언트 간에 공유됩니다. 인터셉터를 등록할 때 범위를 지정하여 이 동작을 재정의할 수 있습니다. InterceptorScope.Client를 지정하여 각 클라이언트마다 새 인터셉터를 만들도록 클라이언트 팩터리를 구성할 수 있습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .AddInterceptor<LoggingInterceptor>(InterceptorScope.Client);

범위가 지정된 클라이언트 인터셉터를 만드는 것은 인터셉터에 DI에서 범위가 지정된 서비스 또는 임시 서비스가 필요한 경우에 유용합니다.

gRPC 인터셉터 또는 채널 자격 증명을 사용하여 각 요청과 함께 Authorization 메타데이터를 보낼 수 있습니다. 인증 구성에 대한 자세한 내용은 gRPC 클라이언트 팩터리를 사용하여 전달자 토큰 보내기를 참조하세요.

채널 구성

ConfigureChannel 메서드를 사용하여 채널에 추가 구성을 적용할 수 있습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

ConfigureChannelGrpcChannelOptions 인스턴스에 전달됩니다. 자세한 내용은 클라이언트 옵션 구성을 참조하세요.

참고 항목

일부 속성은 ConfigureChannel 콜백이 실행되기 전에 GrpcChannelOptions에 설정됩니다.

이러한 값은 ConfigureChannel로 재정의할 수 있습니다.

최종 기한 및 취소 전파

gRPC 서비스에서 팩터리로 만든 gRPC 클라이언트는 최종 기한 및 취소 토큰을 자식 호출에 자동으로 전파하도록 EnableCallContextPropagation()를 사용하여 구성할 수 있습니다. EnableCallContextPropagation() 확장 메서드는 Grpc.AspNetCore.Server.ClientFactory NuGet 패키지에서 사용할 수 있습니다.

호출 컨텍스트 전파는 현재 gRPC 요청 컨텍스트에서 최종 기한 및 취소 토큰을 읽고 gRPC 클라이언트에서 수행한 나가는 호출에 자동으로 전파하는 방식으로 작동합니다. 호출 컨텍스트 전파는 복잡한 중첩 gRPC 시나리오가 항상 최종 기한 및 취소를 전파하도록 하는 유용한 방법입니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation();

기본적으로 클라이언트를 gRPC 호출 컨텍스트의 외부에서 사용하는 경우 EnableCallContextPropagation 오류가 발생합니다. 이 오류는 전파할 호출 컨텍스트가 없다는 경고를 표시하기 위한 것입니다. 호출 컨텍스트 외부에서 클라이언트를 사용하려는 경우 SuppressContextNotFoundErrors를 사용하여 클라이언트를 구성하면 오류가 표시되지 않습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation(o => o.SuppressContextNotFoundErrors = true);

최종 기한 및 RPC 취소에 대한 자세한 내용은 최종 기한 및 취소를 사용하는 안정적인 gRPC 서비스를 참조하세요.

명명된 클라이언트

일반적으로 gRPC 클라이언트 형식은 한 번 등록된 다음, DI를 통해 형식의 생성자에 직접 삽입됩니다. 그러나 하나의 클라이언트에 대해 여러 구성을 사용하는 것이 유용한 시나리오가 있습니다. 예를 들어, gRPC를 호출할 때 인증을 사용하거나 사용하지 않는 클라이언트가 있습니다.

각 클라이언트에 이름을 지정하여 동일한 형식의 여러 클라이언트를 등록할 수 있습니다. 명명된 각 클라이언트에는 자체 구성을 지정할 수 있습니다. 제네릭 AddGrpcClient 확장 메서드에는 name 매개 변수를 포함하는 오버로드가 있습니다.

services
    .AddGrpcClient<Greeter.GreeterClient>("Greeter", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    });

services
    .AddGrpcClient<Greeter.GreeterClient>("GreeterAuthenticated", o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .ConfigureChannel(o =>
    {
        o.Credentials = new CustomCredentials();
    });

앞의 코드가 하는 역할은 다음과 같습니다.

  • GreeterClient 형식을 두 번 등록하고 각각에 고유한 이름을 지정합니다.
  • 명명된 각 클라이언트에 대해 서로 다른 설정을 구성합니다. GreeterAuthenticated 등록은 자격 증명이 있는 gRPC 호출이 인증되도록 채널에 자격 증명을 추가합니다.

명명된 gRPC 클라이언트는 GrpcClientFactory를 사용하여 앱 코드에서 만들어집니다. 원하는 클라이언트의 형식과 이름은 제네릭 GrpcClientFactory.CreateClient 메서드를 사용하여 지정됩니다.

public class AggregatorService : Aggregator.AggregatorBase
{
    private readonly Greeter.GreeterClient _client;

    public AggregatorService(GrpcClientFactory grpcClientFactory)
    {
        _client = grpcClientFactory.CreateClient<Greeter.GreeterClient>("GreeterAuthenticated");
    }
}

추가 리소스