チュートリアルを読んだところ、.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"
コンソールにエラーが出力されない
--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.cs
とTestGrpc.cs
があります。
これを見つける他の人のためのここでのアイドルコメント、これに関するドキュメンテーションはひどく時代遅れであり、完全に間違っています。
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);
}
}
}
}