It is now 2022. .NET 6 has shipped, and Blazor WebAssembly has support for compiled binaries.
That means there are now three options for using a database in a Blazor WebAssembly application.
#1. Create a webApi. Call the webApi on from the client as you can see being done in the default sample. See FetchData.razor
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
and WeatherForecastController.cs on the server. The default solution does not call a database, but you could easily use a dbContext in Get() to pull data from a database.
#2: With support for compiled binaries in Blazor WebAssembly, it is now possible to completely host Sqlite in WebAssembly.
https://github.com/TrevorDArcyEvans/BlazorSQLiteWasm
#3: IndexedDb. Through js interop, the IndexDb in the browser can be used. Large amounts of data can be stored in this Db, and like the name implies, it is indexed. Since this can be accidentally cleared, it is most useful in a PWA, where that is more difficult. Also, with this and Sqlite, anything done in the browser is open to the user and hackers that compromise the user's maching.
I use https://github.com/wtulloch/Blazor.IndexedDB
You add schema in program.cs:
builder.Services.AddIndexedDB(dbStore =>
{
dbStore.DbName = "SomeDbName";
dbStore.Version = 1;
dbStore.Stores.Add(new StoreSchema
{
Name = "People",
PrimaryKey = new IndexSpec { Name = "id", KeyPath = "id", Auto = false },
Indexes = new List<IndexSpec>
{
new IndexSpec{Name="alias", KeyPath = "alias", Auto=false},
new IndexSpec{Name="isAvailable", KeyPath = "isAvailable", Auto=false},
new IndexSpec{Name="communityId", KeyPath = "communityId", Auto=false},
new IndexSpec{Name="isFriend", KeyPath = "isFriend", Auto=false},
}
});
});
In this code, the names of the fields are camelCased, whereas the objects I'm constructing are PascalCase. This was actually necessary for me to get it to work. I think my serializer may be set to camelCase Json or something, so watch that.
And then you add remove and search using:
public async Task AddPersonAsync(LocalPerson member)
{
var newPerson = new StoreRecord<LocalPerson>
{
Data = member,
Storename = PeopleStoreName
};
await _dbManager.AddRecord(newPerson);
}
public async Task<LocalPerson> GetPersonByIdAsync(Guid id)
{
var localPerson = await _dbManager.GetRecordById<Guid, LocalPerson>(PeopleStoreName, id);
return localPerson;
}
public async Task<List<LocalPerson>> GetPeopleAsync()
{
var results = await _dbManager.GetRecords<LocalPerson>(PeopleStoreName);
return results;
}
public async Task<List<LocalPerson>> GetPeopleByCommunityAsync(Guid id)
{
var indexSearch = new StoreIndexQuery<Guid>
{
Storename = PeopleStoreName,
IndexName = "communityId",
QueryValue = id,
};
var result = await _dbManager.GetAllRecordsByIndex<Guid, LocalPerson>(indexSearch);
if (result is null)
{
return new List<LocalPerson>();
}
return (List<LocalPerson>)result;
}