From ee249889aa9045ee9b2bc1ea70961a8112306408 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 7 Mar 2024 13:10:25 +0100 Subject: [PATCH 1/7] - more testing if the runtime is still running - testing if the promise hoilder is already disposed - added `exit` to `RuntimeAPI` - unregister from `FinalizationRegistry` in `upgrade_managed_proxy_to_strong_ref` - improve `BlazorHosted` WBT exit --- .../browser/runtime/cancelable-promise.ts | 29 +++++++++++++------ src/mono/browser/runtime/export-api.ts | 2 ++ src/mono/browser/runtime/gc-handles.ts | 3 ++ src/mono/browser/runtime/invoke-js.ts | 2 ++ src/mono/browser/runtime/managed-exports.ts | 2 ++ src/mono/browser/runtime/marshal-to-js.ts | 5 ++++ src/mono/browser/runtime/types/index.ts | 7 +++++ .../BlazorHosted.Client/Pages/Chat.razor | 2 +- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/mono/browser/runtime/cancelable-promise.ts b/src/mono/browser/runtime/cancelable-promise.ts index eafa6bd7d3d4c7..25d7427837948c 100644 --- a/src/mono/browser/runtime/cancelable-promise.ts +++ b/src/mono/browser/runtime/cancelable-promise.ts @@ -36,6 +36,10 @@ export function wrap_as_cancelable(inner: Promise): ControllablePromise } export function mono_wasm_cancel_promise(task_holder_gc_handle: GCHandle): void { + if (!loaderHelpers.is_runtime_running()) { + mono_log_debug("This promise can't be canceled, mono runtime already exited."); + return; + } const holder = _lookup_js_owned_object(task_holder_gc_handle) as PromiseHolder; mono_assert(!!holder, () => `Expected Promise for GCHandle ${task_holder_gc_handle}`); holder.cancel(); @@ -75,6 +79,11 @@ export class PromiseHolder extends ManagedObject { resolve(data: any) { mono_assert(!this.isResolved, "resolve could be called only once"); + mono_assert(!this.isDisposed, "resolve is already disposed."); + if (!loaderHelpers.is_runtime_running()) { + mono_log_debug("This promise resolution can't be propagated to managed code, mono runtime already exited."); + return; + } if (WasmEnableThreads && !this.setIsResolving()) { // we know that cancelation is in flight // because we need to keep the GCHandle alive until until the cancelation arrives @@ -89,11 +98,16 @@ export class PromiseHolder extends ManagedObject { return; } this.isResolved = true; - this.complete_task(data, null); + this.complete_task_wrapper(data, null); } reject(reason: any) { mono_assert(!this.isResolved, "reject could be called only once"); + mono_assert(!this.isDisposed, "resolve is already disposed."); + if (!loaderHelpers.is_runtime_running()) { + mono_log_debug("This promise rejection can't be propagated to managed code, mono runtime already exited."); + return; + } const isCancelation = reason && reason[promise_holder_symbol] === this; if (WasmEnableThreads && !isCancelation && !this.setIsResolving()) { // we know that cancelation is in flight @@ -109,11 +123,12 @@ export class PromiseHolder extends ManagedObject { return; } this.isResolved = true; - this.complete_task(null, reason); + this.complete_task_wrapper(null, reason); } cancel() { mono_assert(!this.isResolved, "cancel could be called only once"); + mono_assert(!this.isDisposed, "resolve is already disposed."); if (this.isPostponed) { // there was racing resolve/reject which was postponed, to retain valid GCHandle @@ -121,9 +136,9 @@ export class PromiseHolder extends ManagedObject { // and we need to use the postponed data/reason this.isResolved = true; if (this.reason !== undefined) { - this.complete_task(null, this.reason); + this.complete_task_wrapper(null, this.reason); } else { - this.complete_task(this.data, null); + this.complete_task_wrapper(this.data, null); } } else { // there is no racing resolve/reject, we can reject/cancel the promise @@ -138,11 +153,7 @@ export class PromiseHolder extends ManagedObject { } // we can do this just once, because it will be dispose the GCHandle - complete_task(data: any, reason: any) { - if (!loaderHelpers.is_runtime_running()) { - mono_log_debug("This promise can't be propagated to managed code, mono runtime already exited."); - return; - } + complete_task_wrapper(data: any, reason: any) { try { mono_assert(!this.isPosted, "Promise is already posted to managed."); this.isPosted = true; diff --git a/src/mono/browser/runtime/export-api.ts b/src/mono/browser/runtime/export-api.ts index 1b4b596bdb6e33..f7d2b44a2c45b5 100644 --- a/src/mono/browser/runtime/export-api.ts +++ b/src/mono/browser/runtime/export-api.ts @@ -9,11 +9,13 @@ import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU1 import { mono_run_main, mono_run_main_and_exit } from "./run"; import { mono_wasm_setenv } from "./startup"; import { loaderHelpers, runtimeHelpers } from "./globals"; +import { mono_exit } from "./loader/exit"; export function export_api(): any { const api: APIType = { runMain: mono_run_main, runMainAndExit: mono_run_main_and_exit, + exit: mono_exit, setEnvironmentVariable: mono_wasm_setenv, getAssemblyExports: mono_wasm_get_assembly_exports, setModuleImports: mono_wasm_set_module_imports, diff --git a/src/mono/browser/runtime/gc-handles.ts b/src/mono/browser/runtime/gc-handles.ts index 3fc31717987fc1..61b1640d8993e2 100644 --- a/src/mono/browser/runtime/gc-handles.ts +++ b/src/mono/browser/runtime/gc-handles.ts @@ -139,6 +139,9 @@ export function setup_managed_proxy(owner: any, gc_handle: GCHandle): void { export function upgrade_managed_proxy_to_strong_ref(owner: any, gc_handle: GCHandle): void { const sr = create_strong_ref(owner); + if (_use_finalization_registry) { + _js_owned_object_registry.unregister(owner); + } _js_owned_object_table.set(gc_handle, sr); } diff --git a/src/mono/browser/runtime/invoke-js.ts b/src/mono/browser/runtime/invoke-js.ts index c13250fbe0ba4a..cb26b89a73b79f 100644 --- a/src/mono/browser/runtime/invoke-js.ts +++ b/src/mono/browser/runtime/invoke-js.ts @@ -53,6 +53,7 @@ export function mono_wasm_invoke_jsimport(signature: JSFunctionSignature, args: export function mono_wasm_invoke_jsimport_ST(function_handle: JSFnHandle, args: JSMarshalerArguments): void { if (WasmEnableThreads) return; + loaderHelpers.assert_runtime_running(); const bound_fn = js_import_wrapper_by_fn_handle[function_handle]; mono_assert(bound_fn, () => `Imported function handle expected ${function_handle}`); bound_fn(args); @@ -336,6 +337,7 @@ type BindingClosure = { } export function mono_wasm_invoke_js_function(bound_function_js_handle: JSHandle, args: JSMarshalerArguments): void { + loaderHelpers.assert_runtime_running(); const bound_fn = mono_wasm_get_jsobj_from_js_handle(bound_function_js_handle); mono_assert(bound_fn && typeof (bound_fn) === "function" && bound_fn[bound_js_function_symbol], () => `Bound function handle expected ${bound_function_js_handle}`); bound_fn(args); diff --git a/src/mono/browser/runtime/managed-exports.ts b/src/mono/browser/runtime/managed-exports.ts index 98d27e87fb4a25..5b0bdfe62a04ee 100644 --- a/src/mono/browser/runtime/managed-exports.ts +++ b/src/mono/browser/runtime/managed-exports.ts @@ -80,6 +80,7 @@ export function call_entry_point(main_assembly_name: string, program_args: strin // the marshaled signature is: void LoadSatelliteAssembly(byte[] dll) export function load_satellite_assembly(dll: Uint8Array): void { + loaderHelpers.assert_runtime_running(); const sp = Module.stackSave(); try { const size = 3; @@ -95,6 +96,7 @@ export function load_satellite_assembly(dll: Uint8Array): void { // the marshaled signature is: void LoadLazyAssembly(byte[] dll, byte[] pdb) export function load_lazy_assembly(dll: Uint8Array, pdb: Uint8Array | null): void { + loaderHelpers.assert_runtime_running(); const sp = Module.stackSave(); try { const size = 4; diff --git a/src/mono/browser/runtime/marshal-to-js.ts b/src/mono/browser/runtime/marshal-to-js.ts index bee7d560c88903..db6c36fe9927e0 100644 --- a/src/mono/browser/runtime/marshal-to-js.ts +++ b/src/mono/browser/runtime/marshal-to-js.ts @@ -23,6 +23,7 @@ import { get_marshaler_to_cs_by_type, jsinteropDoc, marshal_exception_to_cs } fr import { localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory"; import { call_delegate } from "./managed-exports"; import { gc_locked } from "./gc-lock"; +import { mono_log_debug } from "./logging"; export function initialize_marshalers_to_js(): void { if (cs_to_js_marshalers.size == 0) { @@ -337,6 +338,10 @@ function create_task_holder(res_converter?: MarshalerToJs) { } export function mono_wasm_resolve_or_reject_promise(args: JSMarshalerArguments): void { + if (!loaderHelpers.is_runtime_running()) { + mono_log_debug("This promise resolution/rejection can't be propagated to managed code, mono runtime already exited."); + return; + } const exc = get_arg(args, 0); const receiver_should_free = WasmEnableThreads && is_receiver_should_free(args); try { diff --git a/src/mono/browser/runtime/types/index.ts b/src/mono/browser/runtime/types/index.ts index 8d9c8a28ba1480..c5754f6c89e8fc 100644 --- a/src/mono/browser/runtime/types/index.ts +++ b/src/mono/browser/runtime/types/index.ts @@ -415,6 +415,13 @@ export type APIType = { * @returns exit code of the Main() method. */ runMainAndExit: (mainAssemblyName?: string, args?: string[]) => Promise; + /** + * Exits the runtime. + * Note: after the runtime exits, it would reject all further calls to the API. + * @param code "process" exit code. + * @param reason could be a string or an Error object. + */ + exit: (code: number, reason?: any) => void; /** * Sets the environment variable for the "process" * @param name diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor index 635ef2d738eed8..83faf539ac5121 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor +++ b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor @@ -86,7 +86,7 @@ { await DisposeHubConnection(); // exit the client - await JSRuntime.InvokeVoidAsync("eval", "import('./dotnet.js').then(module => { module.dotnet; module.exit(0); });"); + await JSRuntime.InvokeVoidAsync("eval", "getDotnetRuntime(0).exit(0);"); } private async Task DisposeHubConnection() From c1246e874fb90222732017a40fb9a34361c3a7c8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 7 Mar 2024 13:46:12 +0100 Subject: [PATCH 2/7] fix --- src/mono/browser/runtime/export-api.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mono/browser/runtime/export-api.ts b/src/mono/browser/runtime/export-api.ts index f7d2b44a2c45b5..623c4222218f01 100644 --- a/src/mono/browser/runtime/export-api.ts +++ b/src/mono/browser/runtime/export-api.ts @@ -9,13 +9,12 @@ import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU1 import { mono_run_main, mono_run_main_and_exit } from "./run"; import { mono_wasm_setenv } from "./startup"; import { loaderHelpers, runtimeHelpers } from "./globals"; -import { mono_exit } from "./loader/exit"; export function export_api(): any { const api: APIType = { runMain: mono_run_main, runMainAndExit: mono_run_main_and_exit, - exit: mono_exit, + exit: loaderHelpers.mono_exit, setEnvironmentVariable: mono_wasm_setenv, getAssemblyExports: mono_wasm_get_assembly_exports, setModuleImports: mono_wasm_set_module_imports, From f30c7dc00f6154877d8ed3b152780388e4746b8b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 7 Mar 2024 13:58:06 +0100 Subject: [PATCH 3/7] more --- src/mono/browser/runtime/dotnet.d.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/mono/browser/runtime/dotnet.d.ts b/src/mono/browser/runtime/dotnet.d.ts index 7b901972e8b8f0..2fdf8e16d09f3e 100644 --- a/src/mono/browser/runtime/dotnet.d.ts +++ b/src/mono/browser/runtime/dotnet.d.ts @@ -446,6 +446,13 @@ type APIType = { * @returns exit code of the Main() method. */ runMainAndExit: (mainAssemblyName?: string, args?: string[]) => Promise; + /** + * Exits the runtime. + * Note: after the runtime exits, it would reject all further calls to the API. + * @param code "process" exit code. + * @param reason could be a string or an Error object. + */ + exit: (code: number, reason?: any) => void; /** * Sets the environment variable for the "process" * @param name From d7caecb681b727b23843c0cddb1b65f4ed4dc560 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 7 Mar 2024 16:16:56 +0100 Subject: [PATCH 4/7] drop assertAfterExit and withAssertAfterExit --- src/mono/browser/runtime/interp-pgo.ts | 1 - src/mono/browser/runtime/loader/config.ts | 4 +--- src/mono/browser/runtime/loader/exit.ts | 16 ++++------------ src/mono/browser/runtime/loader/globals.ts | 1 - src/mono/browser/runtime/loader/run.ts | 13 ------------- src/mono/browser/runtime/types/internal.ts | 2 -- src/mono/browser/test-main.js | 1 - src/mono/sample/wasm/browser-shutdown/main.js | 1 - 8 files changed, 5 insertions(+), 34 deletions(-) diff --git a/src/mono/browser/runtime/interp-pgo.ts b/src/mono/browser/runtime/interp-pgo.ts index e7ec6198fbf51d..c4214b4fe5d6a3 100644 --- a/src/mono/browser/runtime/interp-pgo.ts +++ b/src/mono/browser/runtime/interp-pgo.ts @@ -193,7 +193,6 @@ export async function getCacheKey(prefix: string): Promise { delete inputs.forwardConsoleLogsToWS; delete inputs.diagnosticTracing; delete inputs.appendElementOnExit; - delete inputs.assertAfterExit; delete inputs.interopCleanupOnExit; delete inputs.dumpThreadsOnNonZeroExit; delete inputs.logExitCode; diff --git a/src/mono/browser/runtime/loader/config.ts b/src/mono/browser/runtime/loader/config.ts index e9ae9e1dd3e69d..f4f41750a061f6 100644 --- a/src/mono/browser/runtime/loader/config.ts +++ b/src/mono/browser/runtime/loader/config.ts @@ -6,7 +6,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads"; import { MainThreadingMode, type DotnetModuleInternal, type MonoConfigInternal, JSThreadBlockingMode, JSThreadInteropMode } from "../types/internal"; import type { DotnetModuleConfig, MonoConfig, ResourceGroups, ResourceList } from "../types"; -import { ENVIRONMENT_IS_WEB, exportedRuntimeAPI, loaderHelpers, runtimeHelpers } from "./globals"; +import { exportedRuntimeAPI, loaderHelpers, runtimeHelpers } from "./globals"; import { mono_log_error, mono_log_debug } from "./logging"; import { importLibraryInitializers, invokeLibraryInitializers } from "./libraryInitializers"; import { mono_exit } from "./exit"; @@ -178,8 +178,6 @@ export function normalizeConfig() { } } - loaderHelpers.assertAfterExit = config.assertAfterExit = config.assertAfterExit || !ENVIRONMENT_IS_WEB; - if (config.debugLevel === undefined && BuildConfiguration === "Debug") { config.debugLevel = -1; } diff --git a/src/mono/browser/runtime/loader/exit.ts b/src/mono/browser/runtime/loader/exit.ts index 057197f87d4528..1f4ad75f52faab 100644 --- a/src/mono/browser/runtime/loader/exit.ts +++ b/src/mono/browser/runtime/loader/exit.ts @@ -15,19 +15,11 @@ export function is_runtime_running() { } export function assert_runtime_running() { - if (!is_exited()) { - if (WasmEnableThreads && ENVIRONMENT_IS_WORKER) { - mono_assert(runtimeHelpers.runtimeReady, "The WebWorker is not attached to the runtime. See https://github.com/dotnet/runtime/blob/main/src/mono/wasm/threads.md#JS-interop-on-dedicated-threads"); - } else { - mono_assert(runtimeHelpers.runtimeReady, ".NET runtime didn't start yet. Please call dotnet.create() first."); - } + mono_assert(!is_exited(), () => `.NET runtime already exited with ${loaderHelpers.exitCode} ${loaderHelpers.exitReason}. You can use runtime.runMain() which doesn't exit the runtime.`); + if (WasmEnableThreads && ENVIRONMENT_IS_WORKER) { + mono_assert(runtimeHelpers.runtimeReady, "The WebWorker is not attached to the runtime. See https://github.com/dotnet/runtime/blob/main/src/mono/wasm/threads.md#JS-interop-on-dedicated-threads"); } else { - const message = `.NET runtime already exited with ${loaderHelpers.exitCode} ${loaderHelpers.exitReason}. You can use runtime.runMain() which doesn't exit the runtime.`; - if (loaderHelpers.assertAfterExit) { - mono_assert(false, message); - } else { - mono_log_warn(message); - } + mono_assert(runtimeHelpers.runtimeReady, ".NET runtime didn't start yet. Please call dotnet.create() first."); } } diff --git a/src/mono/browser/runtime/loader/globals.ts b/src/mono/browser/runtime/loader/globals.ts index 7e9708845e65b0..940051627f3046 100644 --- a/src/mono/browser/runtime/loader/globals.ts +++ b/src/mono/browser/runtime/loader/globals.ts @@ -86,7 +86,6 @@ export function setLoaderGlobals( maxParallelDownloads: 16, enableDownloadRetry: true, - assertAfterExit: !ENVIRONMENT_IS_WEB, _loaded_files: [], loadedFiles: [], diff --git a/src/mono/browser/runtime/loader/run.ts b/src/mono/browser/runtime/loader/run.ts index 730a692b4ebf5b..e0c9bd3cded56f 100644 --- a/src/mono/browser/runtime/loader/run.ts +++ b/src/mono/browser/runtime/loader/run.ts @@ -138,19 +138,6 @@ export class HostBuilder implements DotnetHostBuilder { } } - // internal - withAssertAfterExit(): DotnetHostBuilder { - try { - deep_merge_config(monoConfig, { - assertAfterExit: true - }); - return this; - } catch (err) { - mono_exit(1, err); - throw err; - } - } - // internal // todo fallback later by debugLevel withWaitingForDebugger(level: number): DotnetHostBuilder { diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts index 7d4eb89d0f3c9b..5b32ec09f9b4f7 100644 --- a/src/mono/browser/runtime/types/internal.ts +++ b/src/mono/browser/runtime/types/internal.ts @@ -80,7 +80,6 @@ export type MonoConfigInternal = MonoConfig & { browserProfilerOptions?: BrowserProfilerOptions, // dictionary-style Object. If omitted, browser profiler will not be initialized. waitForDebugger?: number, appendElementOnExit?: boolean - assertAfterExit?: boolean // default true for shell/nodeJS interopCleanupOnExit?: boolean dumpThreadsOnNonZeroExit?: boolean logExitCode?: boolean @@ -123,7 +122,6 @@ export type LoaderHelpers = { maxParallelDownloads: number; enableDownloadRetry: boolean; - assertAfterExit: boolean; exitCode: number | undefined; exitReason: any; diff --git a/src/mono/browser/test-main.js b/src/mono/browser/test-main.js index 78c697de19962d..3aacd8e2c67d68 100644 --- a/src/mono/browser/test-main.js +++ b/src/mono/browser/test-main.js @@ -250,7 +250,6 @@ function configureRuntime(dotnet, runArgs) { .withExitCodeLogging() .withElementOnExit() .withInteropCleanupOnExit() - .withAssertAfterExit() .withDumpThreadsOnNonZeroExit() .withConfig({ loadAllSatelliteResources: true diff --git a/src/mono/sample/wasm/browser-shutdown/main.js b/src/mono/sample/wasm/browser-shutdown/main.js index d727f7932a10d0..e3141c08976c1d 100644 --- a/src/mono/sample/wasm/browser-shutdown/main.js +++ b/src/mono/sample/wasm/browser-shutdown/main.js @@ -14,7 +14,6 @@ try { .withExitOnUnhandledError() .withExitCodeLogging() .withElementOnExit() - .withAssertAfterExit() .withOnConfigLoaded(() => { // you can test abort of the startup by opening http://localhost:8000/?throwError=true const params = new URLSearchParams(location.search); From 6adb710111e26c9e7d99c97dd57bf819022dc2ef Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Mar 2024 07:36:28 +0100 Subject: [PATCH 5/7] exit --- .../BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor index 83faf539ac5121..64745009caa45e 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor +++ b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor @@ -86,7 +86,7 @@ { await DisposeHubConnection(); // exit the client - await JSRuntime.InvokeVoidAsync("eval", "getDotnetRuntime(0).exit(0);"); + Environment.Exit(0); } private async Task DisposeHubConnection() From 5d5091dfa4ea96ec59d22dc9256602165545d3e4 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Mar 2024 12:49:03 +0100 Subject: [PATCH 6/7] - fix compareExchange - feedback --- src/mono/browser/runtime/memory.ts | 2 +- src/mono/wasm/features.md | 4 ++-- .../BlazorHosted.Client/wwwroot/index.html | 9 ++++++++- .../BlazorHostedApp/BlazorHosted.Server/appsettings.json | 8 ++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index 1e8db0fd0d4e85..585c6e377a1c1e 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -331,7 +331,7 @@ export function compareExchangeI32(offset: MemOffset, value: number, expected: n } return actual; } - return globalThis.Atomics.compareExchange(localHeapViewI32(), offset >>> 2, value, expected); + return globalThis.Atomics.compareExchange(localHeapViewI32(), offset >>> 2, expected, value); } export function storeI32(offset: MemOffset, value: number): void { diff --git a/src/mono/wasm/features.md b/src/mono/wasm/features.md index 90c0744a8586c1..53995e656a1a61 100644 --- a/src/mono/wasm/features.md +++ b/src/mono/wasm/features.md @@ -402,8 +402,8 @@ In Blazor, you can customize the startup in your index.html + + diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json new file mode 100644 index 00000000000000..75b7c2aa1ecedb --- /dev/null +++ b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Server/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file From 500e0331cdb2a32d89db14da1c01e3e2d543fdc0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 8 Mar 2024 15:07:07 +0100 Subject: [PATCH 7/7] fix exit --- .../BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor index 64745009caa45e..b04a282caf965c 100644 --- a/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor +++ b/src/mono/wasm/testassets/BlazorHostedApp/BlazorHosted.Client/Pages/Chat.razor @@ -86,7 +86,8 @@ { await DisposeHubConnection(); // exit the client - Environment.Exit(0); + Helper.TestOutputWriteLine($"SendExitSignal by CurrentManagedThreadId={Environment.CurrentManagedThreadId}"); + await JSRuntime.InvokeVoidAsync("eval", "setTimeout(() => { getDotnetRuntime(0).exit(0); }, 50);"); } private async Task DisposeHubConnection()