Articoli

Blazor Server in un Windows Service

da

Introduzione

In ambiente locale può essere necessario avviare degli applicativi come servizi di Windows per eseguire task temporizzati, Web Api, ed altro ancora, senza avere la possibilità o la necessità d’appogiarsi ad un web server, tipo IIS.

Unitamente alla parte back-end spesso è necessario anche un front-end, ed allora è sorta la domanda :

E’ possibile creare un Blazor Server in Self-Host che gira come servizio di Windows?

La risposta è sì, e di seguito vi presento gli step per la creazione di un prototipo che accorpa le tre caratteristiche.

Creazione progetto

Partiamo dal classico template Blazor Server :

Al progetto andremo ad aggiungere :

  • un database in memoria per simulare la persistenza di una base dati
  • un servizio che accede alla base dati
  • un task temporizzato che popola il database
  • la funzionalità per essere eseguito come servizio di windows
  • alcuni tool e batch file per manipolare il servizio

L’insieme di questi step porteranno il progetto template (sx) al progetto prototipo (dx) :

Persistenza dati

All’entità WeatherForecast aggiungiamo la proprietà Id mentre al progetto aggiungiamo EntityFrameworkCore ed EntityFrameworkCore.InMemory. Creiamo un WeatherForecastDbContext per avere un contesto EF da usare per interagiare con i dati ed anche la classe WeatherForecastDbContextSeedData per popolarla.

public class WeatherForecastDbContext : DbContext
{
    public WeatherForecastDbContext(DbContextOptions<WeatherForecastDbContext> options)
    : base(options)
    {
        this.EnsureSeedData(); // Initial Seed
    }
 
    public DbSet<WeatherForecast> WeatherForecasts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseInMemoryDatabase("WeatherForecastDataBase");
    }
}

Layer di servizio

Creiamo ora un layer di servizio per l’accesso alla base dati. Questo layer è usato sia dal Worker per popolare la base dati sia nelle pagine Razor del Server Blazor per leggere ed elencare gli elementi presenti. Per mantenete un livello di astrazione maggiore creiamo anche l’interfaccia.

public interface IWeatherForecastService
{
    Task<IEnumerable<WeatherForecast>> GetAllWeatherForecasts();

    Task InsertWeatherForecast(WeatherForecast entity);
}

Nel progetto aggiungiamo il pacchetto Microsoft.Extensions.DependencyInjection e nel main registriamo il servizio :

builder.Services.AddTransient<IWeatherForecastService, WeatherForecastService>();

Task in background

Il Worker creato per derivazione dal BackgroundService ha il compito di popolare nel tempo il database attraverso il layer di servizio. Ogni 5 secondi si “risveglia” e se il numero di record non ha raggiunto 100 accoda un nuovo record creato in modo random. Anche il Worker viene registrato nel sistema di Dependency Injection di DotNet 6 ed avviato in automatico alla partenza dell’applicativo.

builder.Services.AddHostedService<Worker>();

Abilitazione a funzionare come un servizio di windows

Per ottenere questa caratteristica va aggiunto al progetto il pacchetto Microsoft.Extensions.Hosting.WindowsServices e nel main prima della build dell’applicazione va chiamata la UseWindowsService.

builder.Host.UseWindowsService();

Tool e batch

Una volta che la build ha fatto il suo lavoro ed avete pubblicato in una cartella, non vi resta che gestire il servizio. Per fare questo è stato usato NSSM, un tool che, come dice il suo autore, “non fa schifo”… “anzi”! A questo tool affianchiamo alcuni batch file che si occupano dei permessi e delle regole necessarie da impostare nel firewall.

BatchDescrizione
InstallService.batInstalla il servizio in modalità non automatica
UninstallService.batDisinstalla il servizio dopo averlo arrestato
StartService.batAvvia il servizio
StopService.batArresta il servizio
Tutti i batch devono essere avviati come amministratore.

Conclusioni

Il progetto, che trovate pubblicato su GitHub (https://github.com/dcube9/Host-Blazor-Server-As-Windows-Service), è giusto un punto di partenza per sperimentarne il comportamento.

Lo stesso meccanismo si poteva ottenere con un applicazione ASP.NET MVC e non solo, ma la possibilità d’usare Blazor Server come front-end in certi scenari è una soluzione ideale, sia per il tipo di progetto che si deve trattare sia perchè Blazor è uno strumento più familiare e con una curva d’apprendimento minore per chi non proviene dal mondo Front-End.