Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC C# plugin.
If you want to run this yourself, make sure you've installed protoc and gRPC C# plugin. The instructions vary based on your OS:
- For Windows, the `Grpc.Tools` NuGet package contains the binaries you will need to generate the code.
- For Windows, the `Grpc.Tools`and `Google.Protobuf`NuGet packages contain the binaries you will need to generate the code.
- For Linux, make sure you've [installed gRPC C Core using Linuxbrew](https://github.com/grpc/grpc/tree/master/src/csharp#usage-linux-mono)
- For MacOS, make sure you've [installed gRPC C Core using Homebrew](https://github.com/grpc/grpc/tree/master/src/csharp#usage-macos-mono)
Once that's done, the following command can be used to generate the C# code.
To generate the code on Windows, we use `protoc.exe`and `grpc_csharp_plugin.exe` binaries that are shipped with the `Grpc.Tools` NuGet package under the `tools` directory.
To generate the code on Windows, we use `protoc.exe`from the `Google.Protobuf` NuGet package and `grpc_csharp_plugin.exe` from the `Grpc.Tools` NuGet package (both under the `tools` directory).
Normally you would need to add the `Grpc.Tools` package to the solution yourself, but in this tutorial it has been already done for you. Following command should be run from the `csharp/route_guide` directory:
On Linux/MacOS, we rely on `protoc` and `grpc_csharp_plugin` being installed by Linuxbrew/Homebrew. Run this command from the route_guide directory:
...
...
@@ -143,7 +143,7 @@ public class RouteGuideImpl : RouteGuide.IRouteGuide
`RouteGuideImpl` implements all our service methods. Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`.
@@ -191,8 +178,8 @@ As you can see, here the request object is a `Rectangle` in which our client wan
Similarly, the client-side streaming method `RecordRoute` uses an [IAsyncEnumerator](https://github.com/Reactive-Extensions/Rx.NET/blob/master/Ix.NET/Source/System.Interactive.Async/IAsyncEnumerator.cs), to read the stream of requests using the async method `MoveNext` and the `Current` property.
Console.WriteLine("RouteGuide server listening on port "+port);
...
...
@@ -275,14 +257,13 @@ Console.WriteLine("Press any key to stop the server...");
Console.ReadKey();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
```
As you can see, we build and start our server using `Grpc.Core.Server` class. To do this, we:
1. Create an instance of `Grpc.Core.Server`.
1. Create an instance of our service implementation class `RouteGuideImpl`.
3. Register our service implementation with the server using the `AddServiceDefinition` method and the generated method `RouteGuide.BindService`.
2. Specify the address and port we want to use to listen for client requests using the `AddListeningPort` method.
3. Register our service implementation by adding its service definition to `Services` collection (We obtain the service definition from the generated `RouteGuide.BindService` method).
2. Specify the address and port we want to use to listen for client requests. This is done by adding `ServerPort` to `Ports` collection.
4. Call `Start` on the server instance to start an RPC server for our service.
<aname="client"></a>
...
...
@@ -294,19 +275,15 @@ In this section, we'll look at creating a C# client for our `RouteGuide` service
To call service methods, we first need to create a *stub*.
First, we need to create a gRPC client channel that will connect to gRPC server. Then, we use the `RouteGuide.NewStub` method of the `RouteGuide` class generated from our .proto.
First, we need to create a gRPC client channel that will connect to gRPC server. Then, we use the `RouteGuide.NewClient` method of the `RouteGuide` class generated from our .proto.
@@ -349,17 +326,17 @@ using (var call = client.ListFeatures(request))
```
The client-side streaming method `RecordRoute` is similar, except we use the property `RequestStream` to write the requests one by one using `WriteAsync` and eventually signal that no more request will be send using `CompleteAsync`. The method result can be obtained through the property
`Result`.
`ResponseAsync`.
```csharp
using(varcall=client.RecordRoute())
{
foreach(varpointinpoints)
{
{
awaitcall.RequestStream.WriteAsync(point);
}
awaitcall.RequestStream.CompleteAsync();
RouteSummarysummary=awaitcall.Result;
RouteSummarysummary=awaitcall.ResponseAsync;
}
```
...
...
@@ -374,7 +351,7 @@ Finally, let's look at our bidirectional streaming RPC `RouteChat`. In this case
{
varnote=call.ResponseStream.Current;
Console.WriteLine("Received "+note);
}
}
});
foreach(RouteNoterequestinrequests)
...
...
@@ -382,7 +359,7 @@ Finally, let's look at our bidirectional streaming RPC `RouteChat`. In this case