.NET 7 introduced gRPC JSON transcoding, used within ASP.NET Core, to allow HTTP/2 requests to be transcoded to JSON and transmitted via REST APIs on HTTP/1. This was introduced mainly because HTTP/2 is not fully supported in browsers, because JSON and REST APIs have an important role in modern apps, and because it would be too much for teams to build separate gRPC and REST Web APIs to cope with those browser limitations.
Overview
In previous posts we approached gRPC implementations using protobuf .proto files and protobuf-net, however, in .NET 7 the JSON Transcoding is implemented with the use of proto files.
Once implemented, JSON transcoding enables gRPC services to also become REST JSON APIs running on HTTP/1. Requests can then make use of:
HTTP verbs
URL parameter bindings
JSON requests/responses
The changes
The template ASP.NET Core gRPC Service in Visual Studio 2022 creates a gRPC boilerplate service that needs changing to work with JSON transcoding. To start with the NuGet package Microsoft.AspNetCore.Grpc.JsonTranscoding, which needs to be referenced, and then make sure it gets registered on startup code, by adding AddJsonTranscoding() as below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
usingGrpcNet7JSONTranscoding.Services;varbuilder=WebApplication.CreateBuilder(args);// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
// Add services to the container.
builder.Services.AddGrpc().AddJsonTranscoding();varapp=builder.Build();// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();app.MapGrpcService<UserService>();app.MapGet("/",()=>"Communication with gRPC endpoints must be made through a gRPC client.");app.Run();
Another change required is around the Protos folder, which needs to sit outside of the project, with the additional proto files:
In this example, we are going to make use of the proto file user.proto, used in previous posts. Here are some changes required to enable JSON transcoding. Let’s compare the files:
The proto file makes use of import "google/api/annotations.proto", which was added to the Proto folder, and within the RPC GetUserDetails the GET request is specified, accepting the URL parameter binding {user_id}.
Regarding the UserService, this is a dummy implemented inheriting from UserServiceBase:
usingGrpc.Net.Client;usingSystem.Text.Json;usingGrpcNet7JSONTranscoding.Protos;usingSystem.Net.Http;varuserId=1;// gRPC
varchannel=GrpcChannel.ForAddress("https://localhost:7060");varclient=newUserService.UserServiceClient(channel);varuserDetails=awaitclient.GetUserDetailsAsync(newUserRequest(){UserId=userId});Console.WriteLine(JsonSerializer.Serialize(userDetails));// REST API
varhttpClient=newHttpClient();varrequest=newHttpRequestMessage(HttpMethod.Get,$"https://localhost:7060/user/{userId}"){Version=newVersion(2,0)};varresponse=awaithttpClient.SendAsync(request);response.EnsureSuccessStatusCode();varcontent=awaitresponse.Content.ReadAsStringAsync();Console.WriteLine(content);Console.WriteLine("Press any key to exit...");Console.ReadKey();
It creates a request to the gRPC service and also to the REST API endpoint, one running on HTTP/2 and the other on HTTP/1. The result contains the same information, the first a Pascal-cased serialized object while the other a camel-cased JSON string:
Join the conversation! Share your thoughts and connect with other readers.