This is a tutorial on how to implement and test unary methods on a gRPC service using C#/.NET.
Introduction
gRPC is a modern, open source, high performance RPC (remote-procedure-call) framework. It runs on all platforms (Windows, Mac and Linux) and is supported on all major programming languages. As with all RPC programming models, it hides away the networking aspect of the call and makes it appear as if it is a normal, in-process function call.
Due to the performance benefits of gRPC over HTTP-based REST APIs, it is widely used in scenarios where performance is a high priority, such as when processing high data loads, or when there is a need for real-time data streaming. A common architecture adopted by various organizations is to have a public-facing HTTP/REST API (for maximum interoperability) that is backed internally by gRPC microservices (for maximum performance).
Service Definitions and Protobuf
Similar to WCF (Windows Communication Foundation), gRPC relies on service definitions to specify what methods and data types are exposed by the service. Service definitions in gRPC are written in protocol buffers (or protobuf for short) whereas in WCF, a WSDL is used.
An example of a protobuf service definition is shown below. It defines a service named HelloService
which has a single method called SayHello
. SayHello
accepts a request parameter of type HelloRequest
and returns a response of type HelloResponse
.
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string greeting = 1;
}
message HelloResponse {
string reply = 1;
}
Unary Methods
Unary methods are rpc (remote-procedure-call) calls wherein for every request, a response is sent back. It’s a lot similar to the normal function calls that we all write in our code except that for gRPC, the calls go over the network. In the above service definition, SayHello
is a unary method.
Implementation (Server)
To create a gRPC project, fire up Visual Studio and run the project template ASP.NET Core gRPC Service. By default, dotnet creates a greet.proto file which contains the service definition of the generated GreeterService
class. The content of this greet.proto file is similar to the service definition a few paragraphs above.
Let’s create a second Unary method called GetCustomerByName
by editing the greet.proto file:
syntax = "proto3";
option csharp_namespace = "GrpcUnary";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
rpc GetCustomerByName (GetCustomerRequest) returns (GetCustomerResponse);
}
message GetCustomerRequest {
string namePrefix = 1;
}
message GetCustomerResponse {
repeated Customer customer = 1;
}
message Customer {
string firstName = 1;
string lastName = 2;
int32 age = 3;
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Press Ctrl-Shift-B to build the solution. If there are no errors in the proto file, the build should be successful.
Now that we have modified the service definition to include the GetCustomerByName
method, we can go ahead and implement it in code. Open up GreeterService.cs and add an override for the method. Let's simulate a call to a Customers
DB and - when a record is not found, we'll throw an RPC exception with a status code of NotFound
.
public override async Task<GetCustomerResponse> GetCustomerByName
(GetCustomerRequest request, ServerCallContext context)
{
var matched = _customers.Where(c => c.FirstName.StartsWith(request.NamePrefix));
if (matched.Any())
{
var response = new GetCustomerResponse();
response.Customers.AddRange(matched);
return response;
}
throw new RpcException(new Status(StatusCode.NotFound,
$"Unable to find a customer with a first name starting with {request.NamePrefix}"));
}
Press F5 to run the service and take note of the port where it is running.
Test the Method
Now that the service is running, let’s fire up FintX (https://github.com/namigop/FintX) to verify that the service is working fine. FintX is an open-source, native, and cross-platform gRPC client. I’m on Windows, so I have installed the windows package (macOS and Linux downloads are also available).
Click on the plus icon to add a client. The value entered in the http address should match the running service.
Open GetCustomerByName
method and edit the request. Double-click on the NamePrefix
node to edit it, then click the Run button.
Give the NamePrefix
some invalid value to verify that indeed an RPC exception is thrown with a NotFound
status code.
Conclusion
In this tutorial post, you've seen how to implement and test unary methods in a gRPC service. They are quite easy and straightforward to implement.
History
- 20th February, 2024: Initial version