Download this package from Nuget.
SqliteWasmHelper
is a package designed to make it easy to work with SQLite databases
in Blazor Wasm apps. Although you could install Eric Sink's
SQLitePCLRaw.bundle_e_sqlite3
package directly, that will only provide an in-memory implementation. This package
automatically injects the code needed to persist your database in cache with the
help of EF Core.
WARNING The browser cache is both easily accessible by the end user and can be flushed any time. Do not use SQLite in the browser to store sensitive data. Do not use it to store user-entered data unless the data is temporary in nature or you have a process to synchronize data to the back end.
Let's get right to the point! Boring text follows, a more exciting video with questionable audio quality can be viewed here:
📽️ How to use SQLiteWasmHelper to add EF Core 6.0 and SQLite to your Blazor WebAssembly projects
For the Wasm client to get properly linked, you must have the WebAssembly Tools workload installed.
- Install the lastest SQlite in WebAssembly helper NuGet package or reference the
SqliteWasmHelper
project. This automatically installs all necessary dependencies:SqliteWasmHelper
- Entity Framework Core and the SQLite provider
- The SQLitePCLRaw.bundle for running SQLite in WebAssembly
- Add the following to the
.csproj
file for your Blazor WebAssembly project (it can be added to an existingPropertyGroup
):<PropertyGroup> <WasmBuildNative>true</WasmBuildNative> </PropertyGroup>
- Add
using SqliteWasmHelper;
to the top of theProgram.cs
file in your Blazor WebAssembly project - Use the extension method to add a special
DbContext
factory:builder.Services.AddSqliteWasmDbContextFactory<ThingContext>( opts => opts.UseSqlite("Data Source=things.sqlite3"));
- Inject the factory into the components that need it
@inject ISqliteWasmDbContextFactory<ThingContext> Factory
- Use the
DbContext
as you normally wouldusing var ctx = await Factory.CreateDbContextAsync(); ctx.Things.Add(new Thing { Name = newThing }); await ctx.SaveChangesAsync();
- If you want access to the file, look at the GenerateDownloadLinkAsync documentation or use/customize the BackupLink component.
The BlazorWasmExample
is a working example to show it in use.
⚠️ IMPORTANT The helper requires JavaScript interop to store the database in cache. For this reason, it is important you always callSaveChangesAsync
notSaveChanges
when saving updates. Any other operations such as callingEnsureCreated
or executing queries can be done either synchronously or asynchronously.
⚠️ ALSO IMPORTANT The helper callsEnsureCreated
on the database before passing control to JavaScript. This won't conflict with other calls but may lead to unexpected behavior. For example, if you seed your database based on a successful call, you will need to change your logic to check for data in tables instead of using theEnsureCreated
result.
When your app requests a DbContext
, the special factory uses JavaScript interop to
check for the existence of a cache. If the cache exists, it is restored and returned,
otherwise a new database is created.
graph TD
A(Start) --> B[Get filename from data source]
B --> C{First time?}
C -->|Yes| D[Generate restore filename]
C -->|No| E[Generate backup filename]
D --> G[Call JavaScript]
E --> F[Backup database]
F --> G
G --> H{First time?}
H -->|Yes| I{Backup in cache?}
H -->|No| K[Store backup to cache]
I -->|Yes| J[Restore to Wasm filesystem]
I --> |No| L
J --> L[Return to DotNet]
K --> L
L --> M{Backup loaded from cache?}
M --> |Yes| N[Restore database]
M --> |No| O(End)
N --> O
The first time you context is generated, the database will be restored if a backup exists in cache. Any call to SaveChangesAsync
will result in the database being saved to cache.
To see the cache, open developer tools in your browser and navigate to Application -> Cache -> Cache Storage -> SqliteWasmHelper. The key for your database is /data/cache/filename
.
Run the application and use F12 to open developer tools. Navigate to the Console tab. Open the cache:
const cache = await caches.open('SqliteWasmHelper');
Now load the database backup from the cache. Swap things.db
with the filename of your database.
const resp = await cache.match('/data/cache/things.db');
If the resp
instance is populated, access the underlying blob:
const blob = await resp.blob();
Finally, generate the link. This should emit a link to the console you can click on to download your database.
URL.createObjectURL(blob);
You can then examine the database with your SQLite tool of choice. You can use a similar approach for synchronization but sending the blob to the server.
Read the autogenerated API Docs.
Read the release notes.
Questions? DM @JeremyLikness or open a GitHub issue.