GPRC
Setup
-
Create a directory
mkdir gRPC
cd gRPC -
Create a new ASP.NET Core gRPC Service project
dotnet new grpc -n GrpcHero --framework net9.0
cd GrpcHero -
Open in IDE
rider .
Grpc Hello World
-
Duplicate
greet.protoashero.proto -
Update
hero.proto:syntax = "proto3";
option csharp_namespace = "GrpcHero";
package hero;
// The greeting service definition.
service HeroGreeter {
// Sends a greeting
rpc CallForHelp (HelpRequest) returns (HelpReply);
}
message HelpRequest {
string problem = 1;
}
message HelpReply {
string message = 1;
} -
Update csproj to add the following to the existing itemgroup:
<Protobuf Include="Protos\hero.proto" GrpcServices="Server" />warningIf you forget to add this step your service won't get source generated.
-
Duplicate
GreeterServicetoHeroServiceand fix upusing Grpc.Core;
using GrpcHero;
public class HeroService : HeroGreeter.HeroGreeterBase
{
private readonly ILogger<HeroService> _logger;
public HeroService(ILogger<HeroService> logger)
{
_logger = logger;
}
public override Task<HelpReply> CallForHelp(HelpRequest request, ServerCallContext context)
{
return Task.FromResult(new HelpReply()
{
Message = "Superman is on the way 💪!"
});
}
} -
Update
Program.csto add the new serviceapp.MapGrpcService<HeroService>();
Reflection
-
Run project
-
Open Insomnia Scratchpad
-
Create a new gRPC request
-
Set the URL to
https://localhost:5000 -
Show that the server doesn't support reflection so we can't see what services are available
noteWe COULD manually add the proto file, but let's use reflection instead.
-
Add the following package
dotnet add package Grpc.AspNetCore.Server.Reflection -
Register reflection in
Program.cs:builder.Services.AddGrpcReflection();app.MapGrpcReflectionService(); -
Run app again
-
Refresh proto definitions in Insomnia via 'reflection'
Test
-
Select
HeroGreeter/CallForHelpas the function -
Set unary body to
{
"problem": "I need help!"
} -
Hit send
Grpc Streaming
-
Add a new method to the
hero.protofile for streaming:// Sends a stream of hero's greetings to a user
rpc PlanMission (MissionRequest) returns (stream MissionReply); -
Add new messages
message MissionRequest {
string problem = 1;
}
message MissionReply{
string plan = 1;
} -
Build the project
-
Add a mission plan
public class MissionPlan
{
public static string[] GetSupermanAndWonderWomanPlan()
{
return new string[]
{
"Superman and Wonder Woman will conduct reconnaissance from the air to assess the situation.",
"Wonder Woman will use her Lasso of Truth to extract crucial information from key individuals.",
"Superman will use his super speed to evacuate civilians from the danger zone.",
"Wonder Woman will deflect incoming projectiles with her indestructible bracelets.",
"Superman will use his freeze breath to neutralize any immediate threats.",
"Wonder Woman will establish a secure perimeter using her Amazon training.",
"Superman will use his x-ray vision to locate hidden enemies or devices.",
"Together they will execute a coordinated attack on the main threat.",
"Wonder Woman will secure any dangerous artifacts with her divine knowledge.",
"Superman will use his strength to restore damaged infrastructure."
};
}
} -
Update
HeroServiceto implement the new streaming method:public override async Task PlanMission(MissionRequest request, IServerStreamWriter<MissionReply> responseStream, ServerCallContext context)
{
_logger.LogInformation($"Planning mission for problem: {request.Problem}");
string[] missionSteps = MissionPlan.GetSupermanAndWonderWomanPlan();
foreach (var step in missionSteps)
{
await responseStream.WriteAsync(new MissionReply { Plan = step });
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
Test the streaming method
-
Update gRPC definition via reflection
-
Test as above
-
Observe streamed responses
Stop here during the demo. The attendees can try out the other demos on their own.
Grpc JsonTranscoding
-
Add a package reference to
Microsoft.AspNetCore.Grpc.JsonTranscodingdotnet add package Microsoft.AspNetCore.Grpc.JsonTranscoding -
Register transcoding in server startup code by adding
AddJsonTranscoding:- In the
Program.csfile, changebuilder.Services.AddGrpc();tobuilder.Services.AddGrpc().AddJsonTranscoding();.
- In the
-
Add
<IncludeHttpRuleProtos>true</IncludeHttpRuleProtos>to the property group in the.csprojproject file:<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<IncludeHttpRuleProtos>true</IncludeHttpRuleProtos>
</PropertyGroup> -
Annotate gRPC methods in your
.protofiles with HTTP bindings and routes:// 👇👇👇
import "google/api/annotations.proto";
// 👆👆👆
service Hero {
rpc SayHello (HelloRequest) returns (HelloReply) {
// 👇👇👇
option (google.api.http) = {
get: "/v1/hero/{name}"
};
// 👆👆👆
}
rpc SayHelloStream (HelloStreamRequest) returns (stream HelloReply) {
// 👇👇👇
option (google.api.http) = {
post: "/v1/hero"
body: "*"
};
// 👆👆👆
}
}
GrpcSwagger
-
Add a package reference to
Microsoft.AspNetCore.Grpc.Swaggerdotnet add package Microsoft.AspNetCore.Grpc.Swagger -
Add Swagger to services
using HeroRelay.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddGrpc().AddJsonTranscoding();
builder.Services.AddGrpcReflection();
// 👇👇👇
builder.Services.AddGrpcSwagger();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo { Title = "gRPC Hero transcoding", Version = "v1" });
});
// 👆👆👆
var app = builder.Build();
// Configure the HTTP request pipeline.
// 👇👇👇 - Add Swagger UI Middleware
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Hero API V1");
});
// 👆👆👆
app.MapGrpcService<GreeterService>();
app.MapGrpcReflectionService();
app.MapGet("/", () => "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");
app.Run(); -
Enable the XML documentation file in the server project with:
<GenerateDocumentationFile>true</GenerateDocumentationFile> -
Configure
AddSwaggerGento read the generated XML file. Pass the XML file path toIncludeXmlCommentsandIncludeGrpcXmlComments, as in the following example:var filePath = Path.Combine(System.AppContext.BaseDirectory, "GrpcHero.xml");
c.IncludeXmlComments(filePath);
c.IncludeGrpcXmlComments(filePath, includeControllerXmlComments: true);
Docs
- Grpc Reflection - https://learn.microsoft.com/en-us/aspnet/core/grpc/test-tools
- Json Transcoding: https://learn.microsoft.com/en-us/aspnet/core/grpc/json-transcoding
- Http Rules: https://learn.microsoft.com/en-us/aspnet/core/grpc/json-transcoding-binding
- Grpc Swagger/OpenAPI - https://learn.microsoft.com/en-us/aspnet/core/grpc/json-transcoding-openapi