Remal.BlazorServiceGenerator 0.1.3

dotnet add package Remal.BlazorServiceGenerator --version 0.1.3
NuGet\Install-Package Remal.BlazorServiceGenerator -Version 0.1.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Remal.BlazorServiceGenerator" Version="0.1.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Remal.BlazorServiceGenerator --version 0.1.3
#r "nuget: Remal.BlazorServiceGenerator, 0.1.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Remal.BlazorServiceGenerator as a Cake Addin
#addin nuget:?package=Remal.BlazorServiceGenerator&version=0.1.3

// Install Remal.BlazorServiceGenerator as a Cake Tool
#tool nuget:?package=Remal.BlazorServiceGenerator&version=0.1.3

Blazor Service Source Generator

Source generator that reduce boilerplate code needed to make WebAssembly compatible blazor services.

Installation

You can install using NuGet

dotnet add package Remal.BlazorServiceGenerator --version 0.1.3

NOTE: The generator requires extra setup before it is functioning properly. See setup section.

The Problem

Let's start with a basic Blazor solution. There are probably 3 projects Shared, Server and Client. Somewhere in the Server project there is a piece of code like this:

Server / Greeter.razor

@page "/Greeter"
@using BlazorApp.Shared.Services
@rendermode InteractiveServer

@inject IGreeterService GreeterService

Enter your name:
<input type="text" @bind="Name"/>

<button @onclick="Great">Great</button>

@if (Greeting != null)
{
    <p>Server Greeting: @Greeting</p> 
}

@code {
    private string Name { get; set; } = string.Empty;
    private string? Greeting { get; set; }
    
    private async Task Great()
    {
        Greeting = await GreeterService.Greet(Name);
    }
}

With service like this:

Server / GreeterService.cs

public class GreeterService : IGreeterService
{
    public async Task<string> Greet(string name)
    {
        // TODO use an AI driven blockchain stack to retrieve a personalized greeting message  
        await Task.Delay(200);
        
        return $"Hello, {name}!";
    }
}

If you want to make this component compatible with WebAssembly you need to implement IGreeterService again but this time with http client which is mostly boilerplate code.

Client / GreeterBlazorService.cs

public class GreeterBlazorService : IGreeterService
{
    private HttpClient HttpClient { get; }
	
    public GreeterBlazorService(HttpClient httpClient)
    {
        HttpClient = httpClient;
    }
    
    public async Task<string> Greet (string name)
    {
        string path = $"/GreeterService/Greet?name={name}";
        return await HttpClient.GetStringAsync(path);
    }
	
}

Make sure to also add the new service to blazor dependencies in client project

Client / Program.cs

builder.Services.AddScoped<IGreeterService, GreeterBlazorService>();

And then add appropriate endpoint mapping for /GreeterService/Greet either through MVC or minimal APIs:

Server / Program.cs

app.MapGet("/GreeterService/Greet", ([FromQuery] string name, [FromServices] IGreeterService service) => service.Greet(name));

This code gets redundant very quickly, epically if you are moving many components to WebAssembly

The Solution

After installing and setting up BlazorServiceGenerator you can mark an interface with [BlazorService] attribute. This will auto generate all previous boilerplate including:

  • HttpClient based service implementation
  • Adding service as dependency to Client project
  • Endpoint mappings for Server project

Shared / IGreeterService.cs

[BlazorService]
public interface IGreeterService
{
    // ...
}

Setup

After adding the generator to the Shared project. There will be a one time setup process to make sure the generator works properly.

First: make sure the Shared project has framework reference for Microsoft.AspNetCore.App.

Shared.csproj

<ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" PrivateAssets="all" />
    ...
</ItemGroup>

Second: make sure the Client project has the following in its PropertyGroup:

Client.csproj

<PropertyGroup>
    ...
    <GenerateMvcApplicationPartsAssemblyAttributes>false</GenerateMvcApplicationPartsAssemblyAttributes>
</PropertyGroup>

Third: Add blazor service dependencies to Client project.

Client / Program.cs

// This method is auto generated and may not be avialable before using [BlazorService]
builder.Services.AddBlazorServices();

Finally: Add endpoint mapping to Server project.

Server / Program.cs

// This method is auto generated and may not be avialable before using [BlazorService]
app.MapBlazorServices();

Limitations

There are some limitations on interfaces that can be marked as [BlazorService]. Some are due to network requirement others are just to reduce complexity.

  • All BlazorService methods must be await-able - By Design - code should be asynchronous due to network usage
  • Member must be a method - By Design - extenstion of previous rule
  • Return type must be serializable - By Design - due to network usage
  • Method parameters must be serializable - By Design - due to network usage
  • Method may not be generic - Technical - to reduce generator complexity

License

This project is licensed under the terms of the MIT license.

Copyright (c) 2024 Ali Albarrak

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.1.3 84 4/21/2024
0.1.2 80 4/21/2024
0.1.1 85 4/20/2024
0.1.0 77 4/20/2024