Closed dodyg closed 1 year ago
Thank you for reporting your issue.
You did not state what line of code causes the error. Does the error happen when you call GetWebWorker
, or when you call a method (DoAsync
here) on it?
The error is due to something else in your code that is not here. Please show your full index.html file and your Program.cs file from your Blazor WASM project. The full output from the console may also help.
You may be using Javascript script that is leading to the issue (not necessarily the cause.) I need the info requested so I can get an idea of what might be going on. Thank you.
I did a little checking and I believe you may be following the Microsoft docs example (or similar) Dynamically set the client-side culture by user preference
If that is the case there are ways around the issue depending on whether or not you need culture localization in the WebWorker also.
For example, if you do not need localization in the WebWorker you can simply add a condition statement around the culture checking code like below.
Unmodified example code from the MS Culture example
builder.Services.AddLocalization();
var host = builder.Build();
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
Modified example code to detect if the app is running in a Window and only then load the culture info.
builder.Services.AddLocalization();
var host = builder.Build();
var JS = host.Services.GetRequiredService<BlazorJSRuntime>();
if (JS.IsWindow)
{
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
Part of the problem with the code on that page when working with the WebWorker is that it assumes the code is running in a Window global scope. It even uses localStorage
to store and retrieve the culture info but localStorage does not exist in a Worker global scope. See below example code from that page.
Unmodified Javascript code snippet from MS example
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
If you do need culture info in your WebWorker you will likely need to store it someplace other than localStorage so the WebWorker can access it.
Hope this information helps. Good luck. I am here if you need additional help.
Solution 2
This solution enables culture support in WebWorkers.
Upgrade your SpawnDev.BlazorJS.WebWorkers reference to 2.2.11 and change your code to use either IndexedDB or Cache, instead of localStorage, like in the example below.
Again, from the MS example in your index.html
Change the below code that will not work in a WebWorker context
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
To this code that will work in all contexts
<script webworker-enabled>
blazorCulture = {
get: async () => {
var cache = await caches.open('BlazorCulture');
var response = await cache.match('/culture');
return response ? await response.text() : null;
},
set: async (value) => {
var cache = await caches.open('BlazorCulture');
await cache.put('/culture', new Response(value));
}
};
</script>
When loading a WebWorker, SpawnDev.BlazorJS.WebWorkers ignores all <script>
tags in index.html except those marked with the attribute "webworker-enabled". Version 2.2.10 and below only supported remote scripts (src attribute.) I added support for inline scripts in version 2.2.11 so that this example would work.
I did a little checking and I believe you may be following the Microsoft docs example (or similar) Dynamically set the client-side culture by user preference
Indeed
I am trying solution 2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Taly BNPL </title>
<base href="/" />
<link href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" rel="stylesheet">
<link href="_content/Blazorise/blazorise.css" rel="stylesheet" />
<link href="_content/Blazorise.Bootstrap5/blazorise.bootstrap5.css" rel="stylesheet" />
<link href="_content/Blazorise.LoadingIndicator/blazorise.loadingindicator.css" rel="stylesheet" />
<link href="_content/Blazorise.SpinKit/blazorise.spinkit.css" rel="stylesheet" />
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
<link href="css/app.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="Taly.BNPL.Admin.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://fastly.jsdelivr.net/npm/chartjs-plugin-annotation@2.2.1"></script>
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="/js/app.js"></script>
<script webworker-enabled>
blazorCulture = {
get: async () => {
var cache = await caches.open('BlazorCulture');
var response = await cache.match('/culture');
return response ? await response.text() : null;
},
set: async (value) => {
var cache = await caches.open('BlazorCulture');
await cache.put('/culture', new Response(value));
}
};
</script>
<script>
function loadBootstrapCss(direction) {
var head = document.getElementsByTagName('head')[0]
if (direction === 'ltr') {
const fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", "https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css")
head.append(fileref)
const html = document.getElementsByTagName('html')[0]
html.setAttribute('lang', 'en')
html.setAttribute('dir', 'ltr')
}
else {
const fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", "https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css")
head.append(fileref);
const html = document.getElementsByTagName('html')[0]
html.setAttribute('lang', 'ar')
html.setAttribute('dir', 'rtl')
}
}
if (!window.blazorCulture.get() || window.blazorCulture.get() == 'en-US')
loadBootstrapCss('ltr');
else
loadBootstrapCss('rtl');
</script>
</body>
</html>
Program.cs
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await host.BlazorJSRunAsync();
Project
<PackageReference Include="SpawnDev.BlazorJS.WebWorkers" Version="2.2.11" />
Error
VM6:3 Debugging hotkey: Shift+Alt+D (when application has focus)
invoke-js.ts:176 info: System.Net.Http.HttpClient.Default.ClientHandler[101]
Received HTTP response headers after 2305.2ms - 200
invoke-js.ts:176 info: System.Net.Http.HttpClient.Default.LogicalHandler[101]
End processing HTTP request after 2334ms - 200
VM6:3 Error: One or more errors occurred. (Could not find 'blazorCulture.get' ('blazorCulture' was undefined).
Error: Could not find 'blazorCulture.get' ('blazorCulture' was undefined).
at eval (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:368)
at Array.forEach (<anonymous>)
at l.findFunction (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:336)
at w (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:5079)
at eval (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:2872)
at new Promise (<anonymous>)
at y.beginInvokeJSFromDotNet (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:2835)
at Object.nn [as invokeJSJson] (eval at initScriptElement (spawndev.blazorjs.webworkers.faux-env.js:236:26), <anonymous>:3:53726)
at invoke-js.ts:233:31
at El (invoke-js.ts:276:5))
at Jn (marshal-to-js.ts:349:18)
at El (marshal-to-js.ts:306:28)
at 00b1e17a:0x1fac9
at 00b1e17a:0x1bf8a
at 00b1e17a:0xf171
at 00b1e17a:0x1e7e3
at 00b1e17a:0x1efd9
at 00b1e17a:0xcfeb
at 00b1e17a:0x440a0
at e.<computed> (cwraps.ts:338:24)
callEntryPoint @ VM6:3
await in callEntryPoint (async)
Qt @ VM6:3
await in Qt (async)
ln @ VM6:3
initWebWorkerBlazor @ spawndev.blazorjs.webworkers.js?verbose=false:225
await in initWebWorkerBlazor (async)
(anonymous) @ spawndev.blazorjs.webworkers.js?verbose=false:232
Solution 1 generates no errors
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Taly BNPL </title>
<base href="/" />
<link href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" rel="stylesheet">
<link href="_content/Blazorise/blazorise.css" rel="stylesheet" />
<link href="_content/Blazorise.Bootstrap5/blazorise.bootstrap5.css" rel="stylesheet" />
<link href="_content/Blazorise.LoadingIndicator/blazorise.loadingindicator.css" rel="stylesheet" />
<link href="_content/Blazorise.SpinKit/blazorise.spinkit.css" rel="stylesheet" />
<link rel="stylesheet" href="_content/Radzen.Blazor/css/material-base.css">
<link href="css/app.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="Taly.BNPL.Admin.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://fastly.jsdelivr.net/npm/chartjs-plugin-annotation@2.2.1"></script>
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/Radzen.Blazor/Radzen.Blazor.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="/js/app.js"></script>
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
function loadBootstrapCss(direction) {
var head = document.getElementsByTagName('head')[0]
if (direction === 'ltr') {
const fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", "https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css")
head.append(fileref)
const html = document.getElementsByTagName('html')[0]
html.setAttribute('lang', 'en')
html.setAttribute('dir', 'ltr')
}
else {
const fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", "https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css")
head.append(fileref);
const html = document.getElementsByTagName('html')[0]
html.setAttribute('lang', 'ar')
html.setAttribute('dir', 'rtl')
}
}
if (!window.blazorCulture.get() || window.blazorCulture.get() == 'en-US')
loadBootstrapCss('ltr');
else
loadBootstrapCss('rtl');
</script>
</body>
</html>
Program.cs
var host = builder.Build();
var blazorJs = host.Services.GetRequiredService<BlazorJSRuntime>();
if (blazorJs.IsWindow)
{
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
await host.BlazorJSRunAsync();
I have successfully used Solution 1 to execute this piece of code. Thank you for your help @LostBeard .
public interface INotificationWorker
{
Task<Result<ListNotificationResponse>> FetchNotifications();
}
public class NotificationWorker(IJSRuntime js, IBFFAPIClient client) : INotificationWorker
{
public async Task<Result<ListNotificationResponse>> FetchNotifications()
{
var request = new ListNotificationRequest();
var response = await client.ListNotificationAsync(request);
if (response.IsFalse)
{
JsConsole.Error(js, $"Error in calling {nameof(FetchNotifications)} {response.Message}");
return Result<ListNotificationResponse>.False(response.Message);
}
if (response.Value.IsStatus(StatusCodes.Status200OK) is false)
{
JsConsole.Error(js, $"Error in {nameof(FetchNotifications)} result {response.Value.Header.Status}");
return Result<ListNotificationResponse>.False(response.Value.Header.Status.ToString());
}
return Result<ListNotificationResponse>.True(response.Value.Body!);
}
}
I am trying solution 2
Solution 2 works just fine. You got an error because the WebWorker used a cached version of your index.html. Same thing happened to me on the first test of the code. Simply disabling caching via the DevTools and refreshing allowed the new index.html to be loaded.
Glad you found a usable solution. 👍
I encounter this error on .NET 8 RC-1
Program.cs
On Razor
The interface
On the project