C#에서 gRPC 서버를 구현하려고했습니다.

C #에서 gRPC 서버를 구현하려고했습니다.



소개



배경



학생의 프로젝트로, Apiary나 Swagger등의 API 문서 툴을 이용하고 있었지만, 규모가 커질수록 편집이 귀찮다구나라고 느끼고 있었다.
↓이런 느낌의 yaml을 계속 써

그렇게 생각했을 때 만난 것이 gRPC이다.

gRPC란?



gRPC는 RPC(Remote Procedure Call)를 실현하기 위해 Google에서 개발한 프로토콜 중 하나입니다. Protocol Buffers를 사용하여 데이터를 직렬화하고 고속 통신을 실현할 수 있는 점이 특징입니다.
ref: gRPC는 무엇입니까?

그렇지만 정말로 좋다고 생각한 것은 여기가 아니다!



gRPC에서는 IDL(인터페이스 정의 언어)을 사용하여 미리 API 사양을 .proto 파일로 정의하고 거기에서 서버측 및 클라이언트측에 필요한 소스 코드의 편지지를 생성합니다.



이런 proto 파일을 정의해 주면, API 문서의 생성, Client&Server용의 코드를 자동 생성해 준다. 대단해!
데이터 교환의 로직 구현에 시간을 걸릴 수 없다는 것이 압도적 이점이라고 생각한다!
  • weather.proto
  • syntax = "proto3";
    
    package proto.weather;
    
    service Weathers{
        rpc Get (GetRequest) returns (GetResponse) {}
    }
    
    message Weather {
        double ID = 1;
        string CityName = 2;
        double TempMax = 3;
        double TempMin = 4;
        double Wind = 5;
        string Type = 6;
        string Description = 7;
    }
    
    message GetRequest {
        string CityName = 1;
    }
    
    message GetResponse {
        Weather Weather = 1;
    }
    

    개발 환경



    도구 등


  • OS: MacOS
  • Visual Studio: IDE
  • Dotnet SDK (2.2.103) : 컨테이너 이미지

  • bloomrpc : Postman처럼 GUI에서 API를 두드리는 어려운 도구
  • Docker for Mac

  • gRPC-Trainning : 이번에 사용할 리포지토리

  • C# 라이브러리


    <PackageReference Include="Dapper" Version="1.50.5" />
    <PackageReference Include="Google.Cloud.Language.V1" Version="1.1.0" />
    <PackageReference Include="Google.Protobuf" Version="3.6.1" />
    <PackageReference Include="Grpc" Version="1.18.0" />
    <PackageReference Include="Grpc.Core" Version="1.18.0" />
    <PackageReference Include="Grpc.Tools" Version="1.18.0">
    

    구체적인 구현



    사전 준비


  • MacOS에 proto 파일을 다른 언어로 컴파일하기위한 도구와 플러그인을 넣는 것
    ↓매우 알기 쉽습니다
    ref: C#에서 gRPC 환경 만들기

  • 디렉토리 구성



    DDD풍으로 해 보았습니다.


    Application/Implements



    주로 여기에 RPC의 구현을 실시한다(ASP.NET Core의 Controller라고 생각해 주어 괜찮습니다!)
    흐름으로서는, 자동 생성된 파일을 기본 클래스로 상속합니다.
    그리고는 메소드를 오버라이드(override) 해, 로직을 써 가는 느낌.
  • Implements/WeatherImpl.cs
  • using Proto.Weather;
    using System.Threading.Tasks;
    using Grpc.Core;
    using WeatherApi.Application.Domain.Service.Interface;
    using System;
    
    namespace WeatherApi.Application.Implements
    {
        public class WeatherImpl: Weathers.WeathersBase
        {
            IWeatherService service;
            public WeatherImpl(IWeatherService _service) : base()
            {
                if (_service == null)
                {
                    throw new ArgumentNullException(nameof(IWeatherService));
                }
                this.service = _service;
            }
            public override Task<GetResponse> Get(GetRequest request, ServerCallContext context)
            {
                string cityName = request.CityName;
                var weathers = this.service.FindCurrentWeatherByCityName(cityName);
                var response = new GetResponse();
                response.Weather = weathers[0];
                return Task.FromResult(response);
            }
        }
    }
    

    Application/Program.cs



    Implements로 작성한 RPC를 Server에 Bind합니다.
    나머지 구현은 기존 웹 프레임워크와 다르지 않습니다.
    using System;
    using Microsoft.Extensions.Configuration;
    using WeatherApi.Application.Infrastructure;
    using Grpc.Core;
    using Proto.Weather;
    using Proto.User;
    using WeatherApi.Application.Implements;
    using WeatherApi.Application.Domain.Service;
    using Proto.Ping;
    
    namespace Application
    {
        public class Program
        {
            public static IConfigurationRoot configuration;
            public static SqlHandler sqlHandler;
            public static void Main(string[] args)
            {
                const int Port = 5000;
                var weatherImpl = new WeatherImpl(new WeatherService());
                var userImpl = new UserImpl(new UserService());
                var pingImpl = new PingImpl();
                Server server = new Server
                {
                    Services = { 
                        Weathers.BindService(weatherImpl),
                        Check.BindService(pingImpl),
                        Users.BindService(userImpl)
                    },
                    Ports = { new ServerPort("0.0.0.0", Port, ServerCredentials.Insecure) }
                };
                server.Start();
    
                Console.WriteLine("Tozawa server listening on port " + Port);
                Console.WriteLine("Press any key to stop the server...");
                Console.Read();
    
                server.ShutdownAsync().Wait();
            }
        }
    }
    

    설정


  • 프로젝트 파일 복제
  • git clone https://github.com/tozastation/gRPC-Training.git

  • gRPC 서버 시작
  • docker-compose build; docker-compose up grpc


  • 사용법


  • bloomrpc 시작 & 더하기 버튼에서 만든 proto 파일을 추가합니다
  • 나중에 json을 전달하는 것처럼 쓰기만하면됩니다.


  • 끝에



    C#의 gRPC 구현이 별로 없기 때문에
    이번 기사에서, C#에서의 gRPC 서버 구현 및 Debug 방법의 공유가 가능하면 무엇보다입니다!
    앞으로는 Interceptor(Middleware)의 구현도 하고 싶다
    절실히 문서가 늘어나길 바란다.

    좋은 웹페이지 즐겨찾기