Skip to content

Commit 1832fa1

Browse files
authored
Feature/js direct from dotnet (#104)
* JsDirect feature + demo * Change event name to something with ":", looks nicer than underscode * hopefully slightly more readable example * Some docs for worker message service * Version up for Core
1 parent 25ffe21 commit 1832fa1

File tree

14 files changed

+219
-6
lines changed

14 files changed

+219
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@page "/JsDirect"
2+
<BlazorWorker.Demo.SharedPages.Pages.JsDirect />

src/BlazorWorker.Demo/Net8/Client/BlazorWorker.Demo.Client/Program.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using BlazorWorker.Core;
22
using BlazorWorker.Demo.Client;
33
using BlazorWorker.Demo.IoCExample;
4+
using BlazorWorker.Demo.Shared;
45
using Microsoft.AspNetCore.Components.Web;
56
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
67

@@ -11,4 +12,7 @@
1112
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
1213
builder.Services.AddWorkerFactory();
1314
builder.Services.AddIndexedDbDemoPersonConfig();
15+
16+
builder.Services.AddTransient<JsDirectExample>();
17+
1418
await builder.Build().RunAsync();

src/BlazorWorker.Demo/Shared/BlazorWorker.Demo.Shared.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
<PropertyGroup>
44
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
55
<Configurations>Debug;Release;Nuget</Configurations>
6+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
67
</PropertyGroup>
78

89
<PropertyGroup>
910
<NoWarn>1701;1702;1591;CA1416</NoWarn>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
14+
<ProjectReference Include="..\..\BlazorWorker.ServiceFactory\BlazorWorker.BackgroundServiceFactory.csproj" />
15+
<ProjectReference Include="..\..\BlazorWorker.WorkerBackgroundService\BlazorWorker.WorkerBackgroundService.csproj" />
1316
<ProjectReference Include="..\..\BlazorWorker.WorkerCore\BlazorWorker.WorkerCore.csproj" />
17+
<ProjectReference Include="..\..\BlazorWorker\BlazorWorker.Core.csproj" />
1418
</ItemGroup>
1519

1620
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using BlazorWorker.Core;
2+
using BlazorWorker.WorkerCore;
3+
using System;
4+
using System.Threading.Tasks;
5+
using BlazorWorker.BackgroundServiceFactory;
6+
using Microsoft.JSInterop;
7+
using BlazorWorker.WorkerBackgroundService;
8+
using System.Runtime.InteropServices.JavaScript;
9+
10+
namespace BlazorWorker.Demo.Shared
11+
{
12+
public partial class JsDirectExample
13+
{
14+
private readonly IWorkerFactory workerFactory;
15+
private readonly IJSRuntime jsRuntime;
16+
private IWorkerBackgroundService<JsDirectExampleWorkerService> service;
17+
private long workerId;
18+
public event EventHandler<string> LogHandler;
19+
20+
public JsDirectExample(IWorkerFactory workerFactory, IJSRuntime jsRuntime)
21+
{
22+
this.workerFactory = workerFactory;
23+
this.jsRuntime = jsRuntime;
24+
}
25+
26+
private void Log(string message)
27+
{
28+
LogHandler?.Invoke(this, message);
29+
}
30+
31+
public async Task Execute()
32+
{
33+
if (this.service == null)
34+
{
35+
Log("Execute: Creating worker...");
36+
var worker = await this.workerFactory.CreateAsync();
37+
this.workerId = worker.Identifier;
38+
Log("Execute: Creating service...");
39+
this.service = await worker.CreateBackgroundServiceAsync<JsDirectExampleWorkerService>();
40+
41+
Log("Execute: Setting up main js...");
42+
43+
// Method setupJsDirectForWorker is defined in BlazorWorker.Demo.SharedPages/wwwroot/JsDirectExample.js
44+
await this.jsRuntime.InvokeVoidAsync("setupJsDirectForWorker", this.workerId);
45+
}
46+
47+
Log("Execute: Calling ExecuteJsDirect on worker...");
48+
await service.RunAsync(s => s.ExecuteJsDirect());
49+
Log("Execute: Done");
50+
}
51+
52+
}
53+
54+
public class JsDirectExampleWorkerService
55+
{
56+
private readonly IWorkerMessageService messageService;
57+
public JsDirectExampleWorkerService(IWorkerMessageService messageService)
58+
{
59+
this.messageService = messageService;
60+
}
61+
public async Task ExecuteJsDirect()
62+
{
63+
await messageService.PostMessageJsDirectAsync("Hello main js thread.");
64+
}
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
@inject JsDirectExample jsDirectExample
2+
3+
<div class="row">
4+
<div class="col-9 col-xs-12">
5+
<script src="_content/BlazorWorker.Demo.SharedPages/JsDirectExample.js"></script>
6+
<h1>JSDirect Calls</h1>
7+
8+
Demonstrates how to receive messages from a dotnet worker on the main/ui js thread directly.
9+
Also demonstrates putting most of the logic in a separate class (JsDirectExample)
10+
<br />
11+
<br />
12+
<button disabled=@RunDisabled @onclick=OnClick class="btn btn-primary">Run test</button><br /><br />
13+
<br />
14+
<br />
15+
<div class="row">
16+
<div class="col-6 col-xs-12">
17+
<strong>JsDirect.razor Output:</strong>
18+
19+
<hr />
20+
<pre>@output</pre>
21+
</div>
22+
<div class="col-6 col-xs-12">
23+
<strong>Main js Output:</strong>
24+
<hr />
25+
<pre id="jsDirectOutputElement" style="text-wrap: pretty"></pre>
26+
</div>
27+
</div>
28+
29+
</div>
30+
<div class="col-3 col-xs-12">
31+
<GithubSource RelativePath="Pages/JsDirect.razor" />
32+
</div>
33+
</div>
34+
@code {
35+
string output;
36+
string RunDisabled => Running ? "disabled" : null;
37+
bool Running = false;
38+
39+
protected override void OnInitialized()
40+
{
41+
jsDirectExample.LogHandler += (s, e) => log(e);
42+
output = "";
43+
base.OnInitialized();
44+
}
45+
46+
public async Task OnClick(EventArgs _)
47+
{
48+
Running = true;
49+
try
50+
{
51+
await jsDirectExample.Execute();
52+
}
53+
catch (Exception e)
54+
{
55+
log($"Error = {e}");
56+
}
57+
finally
58+
{
59+
Running = false;
60+
}
61+
}
62+
63+
void log(string logStr){
64+
output += $"{Environment.NewLine}{LogDate()} {logStr}";
65+
StateHasChanged();
66+
}
67+
68+
private string LogDate()
69+
{
70+
return DateTime.Now.ToString("HH:mm:ss:fff");
71+
}
72+
}

src/BlazorWorker.Demo/SharedPages/Shared/NavMenuLinksModel.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ public class NavMenuLinksModel
3838
{
3939
new() { Icon = "document", Href="ComplexSerialization", Text = "ComplexSerialization" }
4040
},
41-
41+
{
42+
new() { Icon = "document", Href="JsDirect", Text = "JsDirect" }
43+
},
4244
{
4345
new() { Icon = "fork", Href="https://github.com/tewr/BlazorWorker", Text = "To the source!" }
4446
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function setupJsDirectForWorker(myWorkerId) {
2+
const currtime = () => [new Date()].map(d => `${d.toTimeString().split(" ")[0]}:${d.getMilliseconds()}`)[0];
3+
const output = document.getElementById('jsDirectOutputElement');
4+
output.innerText += `\n${currtime()} Setting up event listener.`;
5+
window.addEventListener('blazorworker:jsdirect', function (e) {
6+
if (e.detail.workerId === myWorkerId) {
7+
output.innerText += `\n${currtime()} blazorworker:jsdirect listener. workerId: ${e.detail.workerId}. data: '${e.detail.data}'`;
8+
}
9+
else {
10+
console.log('blazorworker:jsdirect handler for some other worker not handled by this listener', { workerId: e.detail.workerId, data: e.detail.data });
11+
}
12+
});
13+
}

src/BlazorWorker.WorkerCore/BlazorWorker.WorkerCore.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<PropertyGroup>
44
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
55
<Configurations>Debug;Release;Nuget</Configurations>
6-
<Version>4.1.0</Version>
7-
<AssemblyVersion>4.1.0.0</AssemblyVersion>
6+
<Version>4.2.0</Version>
7+
<AssemblyVersion>4.2.0.0</AssemblyVersion>
88
<Authors>Tor Knutsson (Tewr)</Authors>
99
<Company>Tor Knutsson (Tewr)</Company>
1010
<Product>BlazorWorker</Product>

src/BlazorWorker.WorkerCore/IWorkerMessageService.cs

+15
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,23 @@ namespace BlazorWorker.WorkerCore
55
{
66
public interface IWorkerMessageService
77
{
8+
/// <summary>
9+
/// Events for incoming messages to the current context
10+
/// </summary>
811
event EventHandler<string> IncomingMessage;
912

13+
/// <summary>
14+
/// Post a message to the context this message service belongs to
15+
/// </summary>
16+
/// <param name="message"></param>
17+
/// <returns></returns>
1018
Task PostMessageAsync(string message);
19+
20+
/// <summary>
21+
/// Post a message that can be read directly on the main js thread using the "blazorworker:jsdirect" event on the window object
22+
/// </summary>
23+
/// <param name="message"></param>
24+
/// <returns></returns>
25+
Task PostMessageJsDirectAsync(string message);
1126
}
1227
}

src/BlazorWorker.WorkerCore/MessageService.cs

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public static void OnMessage(string message)
2626

2727
[JSImport("PostMessage", "BlazorWorker.js")]
2828
public static partial void PostMessage(string message);
29+
30+
[JSImport("PostMessageJsDirect", "BlazorWorker.js")]
31+
public static partial void PostMessageJsDirect(string message);
2932
}
3033
}
3134
#else

src/BlazorWorker.WorkerCore/SimpleInstanceService/InjectableMessageService.cs

+7
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,12 @@ public async Task PostMessageAsync(string message)
4141
#endif
4242
MessageService.PostMessage(message);
4343
}
44+
45+
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
46+
public async Task PostMessageJsDirectAsync(string message)
47+
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
48+
{
49+
MessageService.PostMessageJsDirect(message);
50+
}
4451
}
4552
}

src/BlazorWorker/BlazorWorker.Core.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<PackageTags>WebWorker Worker Process Threading Multithreading Blazor Isolation</PackageTags>
1212
<PackageId>Tewr.BlazorWorker.Core</PackageId>
1313
<Configurations>Debug;Release;Nuget</Configurations>
14-
<Version>4.1.2</Version>
15-
<AssemblyVersion>4.1.2.0</AssemblyVersion>
14+
<Version>4.2.0</Version>
15+
<AssemblyVersion>4.2.0.0</AssemblyVersion>
1616
<DocumentationFile>BlazorWorker.Core.xml</DocumentationFile>
1717
<PackageIcon>icon.png</PackageIcon>
1818
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>

src/BlazorWorker/BlazorWorker.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ window.BlazorWorker = function () {
172172
self.postMessage(messagecontent);
173173
},
174174

175+
PostMessageJsDirect: (messagecontent) => {
176+
self.postMessage({ isJsDirect: true, jsData: messagecontent });
177+
},
178+
175179
ImportLocalScripts: async (urls) => {
176180
await self.importLocalScripts(urls);
177181
},
@@ -237,7 +241,7 @@ window.BlazorWorker = function () {
237241

238242
const initConf = {
239243
appRoot: appRoot,
240-
workerId:id,
244+
workerId: id,
241245
runtimePreprocessorSymbols: initOptions.runtimePreprocessorSymbols || {},
242246
messageEndPoint: initOptions.messageEndPoint,
243247
initEndPoint: initOptions.initEndPoint,
@@ -261,6 +265,20 @@ window.BlazorWorker = function () {
261265
};
262266

263267
worker.onmessage = function (ev) {
268+
269+
if (ev.data.isJsDirect) {
270+
if (initOptions.debug) {
271+
console.debug(`BlazorWorker.js:worker[${id}]->jsDirect`, initOptions.callbackMethod, ev.data.jsData);
272+
}
273+
274+
var event = new CustomEvent("blazorworker:jsdirect",
275+
{ detail: { workerId: id, data: ev.data.jsData } }
276+
);
277+
window.dispatchEvent(event);
278+
279+
return;
280+
}
281+
264282
if (initOptions.debug) {
265283
console.debug(`BlazorWorker.js:worker[${id}]->blazor`, initOptions.callbackMethod, ev.data);
266284
}

src/BlazorWorker/WorkerProxy.cs

+7
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ public async Task PostMessageAsync(string message)
7272
await jsRuntime.InvokeVoidAsync("BlazorWorker.postMessage", this.Identifier, message);
7373
}
7474

75+
public async Task PostMessageJsDirectAsync(string message)
76+
{
77+
throw new NotSupportedException("JsDirect calls are only supported in the direction from worker to main js");
78+
}
79+
80+
81+
7582
public long Identifier { get; }
7683
}
7784
}

0 commit comments

Comments
 (0)