Jak stworzyć klienta do API gRPC w .NET?
gRPC to całkiem nowy, bardzo wydajny interfejs (około 10 razy szybszy niż REST), stworzony przez Googla na licencji Open Source. Może działać w dowolnym środowisku. Jego implementacja została oparta na Protocol Buffers, czyli na mechanizmie serializacji danych, niezależnym od języka programowania. Bazuje na protokole HTTP/2, który wspiera dwukierunkowy streaming - połączenie jest podtrzymywane, a serwer i klient mogą wysyłać wiele żądań.
W tym artykule pokażę ci, w jaki sposób połączyć się z już istniejącym serwerem gRPC i wysłać pierwsze zapytania za pomocą C#. Za przykładowy serwer posłuży mi StabilitySDK.
Przygotowanie środowiska
Zacznij od utworzenia projektu. Do stworzenia klienta, najlepiej użyć szablon biblioteki.
Kolejny krokiem, jest dodanie kilku niezbędnych narzędzi, ułatwiających pracę z gRPC:
- Grpc.Tools - umożliwia generowanie kodu C# na podstawie plików proto
- Grpc.Net.Client - odpowiada za tworzenie kodu klienta bazując na plikach proto
- Google.Protobuf - dodaje rozszerzone typy danych używanych w protobuf (jest duża szansa, że twoje pliki proto będą takie zawierać)
- dotnet-grpc - narzędzie .NET, które umożliwia linkowanie plików proto; dodaj je do projektu za pomocą komendy:
dotnet tool install -g dotnet-grpc
Jeśli używasz Ridera polecam dodanie pluginu Protocol Buffers, który zapewni podstawową analizę składni.
Dodanie plików proto
W stworzonym projekcie załóż folder Protos. Następnie zdobądź link do pliku proto, który chcesz dodać do projektu. Na Githubie wygląda to następująco:
Otwórz plik proto, a następnie kliknij Raw, aby otrzymać czysty plik, bez interfejsu Githuba.
Skopiuj link. Kolejno otwórz terminal w miejscu, gdzie masz swój plik .csproj i użyj komendy o następującej strukturze:dotnet-grpc add-url <link-do-pliku-raw> -o <adres-do-pliku>
W moim wypadku wyglądało to tak:dotnet-grpc add-url https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/dashboard.proto -o ./Protos/dashboard.proto
Komenda dodaje link źródłowy do .csproj, pobiera kod z podlinkowanego pliku i zapisuje go w lokalizacji, podanej jako parametr wywołania komendy.
Po dodaniu plików proto w .csproj powinien pojawić się fragment podobny do przykładu poniżej:
<ItemGroup>
<Folder Include="Protos" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos/dashboard.proto" GrpcServices="Client">
<SourceUrl>https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/dashboard.proto</SourceUrl>
</Protobuf>
<Protobuf Include="Protos/engines.proto" GrpcServices="Client">
<SourceUrl>https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/engines.proto</SourceUrl>
</Protobuf>
<Protobuf Include="Protos/generation.proto" GrpcServices="Client">
<SourceUrl>https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/generation.proto</SourceUrl>
</Protobuf>
<Protobuf Include="Protos/project.proto" GrpcServices="Client">
<SourceUrl>https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/project.proto</SourceUrl>
</Protobuf>
<Protobuf Include="Protos/tensors.proto" GrpcServices="Client">
<SourceUrl>https://raw.githubusercontent.com/coreweave/tensorizer/35381e3812ba342991d30b71ce257503622ae828/proto/tensors.proto</SourceUrl>
</Protobuf>
</ItemGroup>
Zamiast używać instrukcji podanej wyżej, możesz go również wypełnić ręcznie, a następnie użyć komendy:dotnet-grpc refresh
Porównuje ona zawartość twoich plików proto z plikami źródłowymi i na tej podstawie wprowadza zmiany. Jeśli pliki proto nie istnieją, tworzy je.
Dodatkowo warto określić atrybut ProtoRoot dla wszystkich tagów Protobuf, w którym zdefiniujesz root dla plików proto. Jest to wymagane, jeśli pliki proto używają wewnątrz importów.
<Protobuf Include="Protos\dashboard.proto" GrpcServices="Client" ProtoRoot="Protos">
<SourceUrl>https://raw.githubusercontent.com/Stability-AI/api-interfaces/main/src/proto/dashboard.proto</SourceUrl>
</Protobuf>
Jeśli korzystasz z Ridera, możesz dodać do ustawień ścieżki importu plików proto. Nie wpływa to na działanie kodu, ale IDE nie będzie wtedy niepotrzebnie podkreślało importów jako błędne.
Wystarczy kliknąć komunikat, który pojawia się przy czerwonej żarówce.
Tworzenie klienta
Pierwszym krokiem jest zbudowanie projektu. Spowoduje to wygenerowanie kodu metod i typów opisanych w plikach proto.
Tworzenie klienta zacznij od utworzenia kanału. Służy on do nawiązywania długotrwałego połączenia z API.var channel = GrpcChannel.ForAddress(host);
Host jest adresem API, z którym się łączysz. Opcjonalnie możesz skonfigurować połączenie za pomocą GrpcChannelOptions:
var grpcChannelOptions = new GrpcChannelOptions() {
Credentials = ChannelCredentials.Create(ChannelCredentials.SecureSsl,
CallCredentials.FromInterceptor((_, metadata) => {
metadata.Add("Authorization", $"Bearer {apiKey}");
return Task.CompletedTask;
})
)
};
var channel = GrpcChannel.ForAddress(host, grpcChannelOptions);
W tym wypadku dodaję apiKey umożliwiające autoryzację oraz ustawiam poświadczenie, zapewniające bezpieczeństwo połączenia SSL, które było wymagane przez Stability API.
Pełne możliwości konfiguracji znajdziesz w dokumentacji.
Możesz używać już konkretnych serwisów. Zostały one wygenerowane na podstawie plików proto w projekcie. Nazwy serwisów będa się pokrywać z nazwami plików proto.
var engineService = new EnginesService.EnginesServiceClient(channel);
var engineList = engineService.ListEngines(new ListEnginesRequest());
W pierwszej linijce tworzę serwis, z pomocą wcześniej opisanego kanału. Serwis daje mi dostęp do wszystkich metod opisanych w plikach proto. Druga linijka jest przykładem zapytania do Stability API.
I gotowe
W ten sposób możesz się komunikować z serwerem gRPC przy pomocy wygenerowanego klienta. W przypadku gdy pliki proto się zmienią, wystarczy zrobić dotnet-grpc refresh, a następnie zbudować projekt.
PS Możesz zobaczyć bardziej rozbudowany, działający przykład na GitHubie.