Skip to Content
Course content

74: gRPC Basics in .NET

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've spent most of your time building REST APIs, gRPC is going to feel like a bit of a culture shock. Instead of thinking in terms of "endpoints" and "HTTP verbs," we're thinking in terms of "services" and "remote procedures." It's essentially like calling a method on a class, but that class happens to live on a different server across the network.

The magic here is Protocol Buffers (Protobuf). Instead of sending bulky JSON strings back and forth, gRPC uses a binary format. It's faster, smaller, and—most importantly—it forces us to define a strict contract before we write a single line of C# code.

Defining the Inventory Contract

Let's build a simple Inventory Check service. Imagine a warehouse system where a storefront needs to quickly check if a specific item is in stock. I'll start by creating a inventory.proto file. This is the "source of truth" for both the server and the client.

syntax = "proto3";

option csharp_namespace = "InventoryService";

service Inventory {
  rpc GetStockLevel (StockRequest) returns (StockResponse);
}

message StockRequest {
  string sku = 1;
}

message StockResponse {
  int32 quantity = 1;
  bool is_available = 2;
}

Notice those numbers (= 1, = 2)? Those aren't values; they're field tags. Since the data is binary, gRPC doesn't send the name "sku" over the wire; it just sends the tag "1". This is why you can't just change these numbers once your service is in production—you'd break every client currently talking to your server.

Implementing the Server Logic

Once I save that proto file and build the project, .NET does some heavy lifting in the background. It generates a base class that I just need to inherit from. I don't have to worry about the networking guts; I just override the method and write the business logic.

public class InventoryProvider : Inventory.InventoryBase
{
    private readonly Dictionary<string, int> _stock = new()
    {
        { "LAPTOP-001", 15 },
        { "MOUSE-002", 0 },
        { "MONITOR-003", 7 }
    };

    public override Task<StockResponse> GetStockLevel(StockRequest request, ServerCallContext context)
    {
        _stock.TryGetValue(request.Sku, out int quantity);
        
        return Task.FromResult(new StockResponse
        {
            Quantity = quantity,
            IsAvailable = quantity > 0
        });
    }
}

Correcting a Common Proto Mistake

I'll be honest: when I first started with gRPC, I tried to be "efficient" and write my service definition like this: rpc GetStockLevel (string sku) returns (StockResponse);. I thought, "Why wrap a single string in a message object? That's just boilerplate."

The compiler immediately yelled at me. In gRPC, every request and response must be a defined message type. You cannot pass raw primitives like strings or ints directly into the RPC call. It feels tedious at first, but it's actually a lifesaver. If we ever need to add a "WarehouseId" or a "CustomerPriority" to that request later, we can do it without breaking the method signature for existing clients.

Wiring up the Client

Now that the server is running, the client side is surprisingly clean. I don't have to deal with HttpClient, JSON deserialization, or status code checks. I just create a channel and instantiate the generated client class.

using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Inventory.InventoryClient(channel);

var response = await client.GetStockLevelAsync(new StockRequest { Sku = "LAPTOP-001" });

Console.WriteLine($"Quantity: {response.Quantity}, Available: {response.IsAvailable}");

I love how this feels. It's type-safe from end to end. If I change a field name in the proto file, the client code won't even compile until I fix the reference. That's a massive upgrade over the "fingers crossed" approach we often use with REST and JSON.




📋 Practical Task

Build a Product Pricing gRPC Service

Your task is to extend the concepts from this lesson by creating a new gRPC service that handles product pricing. Follow these requirements:

  • Create a pricing.proto file defining a service called PriceCalculator.
  • The service should have a method GetPrice that takes a PriceRequest (containing a productId and a currencyCode) and returns a PriceResponse (containing the amount as a double and a formattedPrice string).
  • Implement the server-side logic in a class inheriting from the generated base class. Use a hard-coded dictionary to simulate a price database.
  • Write a small console client that requests the price for a specific product and prints the formattedPrice to the console.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.