web-dev-qa-db-ja.com

gRPCツールを使用してコードを生成する方法

チュートリアルを読んだところ、.csファイルを生成できましたが、サービスやrpcの定義が含まれていません。

protocをPATHに追加し、プロジェクトディレクトリ内から追加しました。

protoc project1.proto --csharp_out="C:\output" --plugin=protoc-gen-grpc="c:\Users\me\.nuget\packages\grpc.tools\1.8.0\tools\windows_x64\grpc_csharp_plugin.exe"

コンソールにエラーが出力されない

8
user3953989

--grpc_outコマンドラインオプションを追加する必要があります。追加

--grpc_out="C:\output\"

サービスがない場合、ファイルは書き込まれません。

これが完全な例です。ルートディレクトリから、以下を作成します。

  • 空のoutputディレクトリ
  • toolsディレクトリとprotoc.exeおよびgrpc_csharp_plugin.exe
  • 次に示すように、protosディレクトリにtest.protoが含まれています。

test.proto

syntax = "proto3";

service StackOverflowService {
  rpc GetAnswer(Question) returns (Answer);
}

message Question {
  string text = 1;
  string user = 2;
  repeated string tags = 3;
}

message Answer {
  string text = 1;
  string user = 2;
}

次に実行します(すべて1行で、ここでは読みやすくするために改行しています)。

tools\protoc.exe -I protos protos\test.proto --csharp_out=output
    --grpc_out=output --plugin=protoc-gen-grpc=tools\grpc_csharp_plugin.exe 

outputディレクトリには、Test.csTestGrpc.csがあります。

11
Jon Skeet

これを見つける他の人のためのここでのアイドルコメント、これに関するドキュメンテーションはひどく時代遅れであり、完全に間違っています。

Grpc.Toolsをインストールしても、packagesフォルダーには何もインストールされません。それは、もはや真実ではないレガシー動作ですWindowsでも

Grpc.Toolsをインストールすると、ローカルパッケージキャッシュに隠されます。これは、次の呼び出しで確認できます。

$ dotnet nuget locals all --list
info : http-cache: /Users/doug/.local/share/NuGet/v3-cache
info : global-packages: /Users/doug/.nuget/packages/
info : temp: /var/folders/xx/s2hnzbrj3yn4hp1bg8q9gb_m0000gn/T/NuGetScratch

必要なバイナリはtheseフォルダのいずれかにあります。

これを行う最も簡単な方法は、Grpc.Toolsパッケージをnugetから直接ダウンロードし、ローカルにインストールすることです。

私はこれを行うためにこの小さなヘルパースクリプトをハッキングしました。これは、windows/mac/linuxで動作します。

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Mono.Unix;

namespace BuildProtocol
{
  public class Program
  {
    private const string ToolsUrl = "https://www.nuget.org/api/v2/package/Grpc.Tools/";
    private const string Service = "Greeter";
    private static string ProtocolPath = Path.Combine("..", "protos");
    private static string Protocol = Path.Combine(ProtocolPath, "helloworld.proto");
    private static string Output = Path.Combine("..", "Greeter");

    public static void Main(string[] args)
    {
      RequireTools().Wait();

      var protoc = ProtocPath();
      var plugin = ProtocPluginPath();

      Console.WriteLine($"Using: {protoc}");
      Console.WriteLine($"Using: {plugin}");

      var command = new string[]
      {
        $"-I{ProtocolPath}",
        $"--csharp_out={Output}",
        $"--grpc_out={Output}",
        $"--plugin=protoc-gen-grpc=\"{plugin}\"",
        Protocol,
      };

      Console.WriteLine($"Exec: {protoc} {string.Join(' ', command)}");

      var process = new Process
      {
        StartInfo = new ProcessStartInfo
        {
          UseShellExecute = false,
          FileName = protoc,
          Arguments = string.Join(' ', command)
        }
      };

      process.Start();
      process.WaitForExit();

      Console.WriteLine($"Completed status: {process.ExitCode}");
    }

    public static async Task RequireTools()
    {
      if (!Directory.Exists("Tools"))
      {
        Console.WriteLine("No local tools found, downloading binaries from nuget...");
        Directory.CreateDirectory("Tools");
        await DownloadTools();
        ExtractTools();
      }
    }

    private static void ExtractTools()
    {
      ZipFile.ExtractToDirectory(Path.Combine("Tools", "tools.Zip"), Path.Combine("Tools", "bin"));
    }

    private static async Task DownloadTools()
    {
      using (var client = new HttpClient())
      {
        Console.WriteLine($"Fetching: {ToolsUrl}");
        using (var result = await client.GetAsync(ToolsUrl))
        {
          if (!result.IsSuccessStatusCode) throw new Exception($"Unable to download tools ({result.StatusCode}), check URL");
          var localArchive = Path.Combine("Tools", "tools.Zip");
          Console.WriteLine($"Saving to: {localArchive}");
          File.WriteAllBytes(localArchive, await result.Content.ReadAsByteArrayAsync());
        }
      }
    }

    private static string ProtocPath()
    {
      var path = Path.Combine("Tools", "bin", "tools", DetermineArch(), "protoc");
      RequireExecutablePermission(path);
      return WithExeExtensionIfRequired(path);
    }

    private static string ProtocPluginPath()
    {
      var path = Path.Combine("Tools", "bin", "tools", DetermineArch(), "grpc_csharp_plugin");
      RequireExecutablePermission(path);
      return WithExeExtensionIfRequired(path);
    }

    private static void RequireExecutablePermission(string path)
    {
      if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
      Console.WriteLine($"Ensuring +x on {path}");
      var unixFileInfo = new UnixFileInfo(path);
      unixFileInfo.FileAccessPermissions = FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | FileAccessPermissions.UserExecute;
    }

    private static string WithExeExtensionIfRequired(string path)
    {
      if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
      {
        path += ".exe";
      }

      return path;
    }

    private static string DetermineArch()
    {
      var Arch = RuntimeInformation.OSArchitecture;
      if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
      {
        return WithArch("windows_", Arch);
      }

      if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
      {
        return WithArch("macosx_", Arch);
      }

      if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
      {
        return WithArch("linux_", Arch);
      }

      throw new Exception("Unable to determine runtime");
    }

    private static string WithArch(string platform, Architecture Arch)
    {
      switch (Arch)
      {
        case Architecture.X64:
          return $"{platform}x86";
        case Architecture.X86:
          return $"{platform}x64";
        default:
          throw new ArgumentOutOfRangeException(nameof(Arch), Arch, null);
      }
    }
  }
}
5
Doug