The REST API has been the standard to communicate between clients and servers for a lot of years now. But recently gRPC has gained a lot of popularity on this territory.
Two reasons for this popularity are:
Although gRPC has excellent cross-platform support, there is one place you can’t call a gRPC service from and that is... the browser. gRPC heavily uses HTTP/2 features and no browser provides the level of control required over web requests to support a gRPC client. For example, browsers do not allow a caller to require that HTTP/2 be used or provide access to underlying HTTP/2 frames.
gRPC-Web is an additional technology from the gRPC team that provides (limited) gRPC support in the browser. gRPC-Web consists of two parts: a JavaScript client that supports all modern browsers, and a gRPC-Web proxy on the server. The gRPC-Web client calls the proxy and the proxy will forward on the gRPC requests to the gRPC server.
The need for this proxy made it a little bit harder to use, but Microsoft announced experimental support for gRPC-Web with .NET! So now we don't need this extra proxy anymore.
In this blogpost I will demonstrate a working example of a .NET Core service communicating with an Angular frontend using gRPC-Web (without the use of an Envoy proxy).
For the service I have used the default "gRPC Service" project provided by Visual Studio.
Start Visual Studio and select Create a new project.
In the Create a new project dialog, select gRPC Service and select Next:
After creating this project, you will have an GreeterService which can communicate by gRPC.
Add the Grpc.AspNetCore.Web NuGet package to enable gRPC-Web (don't forget to check the "Include prerelease" box)
And configure the app to use gRPC-Web by adding the UseGrpcWeb() middleware and .EnableGrpcWeb() to your service in the startup file:
Startup.cs
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
// Add gRPC-Web middleware after routing and before endpoints
app.UseGrpcWeb();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
});
}
Now that we created the server part, we need to create a client to communicate with the server. For the demo we create a new Angular app by using the ng-cli command:
ng new GrpcWebClient
Because the communication between client and server is defined in a .proto file we can generate the client code for the service.
For this to work we need to add 2 packages to our Angular project
npm install ts-protoc-gen
npm install google-protobuf @types/google-protobuf @improbable-eng/grpc-web --save
And we need to download the protoc tool
I have downloaded the "protoc-3.11.4-win64.zip" and copied the protoc.exe and google folder to a new "Protoc" folder (next to my GrpcWebClient folder)
To generate the client code I copied the greet.proto from the .NET project to the Protoc folder and used this command
protoc
--plugin="protoc-gen-ts=C:\Repos\GrpcWeb-dotNetCore-Angular\GrpcWebClient\node_modules\.bin\protoc-gen-ts.cmd"
--js_out="import_style=commonjs,binary:../GrpcWebClient/src/generated"
--ts_out="service=grpc-web:../GrpcWebClient/src/generated" greet.proto
After running this command, it will generate 4 files in my '/GrpcWebClient/src/generated' folder (the 'generated' folder needs to be created by hand).
Now we can add a greeter component by using this command
ng g component greeter
Call the Greeter service from Angular
greater.compontent.ts
export class GreeterComponent implements OnInit {
response: string;
ngOnInit(): void {
const client = new GreeterClient('https://localhost:5001');
const req = new HelloRequest();
req.setName("World!");
client.sayHello(req, (err: ServiceError, response: HelloReply) => {
if (err) {
this.response = `Error: {err.message}`;
return;
}
this.response = response.getMessage();
});
}
}
After running the client (and server) you will have the "Hello World!" example of a browser to server application using gRPC-Web for communication. For more information on gRPC see grpc.io