gRPC 共通プロジェクトの分離と実装

本記事では、gRPCでの共通プロジェクトの分離方法について説明します。具体的には、annotations.protoやhttp.protoファイルをサーバーおよびクライアントで共有するための手法を取り上げます。

共通プロジェクトの設定

以下は、共通プロジェクトの.csprojファイルの例です。この設定により、必要なパッケージがインストールされます。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.70.0" />
  </ItemGroup>
</Project>

プロトコルバッファ定義

次に、プロトコルバッファファイル(.proto)の例を示します。ここでは、学生情報の取得サービスを定義しています。

syntax = "proto3";
option csharp_namespace = "StudentServiceLib";

package student;

import "google/api/annotations.proto";

service StudentInfoService {
  rpc FetchStudent (SearchRequest) returns (SearchResponse) {
    option (google.api.http) = {
      get: "/v1/students/{keyword}"
    };
  }
}

message SearchRequest {
  string keyword = 1;
}

message SearchResponse {
  repeated Student students = 1;
}

message Student {
  string id = 1;
  string name = 2;
}

サービス実装

以下は、上記のプロトコルバッファに基づくgRPCサービスの実装例です。

using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using System.Collections.Generic;
using System.Linq;

namespace StudentServiceLib
{
    public class StudentInfoServiceImpl : StudentInfoService.StudentInfoServiceBase
    {
        private static readonly List<Student> _students = new() 
        { 
            new() { Id = "S001", Name = "太郎" }, 
            new() { Id = "S002", Name = "花子" } 
        };

        public override Task<SearchResponse> FetchStudent(SearchRequest request, ServerCallContext context)
        {
            var filteredStudents = _students.Where(s => s.Name.Contains(request.Keyword)).ToList();
            return Task.FromResult(new SearchResponse { Students = { filteredStudents } });
        }
    }
}

WebAPIプロジェクトの設定

WebAPIプロジェクトでは、以下の.csprojファイルを使用します。

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Google.Api.CommonProtos" Version="2.16.0" />
    <PackageReference Include="Grpc.AspNetCore" Version="2.70.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Common\SharedGrpcProject.csproj" />
  </ItemGroup>

  <ItemGroup>
    <Protobuf Include="StudentInfoService.proto">
      <AdditionalImportDirs>../../Common</AdditionalImportDirs>
    </Protobuf>
  </ItemGroup>
</Project>

クライアント側の実装

最後に、クライアント側の実装例を示します。

using Grpc.Net.Client;
using Microsoft.AspNetCore.Mvc;
using StudentServiceLib;

namespace ClientApp.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class StudentController : ControllerBase
    {
        [HttpGet("{query}")]
        public IActionResult Get(string query)
        {
            var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var client = new StudentInfoService.StudentInfoServiceClient(channel);
            var response = client.FetchStudent(new SearchRequest { Keyword = query });

            return Ok(response.Students);
        }
    }
}

クライアントプロジェクトの設定

クライアントプロジェクトでは、以下のような.csprojファイルを使用します。

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Grpc.Net.Client" Version="2.70.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Common\SharedGrpcProject.csproj" />
  </ItemGroup>

  <ItemGroup>
    <Protobuf Include="StudentInfoService.proto" GrpcServices="Client">
      <AdditionalImportDirs>../../Common</AdditionalImportDirs>
    </Protobuf>
  </ItemGroup>
</Project>

タグ: gRPC C# protobuf

7月18日 00:13 投稿