10 Steps to Replace REST Services with gRPC-Web in Blazor WebAssembly
Tags: blazor, dotnet, csharp, webdev
Published: 2020-09-02 11:44:49

---
title: 10 Steps to Replace REST Services with gRPC-Web in Blazor WebAssembly
published: true
date: 2020-09-02 11:12:26 UTC
tags: blazor, dotnet, csharp, webdev
canonical_url: https://www.syncfusion.com/blogs/post/10-steps-to-replace-rest-services-with-grpc-web-in-blazor-webassembly.aspx
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/0p5cdlq5appeq4ig74cb.png
---

In modern web applications, the common way data is exchanged between client and server is through [REST (representational state transfer) services](https://en.wikipedia.org/wiki/Representational_state_transfer). [JSON](https://en.wikipedia.org/wiki/JSON) is the standard file format for this two-way communication.

In REST, the client makes a request to a specific endpoint, and the server responds to it.

This architectural style works fine and has been the standard for several years. All web frameworks for creating SPA (single-page applications) are based on it. At first glance, even Blazor WebAssembly seems to use REST just like other frameworks.

Despite the wide use of this standard, there are some critical issues to consider:

- If it is true that JSON is less verbose than XML, then it is also true that it is not optimized for bandwidth. Sometimes, JSON structure gets much too complicated.
- REST APIs are stateless. This can have some negative consequences; for example, all requests should contain all the necessary information in order to perform the desired operations.
- REST is not a protocol, but an architectural style. This involves increasing the responsibilities of developers. Most implementations of REST use only a subset of its principles but work, more or less. Often there is a confusion between REST services and RESTful services (those that implement REST services).

To be clear, REST architecture remains a great way to exchange data between clients and servers, but perhaps today we can afford to look beyond to find alternative solutions.

## What are gRPC and gRPC-Web?

[gRPC](https://en.wikipedia.org/wiki/GRPC) is a remote procedure call system created at Google in 2015. It is open source and can be defined as a replacement for [Windows Communication Foundation (WCF)](https://en.wikipedia.org/wiki/Windows_Communication_Foundation). However, thanks to the latest update, it can also substitute REST API.

gRPC uses [Protobuf](https://en.wikipedia.org/wiki/Protocol_Buffers) (Protocol Buffers) as the format for the payload and supports all kinds of streaming:

- Server-side streaming
- Client-side streaming
- Bidirectional streaming

From a performance point of view, Protobuf is an efficient binary message format. Protobuf serialization results in small message payloads, which is important in limited-bandwidth scenarios like mobile and web apps.

gRPC defines the contract of services and messages by the [.proto file](https://developers.google.com/protocol-buffers/docs/proto3) shared between the server and client. It allows you to automatically generate client libraries. gRPC is consistent across platforms and implementations.

[The following](https://context.reverso.net/traduzione/inglese-italiano/the+following+scheme)table shows a comparison of features between gRPC and REST APIs with JSON format.

![gRPC vs REST API](https://dev-to-uploads.s3.amazonaws.com/i/wrrjmbg1bvwq8z49hf76.png)

All of this sounds great, doesn’t it? Unfortunately, there’s bad news!

gRPC can’t be used from within web browsers because it requires HTTP/2 binary protocol. Don’t worry, the solution to this problem is called [gRPC-Web](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md), which makes gRPC usable in the browser. There’s also an implementation of [gRPC-Web for .NET](https://devblogs.microsoft.com/aspnet/grpc-web-for-net-now-available/) that has been officially released.

To be fair, [gRPC-Web](https://grpc.io/docs/tutorials/basic/web.html) provides limited gRPC support. For example, client and bi-directional streaming aren’t supported, and there is limited support for server streaming too.

After this preamble, it’s time to go from theory to practice!

In this post I’ll show you how to consume a gRPC-Web service from within a Blazor WebAssembly app to build **weather forecasting application**. At the time of writing, there’s no native project template for this yet, so adding gRPC support to a Blazor WebAssembly app is a somewhat significant task. But again, don’t worry. No part of this is complicated. It’s only 10 small steps!

**Step 1**

Create a Blazor WebAssembly ASP.NET Core-hosted solution, and name it **BlazorGrpc**. Refer to the following screenshot.

**![Create a Blazor WebAssembly ASP.NET Core-hosted solution, and name it as BlazorGrpc](https://www.syncfusion.com/blogs/wp-content/uploads/2020/08/Create-a-Blazor-WebAssembly-ASP.NET-Core-hosted-solution-and-name-it-BlazorGrpc.png)Step 2**

These are the changes that need to be made to the project files to add dependencies and more.  
**BlazorGrpc.Shared.csproj**

```html
<ItemGroup>
  <None Remove="weatherforecast.proto" />
</ItemGroup>
 
<ItemGroup>
  <PackageReference Include="Google.Protobuf" Version="3.13.0" />
  <PackageReference Include="Grpc.Net.Client" Version="2.31.0" />
  <PackageReference Include="Grpc.Tools" Version="2.31.0">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
</ItemGroup>
 
<ItemGroup>
  <Protobuf Include="weatherforecast.proto" />
</ItemGroup>
```

**BlazorGrpc.Server.csproj**

```html
<PackageReference Include=”Grpc.AspNetCore” Version=”2.31.0” />
<PackageReference Include=”Grpc.AspNetCore.Web” Version=”2.31.0” />
```

**BlazorGrpc.Client.csproj**

```html
<PackageReference Include="Grpc.Net.Client.Web" Version="2.31.0" />
```

**Step 3**

In the **Shared project** , create a **weatherforecast.proto** file like the code example below.

```csharp
syntax = "proto3";
 
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
 
option csharp_namespace = "BlazorGrpc.Shared";
 
package WeatherForecast;
 
service WeatherForecastService {
  rpc GetWeatherForecast (google.protobuf.Empty) returns (WeatherForecastResponse);
}
 
message WeatherForecastResponse {
  repeated WeatherForecast forecasts = 1;
}
 
message WeatherForecast {
  google.protobuf.Timestamp dateTimeStamp = 1;
  int32 temperatureC = 2;
  string summary = 3;
}
```

The .proto file defines the service and everything necessary to run it correctly.

If you want to learn more about the syntax of this file, refer to this documentation:  
[https://developers.google.com/protocol-buffers/docs/proto3](https://developers.google.com/protocol-buffers/docs/proto3)

**Step 4**

Go to the file properties and select the **Protobuf compiler** as the **Build Action**. A new window will appear thanks to the NuGet package Grpc.Tools. Then, select the **Client and Server** option as the **gRPC Stub Classes**. Refer to the following screenshot.

**![select the Protobuf compiler as the Build Action and select the Client and Server option as the gRPC Stub Classes](https://www.syncfusion.com/blogs/wp-content/uploads/2020/08/select-the-Protobuf-compiler-as-the-Build-Action-and-select-the-Client-and-Server-option-as-the-gRPC-Stub-Classes.jpg)Step 5**

Modify the **WeatherForecast** partial class with the following code snippets. Keep in mind that the main properties of this class are generated from the .proto file; however, you can also add some extra useful properties to this partial class.

```csharp
using System;
using Google.Protobuf.WellKnownTypes;
namespace Blazorgrpc.Shared
{
    public partial class WeatherForecast
    {
        public DateTime Date
        {
            get => DateTimeStamp.ToDateTime();
            set { DateTimeStamp = Timestamp.FromDateTime(value.ToUniversalTime()); }
        }
 
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}
```

**Step 6**

In the **Server project** , add gRPC services to the container. In the **Startup.cs** file, modify the **ConfigureServices** method by adding this code:

```csharp
services.AddGrpc();
```

To optimize the performance, I recommend taking advantage of response compression by adding the following code too:

```csharp
services.AddResponseCompression(opts =>
            {
                opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                    new[] { "application/octet-stream" });
            });
```

**Step 7**

Now, it’s time to implement the logic of our application in a service class, add it to the container, and also use it to modify the controller generated by the template. The service class will be something like the code below.

```csharp
public class WeatherForecastService : 
 BlazorGrpc.Shared.WeatherForecastService.WeatherForecastServiceBase  
 
{
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
 
        public override Task<WeatherForecastResponse> GetWeatherForecast(Empty request, ServerCallContext context)
        {
            var response = new WeatherForecastResponse();
 
            response.Forecasts.AddRange(GetWeatherForecast());
 
            return Task.FromResult<WeatherForecastResponse>(response);
        }
 
        public IEnumerable<WeatherForecast> GetWeatherForecast()
        {
            var rng = new Random();
            return Enumerable.Range(1, 365).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            });
        }
}
```

**Note:** The WeatherForecastService class is inherited from BlazorGrpc.Shared.WeatherForecastService.WeatherForecastServiceBase, which is generated automatically from the .proto file.

**Step 8**

Go back to the **Startup.cs** file to configure the gRPC-Web middleware in the **Configure** method as shown in the following code, so that all the services will support gRPC-Web by default.

```csharp
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
```

Then, add the route with the following code:

```csharp
app.UseEndpoints(endpoints =>
      {
       endpoints.MapGrpcService<WeatherForecastService>();
      }
```

**Step 9**

Let’s move on to the client project. First, add the **WeatherForecastService** to the container, then create a gRPC-Web channel pointing to the back-end server and instantiate the gRPC clients for this channel.

Refer to the following code to modify the **Program.cs** file, to which we need to add additional required namespaces.

```csharp
builder.Services. AddSingleton(services =>
            {
                var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
                var backendUrl = services.GetRequiredService<NavigationManager>().BaseUri;
                var channel = GrpcChannel.ForAddress(backendUrl, new GrpcChannelOptions { HttpClient = httpClient });
 
                return new WeatherForecastService.WeatherForecastServiceClient(channel);
});
```

**Note:** The **WeatherForecastService.WeatherForecastServiceClient** class is also generated automatically from the .proto file.

**Step 10**

Finally, add the **FetchDataGrpc.razor** file and make some small changes to the **FetchData.razor** and **NavMenu.razor** files. Don’t forget to make changes to the **\_Imports.razor** file as well.

Refer to the following code.

```html
@page "/fetchdatagrpc"
@inject WeatherForecastService.WeatherForecastServiceClient WeatherForecastServiceClient
@using Blazorgrpc.Shared
@using Google.Protobuf.WellKnownTypes
<h1>Weather forecast</h1>
 
<p>This component demonstrates fetching data from the gRPC service.</p>
 
@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}
 
@code {
 
    private IList<WeatherForecast> forecasts;
 
    protected override async Task OnInitializedAsync()
    {
        forecasts = (await WeatherForecastServiceClient.GetWeatherForecastAsync(new Empty())).Forecasts;
    }
}
```

That’s all folks! Now, we can have fun in testing our work. After implementing the above code examples, we will get a result like the following screenshot:

![Result](https://www.syncfusion.com/blogs/wp-content/uploads/2020/08/Result.jpg)We can see that both pages return the same data, but one consumes a REST service, the other consumes a gRPC service.

Test them all and inspect the network traffic to see the real advantage.

![Network Traffic Comparison](https://www.syncfusion.com/blogs/wp-content/uploads/2020/08/Network-Traffic-Comparison.jpg)<figcaption>Network Traffic Comparison</figcaption>

In the screenshot above, you can see that the REST service has sent 55.6 KB, but the gRPC service has sent only 10.1 KB!

## Resource

The converted project is available in this [GitHub repository](https://github.com/SyncfusionExamples/gRPC-Web-in-Blazor-WebAssembly).

## Conclusion

In this post, we have seen how to create a gRPC service in a Blazor WebAssembly-hosted application and how this solution brings significant performance benefits. This will be helpful in limited-bandwidth scenarios and will definitely speed up data transfer operations.

Try it out yourself and leave your feedback in the comments section below!

[Syncfusion Essential Studio for Blazor](https://www.syncfusion.com/blazor-components) offers 65+ high-performance, lightweight, and responsive UI components for the web, including file-format libraries, in a single package. Please take a look at our live demos in our [sample browser](https://blazor.syncfusion.com/) for a hands-on experience.

For existing customers, the latest version is available for download from the [License and Downloads](https://www.syncfusion.com/account/downloads) page. If you are not yet a Syncfusion customer, you can try our 30-day [free trial](https://www.syncfusion.com/downloads) to check out the available features. Also, you can try our samples from this [GitHub](https://github.com/syncfusion) location.

You can also contact us through our [support forums](https://www.syncfusion.com/forums), [Direct-Trac](https://www.syncfusion.com/support/directtrac/incidents), or [feedback portal](https://www.syncfusion.com/feedback/blazor-components). We are always happy to assist you!

If you like this post, we think you will also like the following:

- [MVVM Pattern in Blazor for State Management—A Complete Guide](https://dev.to/syncfusion/mvvm-pattern-in-blazor-for-state-management-a-complete-guide-3cj1) [Blog]
- [CSV Data Sources in Blazor Pivot Table: A Groundbreaking Feature](https://dev.to/syncfusion/csv-data-sources-in-blazor-pivot-table-a-groundbreaking-feature-69) [Blog]
- [Build PWAs with Blazor WebAssembly Using Syncfusion Blazor Components](https://dev.to/sureshmohan/build-pwas-with-blazor-webassembly-using-syncfusion-blazor-components-webinar-show-notes-lam-temp-slug-2519605) [Webinar Show Notes]
- _[Blazor Succintly](https://www.syncfusion.com/ebooks/blazor-succinctly)_ [Ebook]