Blazor Server: setup gRPC
The Blazor Server model, with its integrated backend, offers a unique advantage when interacting with third-party gRPC services. Let’s clarify how this works and why it’s different from Blazor WASM or Flutter.
With Blazor Server, your C# code runs directly on the server. This means you can directly use the gRPC client libraries within your Blazor Server application’s backend code to communicate with any external gRPC service. The communication happens entirely server-side:
- Blazor Component Initiates Request: A Blazor component on the server triggers a method call that needs data from the third-party gRPC service.
- Server-Side gRPC Call: The Blazor Server backend code uses the gRPC client libraries to make the call to the external gRPC service over HTTP/2.
- gRPC Response Processed: The gRPC server sends back the response, which is deserialized by the gRPC client library on the Blazor Server backend.
- Data Sent to Component: The processed data is then passed from the server-side code back to the Blazor component over the SignalR connection (which is not gRPC or HTTP/2, but typically WebSockets over HTTP/1.1).
- Component Updates: The Blazor component updates with the received data.
Key Differences and Advantages compared to Blazor WASM and Flutter:
- No Proxying Required: With Blazor Server, you don’t need a separate API or gateway to proxy gRPC calls. This simplifies the architecture and reduces latency. In contrast, Blazor WASM or Flutter applications running in a web browser cannot directly make gRPC calls over HTTP/2 due to browser limitations. They often require a proxy or gateway to translate gRPC to something the browser understands (like REST/JSON over HTTP/1.1).
- Server-Side Power: The gRPC client logic runs on the server in Blazor Server, taking advantage of the server’s resources and processing power. This can be beneficial for complex or computationally intensive gRPC interactions.
- Security: Sensitive gRPC credentials and logic remain on the server, away from the client browser, improving security.
In short, Blazor Server provides a simplified and efficient way to interact with third-party gRPC services without the proxying complexities often required in client-side web frameworks like Blazor WASM or Flutter. It leverages the power of server-side C# to handle the gRPC communication, leading to a streamlined and potentially higher-performance solution.
How To Setup your Blazor Server Project to Support gRPC
1.Create the Blazor Server Project: If you don’t already have one, create a new Blazor Server project. The confusing part here is that your Blazor Server will actually be a gRPC client. It should have the following line in it’s Program.cs file:
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
...
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
2. Add gRPC NuGet Packages: Install the necessary gRPC packages to both your Blazor Server project and any shared project where you’ll define your Protocol Buffer messages. You’ll need these packages:
- Grpc.AspNetCore
- Grpc.Net.Client
- Google.Protobuf
- Grpc.Tools
In your PowerShell:
dotnet install Grpc.AspNetCore
dotnet install Grpc.Net.Client
dotnet install Google.Protobuf
dotnet install Grpc.Tools
3. Create the .proto file: Create a .proto
file inside your dotnet project (e.g., Protos/greet.proto
) to define your gRPC service and messages. Here’s a simple hello_world.proto
example:
syntax = "proto3";
option csharp_namespace = "MyGrpcServiceNamespace"; // Replace with your desired namespace
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
4. Modify your .csproj file: Use the gRPC tooling to generate C# code from your .proto
file. A common approach is to add a build step to your project file. This is typically done by adding a <Protobuf>
item group and setting the GrpcServices
property to Server
and/or Client
as needed:
<ItemGroup>
<Protobuf Include="protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
In the snippet above, the GrpcServices
attribute dictates whether the generated code will be a server or client code. The available options are Server
, Client
, Both
or None
. Set Client
in your Blazor Server project, and Server
in your gRPC service.
5. Run dotnet build
command: At this point, your build should add auto-generated files to your obj/Debug/netX.Y
folder (e.g. Greeter.cs, GreeterGRPC.cs etc.)
6. Implement the gRPC Service: Create a class that implements the gRPC service you defined in your .proto
file. For the greet.proto
example, this would be a class that implements the Greeter
service.
using MyGrpcServiceNamespace;
...
public class GreeterService : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
}
7. Map gRPC Endpoints: In your Startup.cs
file, map the gRPC endpoints:
builder.Services.AddGrpc();
builder.Services.AddScoped<GreeterService>();
...
app.UseGrpc(); // Add this to both client and server
// If you want to lock your gRPC service to use only HTTP/2
// (also not usually necessary):
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(54987, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
});
...
// IMPORTANT: When deploying your gRPC service to an App Service
// (Azure WebApp or GCP Cloud Run), you need to add these headers
// for correct handling of TLS termination !!!
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
// For your Service app, map your gRPC service
app.MapGrpcService<GreeterService>();
// IMPORTANT: Make sure NOT to force HTTPS redirection in your gRPC service,
// as this will break your service.
// app.UseHttpsRedirection();
8. Create a gRPC Client in your Blazor Component: In your Blazor component, create a gRPC channel and client to call your gRPC service:
@inject GrpcChannel Channel
// ... other component code
protected override async Task OnInitializedAsync()
{
var client = new Greeter.GreeterClient(Channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "World" });
// Do something with the reply.Message (e.g., display it in the component)
}
9. Configure gRPC Channel in DI: Register your gRPC channel in the Startup.cs
ConfigureServices
method. This might look like the following, but the actual address configuration will depend on your setup.
services.AddSingleton(services =>
{
var httpClientHandler = new HttpClientHandler();
// Return GrpcChannel/GrpcHttpMessageHandler depending on
// whether you need to connect to an external gRPC service.
return GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpHandler = httpClientHandler });
});
This detailed breakdown should help you add gRPC functionality to your Blazor Server project.