Tag Archives: HAVIT Blazor

gRPC code-first for Blazor WebAssembly front-end

gRPC is a phenomenon of our time. This modern and performance-efficient protocol is rapidly spreading, and today we will show how to use it for communication between the Blazor WebAssembly front-end and the ASP.NET Core backend (host):

  1. We will efficiently use the possibilities of sharing code between the server and client part. We will use the code-first arrangement and put the “contract” (interface for the called service and data object definitions) into the assembly shared by both the server and client parts of the solution.
  2. To overcome browser limitations, we will use the gRPC-Web extension.

We will show the entire implementation on a simple example – we will use the default Blazor WebAssembly App template from Visual Studio (ASP.NET Core hosted, version of the .NET7 template) and we will convert the prepared Fetch data example, which uses the REST API in this template, to a gRPC-Web call using code-first.

Let’s do this, it’s just a few steps:

1. MyBlazorSolution.Server – Preparing ASP.NET Core host

First, we prepare the server-side infrastructure for gRPC. We will go directly to the version with the gRPC-Web extension with code-first support and install NuGet packages

We register support services in dependency-injection in Startup.cs:

builder.Services.AddCodeFirstGrpc(config => { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });

We add gRPC middleware somewhere between UseRouting() and endpoint definition (before MapXy() methods):

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

2. MyBlazorSolution.Shared – Service contract definition (code-first)

Now we define in the form of an interface what our service will look like. We will then use the interface on the server side (we will create its implementation) and on the client side (we will generate a gRPC client that will implement the interface and we will directly use it in our code via dependency injection).
Add to the project a NuGet package that allows us to decorate the interface with necessary attributes

Find the example WeatherForecast.cs file from the project template. It contains the definition of the return data message, which the sample REST API now returns to us. We will convert this class into the following form:

[DataContract]
public class WeatherForecast
{
    [DataMember(Order = 1)]
    public DateTime Date { get; set; }

    [DataMember(Order = 2)]
    public int TemperatureC { get; set; }

    [DataMember(Order = 3)]
    public string? Summary { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
  • We added the [DataContract] attribute to mark the class we will use as the gRPC data message.
  • We added [DataMember(Order = ...)] attributes that mark the elements to be transmitted via gRPC (others are ignored, here TemperatureF is calculated and recalculated from other data on the client anytime). Each element needs to be set Order, which defines the fixed layout for the used protobuf serialization.
  • We replaced the original DateOnly type with DateTime. We have to stick to types supported by used protobuf serialization.

Next, we need to create an interface that will describe the whole service:

[ServiceContract]
public interface IWeatherForecastFacade
{
    Task<List<WeatherForecast>> GetForecastAsync(CancellationToken cancellationToken = default);
}
  • The [ServiceContract] attribute tells us the applicability for gRPC (can be used later for automatic registrations).
  • By the nature of network communication, the entire interface should be asynchronous.
  • We can use the optional CancellationToken, which can convey a signal of premature termination of communication by the client (or disconnection).

3. MyBlazorSolution.Server – Implementing the gRPC service

Now we need to implement the prepared interface on the server side (we will use slightly modified code from the sample WeatherForecastController, which you can now delete):

public class WeatherForecastFacade : IWeatherForecastFacade
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public Task<List<WeatherForecast>> GetForecastAsync(CancellationToken cancellationToken = default)
    {
        return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Today.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToList());
    }
}

Now we have to add the gRPC service in Startup.cs:

app.MapGrpcService<WeatherForecastFacade>();

4. MyBlazorSolution.Client – gRPC client in Blazor WebAssembly

Now all that is left is to use the service in the Blazor WebAssembly front-end. The entire definition is available in the form of the IWeatherForecastFacade interface with its WeatherForecast data class.

We will add the necessary NuGet packages to the project:

Register the gRPC-Web infrastructure and the client (in factory form) in Program.cs:

builder.Services.AddTransient<GrpcWebHandler>(provider => new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));

builder.Services.AddCodeFirstGrpcClient<IWeatherForecastFacade>((provider, options) => =>
    {
        var navigationManager = provider.GetRequiredService<NavigationManager>();
        var backendUrl = navigationManager.BaseUri;

        options.Address = new Uri(backendUrl);
    })
    .ConfigurePrimaryHttpMessageHandler<GrpcWebHandler>();

Well, now we can use IWeatherForecastFacade anywhere in the front-end project by having the service injected using dependency injection. So, for example, we’ll modify FetchData.razor to use our new gRPC service instead of the original REST API:

@inject IWeatherForecastFacade WeatherForecastFacade

...

@code {
    private List<WeatherForecast>? forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await WeatherForecastFacade.GetForecastAsync();
    }
}

Done. The project should now be executable and the Fetch data page will now communicate via gRPC-Web.

You can check your solution against the sample repository

Other extensions and more advanced techniques

The gRPC service can, of course, accept input. In this case, use one input parameter for the incoming message – a data class created in the same way we prepared the WeatherForecast output. (Usually these classes are referred to as Data Transfer Object and thus given the suffix Dto. The implementation is usually as a C# record.)

If we have authentication and authorization in our project, then we can use the [Authorize] attribute on the implementing class/method, just as we would on a controller/action.

We can apply arbitrary techniques to the published gRPC endpoint like any other mapped server endpoint (rate limiting, caching, …).

gRPC has support for interceptors which can be used to further improve gRPC communication

  • pass exceptions from server to client (basic support is built-in, but you may want to enrich it with specific handling of custom scenarios),
  • passing the required culture from client to server (what language the front-end is switched to),

In a more advanced variant of the layout, you can also provide automatic registration of interface and data contracts without having to decorate them with [ServiceContract], [DataContract] and [DataMember(Order = ...)] attributes. All this and much more can be found ready in:

Both open-source with MIT license, free of charge.

Announcing HAVIT Blazor 1.4.3 – Free Bootstrap 5 components for ASP.NET Blazor

Didn’t have a chance to announce our component bundle on this KnowledgeBase yet…

Now we released version 1.4.3. What’s new?

  • HxInputDateHxInputDateRange and HxCalendar have new MinDate and MaxDate parameters to allow customization of selectable dates in calendars (also added to Defaults to be able to customize the application-wide defaults)
  • HxInputDate and HxInputDateRange have new CalendarDateCustomizationProvider which allows further customization (enabled/disabled, CssClass) of individual dates in dropdown calendars
  • ⚠️ HxCalendar parameters MinYear and MaxYear replaced with the new MinDate and MaxDate parameters
  • HxCalendar has new simplified month/year navigation
  • HxInputDate fixed validation icon position if CalendarIcon is used
  • HxInputFileCore has new HxInputFileCore.Defaults.MaxFileSize application-wide default to be able to limit maximum file size,
  • HxInputFile has new HxInputFile.Defaults.InputSize application-wide default to be able to set form component size
  • HxSidebar fixed ability to scroll on mobile if viewport is overlapped
  • HxSidebar has new CSS variable for customising background-colour
  • Updated to Bootstrap 5.1.3 and Bootstrap Icons 1.6

What is HAVIT Blazor?

HAVIT Blazor is a free open-source (MIT) component bundle build on top of Bootstrap 5. It not only covers all Bootstrap 5 components but also brings a few enterprise-level ones (e.g. HxGrid, HxInputDate, HxAutosuggest, HxInputTags) and special ones (e.g. HxGoogleTagManager).

Interactive documentation & demos – https://havit.blazor.eu

Source code – https://github.com/havit/Havit.Blazor

Forms

Buttons & Indicators

Data & Grid

Layout & Typography

Navigation

Modals & Interactions

Special

Enterprise-application template [OPTIONAL]

Beside the components there is a ready to run enterprise level application template which includes gRPC code-first communication, full layered architecture stack (Model, DataLayer, Services, …) and much more.