Skip to content

ckadluba/GrpcDemos

Repository files navigation

gRPC Sample Programs

Here are some small sample apps written in C# to explore the current state and features of the gRPC stack for ASP.NET Core.

MinimalHello

The simplest possible client and server gRPC sample app consisting of only two projects. It demonstrates also Microsoft Grpc.Net client- and server side logging.

MinimalGoogleGrpc

Like MinimalHello but client and server based on Google's Grpc.Core library. For demo purposes, it uses insecure transport over HTTP/2 without TLS and demonstrates also Google Grpc.Core client- and server side logging.

SimpleCalc

A simple calculator service with a client using synchronous gRPC calls with ASP .Net Core 3.0.

Execute SimpleCalc.ServiceHost and SimpleCalc.Client.

LifeTime

Two services called from one client. One is configured to create the service class for each request (default) and the other has one single service class instance for all requests.

Execute LifeTime.ServiceHostPerCall, LifeTime.ServiceHostSingleton, LifeTime.ServiceHostGoogleGrpc and LifeTime.Client.

ServerReflection

Demonstrates gRPC Server Reflection. Sample contains only service project.

Call server reflection via gRPCurl in call-service.ps1.

Metadata

Demonstrates sending call metadata in request and response between client and server.

Deadline

Demonstrates terminating a gRPC call using deadline.

AsyncEcho

A service that just echos the input from the client using an asynchronous gRPC call.

Execute AsyncEcho.ServiceHost and AsyncEcho.Client.

AsyncChat

A small chat server with a console client using only one asynchronous gRPC call with bidirectional streaming.

Execute AsyncChat.ServiceHost and two or more instances of AsyncChat.Client.

GrpcWeb

Uses gRPC-Web to perform gRPC communication over HTTP/1.1.

Writing the Code

This example is based on the SimpleCalc sample app.

  1. Maybe you need to install dotnet-grpc

    dotnet tool install -g dotnet-grpc
    
  2. Create SimpleCalc.SharedLib as netcoreapp3.0 classlib
    netstandard2.x would be desirable but does not work because of tooling issue dotnet/AspNetCore.Docs#14702

  3. Create service contract
    In SharedLib create SimpleCalc.proto

  4. Generate client and server stubs
    In SharedLib: Add > Service Reference > gRPC > File: .proto file, Type: Client and Server
    Can also be done with CLI:

    dotnet grpc add-file [options] <files>...
  5. Edit Protobuf element to make generated source visible in Solution Explorer (optional)

    <Protobuf Include="calculator.proto"
              OutputDir="%(RelativePath)"
              CompileOutputs="false" />

    Attention: don't change back or you get errors in clients (duplicated definitions).

  6. Create SimpleCalc.ServiceLib as netcoreapp3.0 classlib.
    Add project reference to SharedLib.
    Add class CalculatorService deriving from CalculatorServiceBase.
    Implement service methods.

  7. Create SimpleCalc.ServiceHost by Add > New Project > "gRPC Service" template
    Delete unused generated directories Services and Proto
    Add project reference to ServiceLib.

  8. Create SimpleCalc.Client as console app
    Add reference to SharedLib.
    Install NuGet package Grpc.Core for Google Grpc library if using that instead of Microsoft Grpc Create instance of CalculatorServiceClient and use with GrpcChannel.ForAddress()

gRPC and WCF

Existing Libraries

  • WCF is a Microsoft .Net technology
    • will not come to .NET Core/.NET 5
  • Original gRPC from Google
    • Grpc.Core etc.
    • Managed wrapper which calls native lib written in C
  • Microsoft gRPC
    • 100% managed code
    • Grpc.Net, Grpc.AspNetCore, etc.

Binding and Contracts

  • WCF Endpoint
    • address
    • binding (protocol, security, etc. also custom bindings possible)
    • contract (interface with ServiceContract attribute)
      • Implemented by class on server
      • Implemented by generated class on client (Add Service Reference ...)
  • gRPC
    • transport over HTTP/2 (for all .Net implementations)
    • channel - single virtual connection (multiplexing, pooling, load balancing, one or more physical connections)
    • IDL interface definition language is protobuffers (.proto)
    • Generated code stubs (client and server code that accesses channel, generated from IDL using protoc compiler)
      • Server stub is base class to derive from (Add Service Reference - Server)
      • Client stub (Add Service Reference - Client)

Transfer Modes

WCF gRPC Comment Protobuffers Sample
Buffered Unary Client sends single request, server answers with respose rpc Hello (Request) returns (Reply)
Return stream to client with binding that supports streamed transfer mode Server streaming Service sends stream to the client rpc DownloadFile (Request) returns (stream Reply)
Pass stream to server with binding that supports streamed transfer mode Client streaming Client sends stream to the server rpc UploadFile (stream Request) returns (Response)
πŸ€·β€πŸ˜‚ Bidirectional streaming Client and server using streams rpc JoinVideoConference (stream Request) returns (stream Response)

Service Lifetime

  • When is the service class created/reused?
  • In WCF controlled by ServiceBehaviorAttribute on service contract (e.g. InstanceContextMode.PerSession)
  • In Google Grpc.Core based services a single instance all requests.
  • In Microsoft Grpc.AspNetCore based services a new instance for each request
    • Can be controlled by directly registering the service with AddSingleton()
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddGrpc();
          services.AddSingleton(new GreeterService());
      }

Security

  • WCF supports HTTPS/TLS transport
  • gRPC
    • All implementations support HTTP/2 with TLS
      • not required
      • still problems in practice with some tools and implementations (see Tools section below)
    • gRPC also supports Google token based authentication
      https://grpc.io/docs/guides/auth/
    • Extensible for futher authentication mechanisms

ServerCallContext

  • gRPC passes ServerCallContext instance to every service method
    • Call specific technical information and functions
    • Exchange metadata (both directions)
    • Deadline/timeout for call
    • Authentication info
    • Called host, method and calling client info
    • Set response status
    • Set Stream options
    • etc.
  • WCF service methods can use OperationContext.Current

gRPC Server Reflection

Client can query service interface.

  • WCF - Metadata Exchange Protocol (MEX)
  • gRPC - Server Reflection
    • NuGet Grpc.AspNetCore.Server.Reflection
    • Server code
      Add Grpc Reflection
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddGrpc();
          services.AddGrpcReflection();
      }
      Map Grpc Reflection service
      app.UseEndpoints(endpoints =>
      {
          endpoints.MapGrpcService<GreeterService>();
          endpoints.MapGrpcReflectionService();
      });

Deadlines/Timeouts

  • In WCF controlled by Binding
    • OpenTimeout, CloseTimeout, SendTimeout, ReceiveTimeout
    • Enforced on client side
  • In gRPC every call can have an individual deadline/timeout
    • Some libraries use a fixed point in time (deadline) others a maximum delay (timeout)
    • Enforced by library
    • Handling in gRPC ASP.NET
      • Client gets RpcException with StatusCode=DeadlineExceeded
      • Server can use CancellactionToken in ServerCallContext object

Logging

Google gRPC based Implementations

Microsoft Grpc.Net based Implementations

  • https://docs.microsoft.com/en-us/aspnet/core/grpc/diagnostics?view=aspnetcore-3.1
  • Server config
    {
      "Logging": {
        "LogLevel": {
          "Default": "Debug",
          "System": "Debug",
          "Microsoft": "Debug",
          "Grpc": "Debug"
        }
      },
      "AllowedHosts": "*",
      "Kestrel": {
        "EndpointDefaults": {
          "Protocols": "Http2"
        }
      }
    }
  • Server code
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureLogging(logging =>
            {
                logging.AddFilter("Grpc", LogLevel.Debug);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
               webBuilder.UseStartup<Startup>();
            });
  • Client code
    var loggerFactory = LoggerFactory.Create(logging =>
    {
        logging.AddConsole();
        logging.SetMinimumLevel(LogLevel.Debug);
    });
    using var channel = GrpcChannel.ForAddress("https://localhost:5001",
        new GrpcChannelOptions { LoggerFactory = loggerFactory });
    var client = new Greeter.GreeterClient(channel);

Tools

  • gRPCurl - a curl for gRPC
    • https://github.com/fullstorydev/grpcurl
    • Command line tool. Many features but not easy to use.
    • Example: call MinimalHello.Service with unencrypted HTTP/2
      grpcurl -v -plaintext -d '{ \"name\": \"Johnny\"}' -import-path "C:\source\github\GrpcDemos\MinimalHello\MinimalHello.Service\Protos\" -proto Greeter.proto localhost:5001 Greet.Greeter/GetGreeting
      Grpcurl
    • Did not work with TLS 😒
  • BloomRPC - a Postman like test tool for gRPC
    • https://github.com/uw-labs/bloomrpc
    • Enter only host[:port] in address field, not full URI like "https://...". Uri is generated according to TLS setting.
    • Could add ASP.Net Core dev certificate as .crt but unfortunately could not get to work with TLS 😒 because of bloomrpc/bloomrpc#100
  • gRPCox - Web based gRPC test tool running in a Docker container
  • Postman + grpc-json-proxy
  • Wireshark
    • Only suitable for general connectivity problems or with insecure HTTP/2 during development
    • TLS also possible but requires cumbersome server cert + private key setup in Wireshark
    • Trace packets on loopback interface with display filter "tcp.port == 5001"
    • Configure HTTP/2 dissection if not port 80: Edit > Settings > Protocols > http2 > Port = 5001
  • gRPC-Web
  • Traffic Parrot

References and Documentation