Skip to content

Commit

Permalink
Merge pull request #101 from Tewr/feature/IndexedDB-II
Browse files Browse the repository at this point in the history
Consistent versions, and Another fix to IndexedDb tests and demo
  • Loading branch information
Tewr authored Feb 27, 2024
2 parents d6427cf + 86814f0 commit 4c6d847
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
<NoWarn>1701;1702;1591;CA1416</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="TG.Blazor.IndexedDB" Version="1.5.0-preview" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BlazorWorker.Extensions.JSRuntime\BlazorWorker.Extensions.JSRuntime.csproj" />
<ProjectReference Include="..\BlazorWorker.WorkerCore\BlazorWorker.WorkerCore.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
Expand Down
64 changes: 64 additions & 0 deletions src/BlazorWorker.Demo.IoCExample/MyIndexDBService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Microsoft.JSInterop;
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TG.Blazor.IndexedDB;

namespace BlazorWorker.Demo.IoCExample
{
public class MyIndexDBService
{
private readonly IJSRuntime jsRuntime;
private readonly IndexedDBManager indexedDBManager;
private bool isIndexDBManagerInitialized;

public MyIndexDBService(
IJSRuntime jsRuntime,
IndexedDBManager indexDBManager)
{
//Console.WriteLine($"{nameof(MyIndexDBService)} instance created");
this.jsRuntime = jsRuntime;
this.indexedDBManager = indexDBManager;
}

public async Task<string> GetPersonName(long id)
{
try
{
//Console.WriteLine($"{nameof(GetPersonName)}({id}) called.");
await EnsureInitializedAsync();
//Console.WriteLine($"{nameof(GetPersonName)}({id}): Get Store name...");
var storeName = indexedDBManager.Stores[0].Name;
var testPersons = (await this.indexedDBManager.GetRecords<Person>(storeName));
foreach (var item in testPersons)
{
if (item.Id == id)
{
return item.Name ?? "[empty name]";
}
}

return "N/A";

}
catch (System.Exception e)
{
Console.Error.WriteLine($"{nameof(GetPersonName)} :{e}");
throw;
}
}

private async Task EnsureInitializedAsync()
{
if (!isIndexDBManagerInitialized)
{
// The following is a workaround as indexedDb.Blazor.js explicitly references "window"
await this.jsRuntime.InvokeVoidAsync("eval", "(() => { self.window = self; return null; })()");
await this.jsRuntime.InvokeVoidAsync("importLocalScripts", "_content/TG.Blazor.IndexedDB/indexedDb.Blazor.js");

isIndexDBManagerInitialized = true;
}
}

}
}
36 changes: 36 additions & 0 deletions src/BlazorWorker.Demo.IoCExample/MyIndexDBServiceStartup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using BlazorWorker.Extensions.JSRuntime;
using BlazorWorker.WorkerCore;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace BlazorWorker.Demo.IoCExample
{
public class MyIndexDBServiceStartup
{
private readonly IServiceProvider serviceProvider;
private readonly IWorkerMessageService workerMessageService;

/// <summary>
/// The constructor uses the built-in injection for library-native services such as the <see cref="IWorkerMessageService"/>.
/// </summary>
/// <param name="workerMessageService"></param>
public MyIndexDBServiceStartup(IWorkerMessageService workerMessageService)
{
this.workerMessageService = workerMessageService;
serviceProvider = ServiceCollectionHelper.BuildServiceProviderFromMethod(Configure);
}

public T Resolve<T>()=> serviceProvider.GetService<T>();

public void Configure(IServiceCollection services)
{
services.AddTransient<IMyServiceDependency, MyServiceDependency>()
.AddBlazorWorkerJsRuntime()
.AddSingleton<MyIndexDBService>()
.AddSingleton(workerMessageService)
.AddIndexedDbDemoPersonConfig();
}
}


}
37 changes: 37 additions & 0 deletions src/BlazorWorker.Demo.IoCExample/SetupIndexedDBExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using TG.Blazor.IndexedDB;

namespace BlazorWorker.Demo.IoCExample
{
public static class SetupIndexedDBExtensions
{
public static IServiceCollection AddIndexedDbDemoPersonConfig(this IServiceCollection services)
{
services.AddIndexedDB(dbStore =>
{
dbStore.DbName = "TheFactory"; //example name
dbStore.Version = 1;

dbStore.Stores.Add(new StoreSchema
{
Name = "TestPersons",
PrimaryKey = new IndexSpec { Name = "id", KeyPath = "id", Auto = true },
Indexes = new List<IndexSpec>
{
new IndexSpec{ Name = "name", KeyPath = "name", Auto = false },
}
});
});

return services;
}
}

public class Person
{
public long? Id { get; set; }
public string Name { get; set; }

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page "/IndexedDb"
<BlazorWorker.Demo.SharedPages.Pages.IndexedDb />
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BlazorWorker.Core;
using BlazorWorker.Demo.Client;
using BlazorWorker.Demo.IoCExample;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

Expand All @@ -9,5 +10,5 @@

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddWorkerFactory();

builder.Services.AddIndexedDbDemoPersonConfig();
await builder.Build().RunAsync();
143 changes: 143 additions & 0 deletions src/BlazorWorker.Demo/SharedPages/Pages/IndexedDb.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
@using BlazorWorker.Demo.IoCExample
@using BlazorWorker.Extensions.JSRuntime
@using TG.Blazor.IndexedDB
@inject IWorkerFactory workerFactory
@inject IndexedDBManager indexedDBManager

<div class="row">
<div class="col-5 col-xs-12">
<h1>.NET Worker Thread Service with IndexedDB</h1>

This page demonstrates IndexedDB.
In this example, the class @(nameof(MyIndexDBServiceStartup)) is a factory class for @(nameof(MyIndexDBService)).
The factory is implemented using ServiceCollection as an IoC Container.

The example is using the library <a href="https://github.com/wtulloch/Blazor.IndexedDB">TG.Blazor.IndexedDB</a>.

<br /><br />
<button disabled=@RunDisabled @onclick=OnClick class="btn btn-primary">Run test</button><br /><br />
<br />
<br />
<strong>Output:</strong>
<hr />
<pre>
@output
</pre>
</div>
<div class="col-7 col-xs-12">
<GithubSource RelativePath="Pages/IndexedDb.razor" />
</div>
</div>
@code {

string output = "";
IWorker worker;
IWorkerBackgroundService<MyIndexDBServiceStartup> startupService;
string canDisposeWorker => worker == null ? null : "disabled";
string RunDisabled => Running ? "disabled" : null;
bool Running = false;
public async Task OnClick(EventArgs _)
{
Running = true;
//output = "";
var rn = Environment.NewLine;
try
{

if (worker == null)
{
worker = await workerFactory.CreateAsync();
}

var sw = new System.Diagnostics.Stopwatch();
IWorkerBackgroundService<MyIndexDBService> myIocIndexedDbService;


var serviceCollectionDependencies = new string[] {
"Microsoft.Extensions.DependencyInjection.Abstractions.dll"
#if NET5_0_OR_GREATER
,"System.Diagnostics.Tracing.dll"
#endif
#if NET6_0_OR_GREATER
,"Microsoft.Extensions.DependencyInjection.dll"
#endif
};

if (startupService == null)
{
output = $"{rn}{LogDate()} Creating background service Startup class...";
StateHasChanged();

sw.Start();
startupService = await worker.CreateBackgroundServiceAsync<MyIndexDBServiceStartup>();

output += $"{rn}{LogDate()} Background service created in {sw.ElapsedMilliseconds}ms";
StateHasChanged();
}

output += $"{rn}{LogDate()} Resolving instance...";
myIocIndexedDbService = await startupService.CreateBackgroundServiceAsync(startup => startup.Resolve<MyIndexDBService>());


await using (myIocIndexedDbService)
{
long id;
var storeName = indexedDBManager.Stores[0].Name;
output += $"{rn}{LogDate()} Retrieving test person from store '{storeName}'...";
var testPerson = (await this.indexedDBManager.GetRecords<Person>(storeName)).FirstOrDefault();
if (testPerson == null)
{
output += $"{rn}{LogDate()} No test person present, creating a test person...";
await InvokeAsync(StateHasChanged);

await this.indexedDBManager.AddRecord<Person>(
new StoreRecord<Person>()
{
Storename = storeName,
Data = new Person() { Name = "Morgoff" }
});

output += $"{rn}{LogDate()} Test person record added. Verifying that it can be retrieved on the main thread...";
testPerson = (await this.indexedDBManager.GetRecords<Person>(storeName)).FirstOrDefault();
output += $"{rn}{LogDate()} Retrieved = {testPerson?.Name ??"N/A" }";

}
else
{
output += $"{rn}{LogDate()} Test person present.";
await InvokeAsync(StateHasChanged);
}

id = testPerson.Id.Value;

output += $"{rn}{LogDate()} Trying to to get the name of the test person using the worker...";
await InvokeAsync(StateHasChanged);
output += $"{rn}{LogDate()} PersonName() = {await myIocIndexedDbService.RunAsync(s => s.GetPersonName(id))}";
}

StateHasChanged();

}
catch (Exception e)
{
output += $"{rn}Error = {e}";
InvokeAsync(StateHasChanged);
}
finally
{
Running = false;
}
}

public async Task OnDisposeWorker()
{
await worker.DisposeAsync();
worker = null;
startupService = null;
}

private string LogDate()
{
return DateTime.Now.ToString("HH:mm:ss:fff");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class NavMenuLinksModel
new() { Icon = "transfer", Href="IoCExample", Text = "IoC / DI Example" }
},
{
new() { Icon = "document", Href="IndexedDB", Text = "IndexedDB" }
new() { Icon = "document", Href="IndexedDb", Text = "IndexedDB" }
},
{
new() { Icon = "document", Href="ComplexSerialization", Text = "ComplexSerialization" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<ProjectReference Include="..\BlazorWorker.WorkerCore\BlazorWorker.WorkerCore.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Nuget|AnyCPU'">
<PackageReference Include="Tewr.BlazorWorker.Core" Version="4.0.0" />
<PackageReference Include="Tewr.BlazorWorker.Core" Version="4.1.2" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<Authors>Tewr</Authors>
<Product>BlazorWorker</Product>
<Configurations>Debug;Release;Nuget</Configurations>
<Version>4.1.1</Version>
<AssemblyVersion>4.1.1.0</AssemblyVersion>
<Version>4.1.2</Version>
<AssemblyVersion>4.1.2.0</AssemblyVersion>
<PackageIcon>icon.png</PackageIcon>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
</PropertyGroup>
Expand Down Expand Up @@ -42,7 +42,7 @@
</ItemGroup>

<ItemGroup Condition="'$(Configuration)|$(Platform)'=='Nuget|AnyCPU'">
<PackageReference Include="Tewr.BlazorWorker.Core" Version="4.0.0" />
<PackageReference Include="Tewr.BlazorWorker.Core" Version="4.1.2" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/BlazorWorker.WorkerCore/InitOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public class WorkerInitOptions
/// </summary>
public WorkerInitOptions()
{
#pragma warning disable
DependentAssemblyFilenames = Array.Empty<string>();
#pragma warning restore

#if NETSTANDARD21
DeployPrefix = "_framework/_bin";
Expand Down
4 changes: 2 additions & 2 deletions src/BlazorWorker/BlazorWorker.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<PackageTags>WebWorker Worker Process Threading Multithreading Blazor Isolation</PackageTags>
<PackageId>Tewr.BlazorWorker.Core</PackageId>
<Configurations>Debug;Release;Nuget</Configurations>
<Version>4.1.1</Version>
<AssemblyVersion>4.1.1.0</AssemblyVersion>
<Version>4.1.2</Version>
<AssemblyVersion>4.1.2.0</AssemblyVersion>
<DocumentationFile>BlazorWorker.Core.xml</DocumentationFile>
<PackageIcon>icon.png</PackageIcon>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
Expand Down
8 changes: 4 additions & 4 deletions src/BlazorWorker/BlazorWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,16 @@ window.BlazorWorker = function () {
const empty = {};

// Import module script from a path relative to approot
self.importLocalScripts = async (...urls) => {
self.importLocalScripts = async (urls) => {
if (urls === undefined || urls === null) {
return;
}
if (!urls.map) {
urls = [urls]
}
const mappedUrls = urls.map(url => initConf.appRoot + (url.startsWith('/') ? '' : '/') + url);
for (const url of mappedUrls) {
await import(url);
for (const url of urls) {
const urlToLoad = initConf.appRoot + (url.startsWith('/') ? '' : '/') + url;
await import(urlToLoad);
}
};

Expand Down

0 comments on commit 4c6d847

Please sign in to comment.