Blazor è il primo framework puramente front-end sviluppato da Microsoft, nato rispettando i più moderni standard web, tra questi la possibilità di essere installato su un dispositivo emulando un'applicazione vera e propria. Questo approccio, chiamato PWA, è configurabile già in fase di creazione del progetto, spuntando una checkbox. Benche in alcuni casi sia più che sufficiente, in realtà non è che l'inizio!
In un'applicazione sviluppata per essere una PWA bisogna tenere in considerazione che l'utente potrebbe accedere in modalità offline oppure in un luogo in cui non vi è connettività, al che l'unica cosa che vedrà sarà l'interfaccia, perchè i dati, essendo recuperati tramite servizi remoti, non saranno disponibili. Da qui nasce la necessità di cambiare approccio di sviluppo: parliamo di creare applicazioni in modalità Offline First, dove i dati, o una parte di essi, una volta scaricati, vengono salvati all'interno del browser e sincronizzati successivamente con il server.
Un luogo di allocazione può essere il LocalStorage: come abbiamo visto negli scorsi script, in cui salvavamo le scelte di configurazione dell'utente, ma esso ha un limite di memoria pari a 5MB, e non possiede buone prestazioni in lettura/scrittura. Potremmo usare il SessionStorage che ha una memoria illimitata, ma volatile, quindi non adatta.
A lato di queste tecnologie che permettono un salvataggio locale troviamo IndexedDB, che potremmo definire un database integrato nel browser, nel quale possiamo salvare qualsiasi tipologia ed effettuare query in lettura.
L'implementazione in Blazor parte dall'utilizzo della libreria DnetIndexedDb installabile tramite NuGet, e di una libreria custom, allegata a questo script, contenente una serie di metodi che facilitano l'interfacciamento verso IndexedDB.
<ItemGroup> <.. /> <PackageReference Include="DnetIndexedDb" Version="2.3.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\IndexDbHelpers\IndexDbHelpers.csproj" /> </ItemGroup>
Il secondo passo consiste nella creazione di un contesto, così come avviene per Entity framework, estendendo la classe IndexedDbInterop ed un modello, al quale applicare gli attributi necessari per effetture le query
public class ApplicationIndexDb : IndexedDbInterop { public ApplicationIndexDb(IJSRuntime jsRuntime, IndexedDbOptions<ApplicationIndexDb> options) : base(jsRuntime, options) { } } public class SampleContract { [IndexDbKey] public string Id { get; set; } [IndexDbIndex] public string Name { get; set; } }
È importante notare che il modello non è stato definito all'interno del contesto, infatti l'assegnazione avverrà nel file Program.cs, nel quale inseriremo tra i servizi l'accesso al database IndexedDB, al cui interno vi sarà una tabella per SampleContract.
builder.Services.AddIndexedDbDatabase<ApplicationIndexDb>(options => { var indexedDbDatabaseModel = new IndexedDbDatabaseModel() // nome .WithName(nameof(ApplicationIndexDb)) // versione .WithVersion(1); // tabelle indexedDbDatabaseModel.AddStore<SampleContract>(); options.UseDatabase(indexedDbDatabaseModel); });
A questo punto nella pagina, o servizio, designato possiamo accedere al database tramite dependecy injection.
@page "/samples" @using IndexDbHelpers @inject ApplicationIndexDb context <p>Current count: @list.Count</p> <button class="btn btn-primary" @onclick="Add">Add!</button> @code { private IList<SampleContract> list = new List<SampleContract>(); private async Task Add() { // connessione al DB var openResult = await context.OpenIndexedDb(); // aggiunta item await context.AddItems(new List<SampleContract> { new() { Id = Guid.NewGuid().ToString(), Name = $"Contract {DateTime.Now}" } }); // lettura items list = await context.GetAll<SampleContract>(); } }
Infine, dobbiamo ricordare che tutte le operazioni, che dialogano con IndexedDB, utilizzano Interop Javascript, è quindi necessario importare lo script per gestire queste chiamate. All'interno di index.html aggiungiamo
<script src="_content/DnetIndexedDb/rxjs.min.js"></script> <script src="_content/DnetIndexedDb/dnet-indexeddb.js"></script>
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Popolare una classe a partire dal testo, con Semantic Kernel e ASP.NET Core Web API
Utilizzare Tailwind CSS all'interno di React: installazione
Effettuare il binding di date in Blazor
Aprire una finestra di dialogo per selezionare una directory in WPF e .NET 8
Criptare la comunicazione con mTLS in Azure Container Apps
Evitare il flickering dei componenti nel prerender di Blazor 8
Creazione di plugin per Tailwind CSS: espandere le funzionalità del framework dinamicamente
Utilizzare i primary constructor di C# per inizializzare le proprietà
Hosting di componenti WebAssembly in un'applicazione Blazor static
Garantire la provenienza e l'integrità degli artefatti prodotti su GitHub
Eseguire le GitHub Actions offline
Evitare (o ridurre) il repo-jacking sulle GitHub Actions