web-dev-qa-db-fra.com

Comment utiliser les outils gRPC pour générer du code

J'ai lu le tutoriel et je suis capable de générer le fichier .cs mais il n'inclut aucune de mes définitions de service ou rpc.

J'ai ajouté protoc à mon CHEMIN et à l'intérieur du répertoire du projet.

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"

Aucune erreur de sortie dans la console

8
user3953989

Vous devez ajouter le --grpc_out option de ligne de commande, par exemple ajouter

--grpc_out="C:\output\"

Notez qu'il n'écrira aucun fichier si vous n'avez aucun service.

Voici un exemple complet. À partir d'un répertoire racine, créez:

  • Un répertoire output vide
  • Un répertoire tools avec protoc.exe et grpc_csharp_plugin.exe
  • Un répertoire protos avec test.proto comme indiqué ci-dessous:

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;
}

Exécutez ensuite (le tout sur une seule ligne; je l'ai cassé juste pour plus de lisibilité ici):

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

Dans le répertoire output, vous trouverez Test.cs et TestGrpc.cs

11
Jon Skeet

Juste un commentaire inutile ici pour d'autres qui trouvent cela, la documentation à ce sujet est terriblement obsolète et tout simplement fausse.

Installation de Grpc.Tools n'installe rien dans un dossier de packages; c'est un comportement hérité qui n'est plus vrai même sur Windows.

Lorsque vous installez Grpc.Tools il sera caché dans le cache de votre package local, que vous pouvez voir en appelant:

$ 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

Les fichiers binaires que vous voulez seront dans l'un des dossiers these.

La façon la plus simple de procéder consiste à télécharger le Grpc.Tools package directement à partir de nuget, et installez-le localement.

J'ai piraté ce petit script d'aide pour le faire, qui fonctionne sur windows/mac/linux, ce qui peut faciliter la difficulté de commencer avec cela pour d'autres:

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