X

Building gRPC service on ASP.NET Core

ASP.NET Core supports gRPC protocol that is about to replace legacy SOAP services with more performant and powerful protocol that is easier to use and support. This blog post shows how to build gRPC service and client on Visual Studio and ASP.NET Core.

What is gRPC?

gRPC is modern high performance communication framework for connected systems. By nature it is Remote Procedure Call (RPC) framework. It uses Protocol Buffers developed by Google as its Interface Definition Language (IDL). Using IDL the structure and payload messages are defined.

Here’s the example of RPC definition in protocol buffers IDL.

// [START declaration]
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";
// [END declaration]

// [START java_declaration]
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
// [END java_declaration]

// [START csharp_declaration]
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
// [END csharp_declaration]

// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;

  google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

Based on these definition files language tooling can build up client and server classes for gRPC service.

IDL of gRPC is language and tooling agnostic.


Image from gRPC homepage.

Why another communication standard if we have already REST and JSON? Well, gRPC is targeting massive scale messaging by using some fancy features of HTTP/2 and using binary wire formats for message transfer.

There are four communication patterns supported in gRPC.

  1. Unary RPC – client sends single request and gets back single response.
  2. Server streaming RPC – after getting request message from client, server sends back stream of responses.
  3. Client streaming RPC – client send stream of messages to server and server sends back one response.
  4. Bidirectional streaming RPC – client send stream of messages to server and server sends back stream of messages.

These communication patterns are not covered in any REST service specification. There’s even more covered by gRPC documentation like deadlines, timeouts and cancelling.

NB! As of writing this blog post gRPC is not supported with ASP.NET Core applications hosted on Azure App Service or IIS because HTTP/2 implementation of Http.Sys doesn’t support all features required by gRPC. It’s still possible to run applications using Kestrel on virtual machine.

Creating gRPC project on Visual Studio

ASP.NET Core supports gRPC and provides required tooling for Visual Studio.

Solution created based on gRPC Service template has only service. Adding client project is up to us. I went on with ASP.NET Core web application.

GrpcService1 is ASP.NET Core web application hosting gRPC service. It doesn’t have any UI for browsers. WebApplication1 is regular ASP.NET Core MVC application having Home controller to show message from gRPC server.

Both projects have the same greet.proto file. It is hosted in GrpcService1 project and WebApplication1 has file link to it.

GrpcService1 has minimal Startup class.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();

            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
            });
        });
    }
}

It adds gRPC to service collection, enables routing and defines route for GreeterService. Startup class of WebApplication1 is usual ASP.NET Core MVC one. There’s no word about gRPC.

Proto buffer file greet.proto is laconic and defines just simple hello-world-style service with messages.

syntax = "proto3";

option csharp_namespace = "GrpcService1";

package Greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

Here’s the greeter service class generated by tooling.

public class GreeterService : Greeter.GreeterBase
{
    private readonly ILogger<GreeterService> _logger;

    public GreeterService(ILogger<GreeterService> logger)
    {
        _logger = logger;
    }

    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = "Hello " + request.Name
        });
    }
}

On service side things are actually simple and thin. We don’t have much gRPC details surfacing up if we don’t actually need it.

All the ugly mess is hidden to base class of service. It’s auto-generated code we shouldn’t touch.

This code is generated based on .proto file. To have automatic service generation available in project we need reference to Grpc.Tools package.

When creating client web application is went through steps from ASP.NET Core documentation page Create a gRPC client and server in ASP.NET Core. Here is my Home controller that calls service.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public async Task<IActionResult> Index()
    {
        var channel = GrpcChannel.ForAddress("https://localhost:5001");
        var client = new Greeter.GreeterClient(channel);
        var request = new HelloRequest { Name = "Beavis" };
        var response = await client.SayHelloAsync(request);

        ViewBag.Message = response.Message;

        return View();
    }
}

It’s raw and unpolished code that just make its work. Nothing more, nothing less.

NB! In real applications we should have some client class to communicate with gRPC and to hide details like creating communication channel and service client.

Will gRPC replace SOAP, WCF, REST and JSON?

In ASP.NET Core world gRPC is new kid on the block and it’s too early to say if it’s here to replace REST and WebAPI that are easier to consume for client applications. Actually I don’t think so. Having thin and simple service interface that doesn’t require advanced tooling will remain the important benefit.

When it comes to SOAP and WCF it’s a different story. Overview of Protocol Buffers brings out the following advantages of protocol buffer messages over XML based messages:

  • 3 to 10 times smaller,
  • 20 to 100 times faster,
  • less ambiguous.

Those who have experiences with WCF and SOAP should find these numbers great.

AS WCF is not officially supported on .NET Core then gRPC is currently the only serious option for enterprice grade messaging between systems.

Wrapping up

gRPC is a little bit similar to WCF but still a totally different beast. It is using binary format for data exchange between systems and it leads to way smaller message payloads. Using HTTP/2 features it provides four different communication patterns to support also services under heavy load of communication requests. As there’s no WCF support on .NET Core officially, gRPC is currently the best option to take when it’s about enterprise grade web services.

Liked this post? Empower your friends by sharing it!

View Comments (2)

  • On Windows based hosting not yet, as far as I know. It needs changes to HTTP/2 support in HTTP.SYS. Until it will be implemented and deployed you can host your application on Linux.

Related Post