Blazor HotReload throws `System.NullReferenceException` when using Serilog
See original GitHub issueIs there an existing issue for this?
- I have searched the existing issues
Describe the bug
When using the serilog browser-console sink, the application throws System.NullReferenceException. The author of the library already tried to fix it but it looks like it’s a problem with Blazor itself.
Here is a reference to the issue in the browser-console sink repository https://github.com/serilog/serilog-sinks-browserconsole/issues/20
Expected Behavior
We should be able to add a log and start the application without getting a null reference exception.
Steps To Reproduce
- Create a new Blazor project.
- Add serilog browser-console sink package.
- Update the entry point so it looks like this:
// This is the line that makes Blazor throw the exception
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.BrowserConsole(
restrictedToMinimumLevel: LogEventLevel.Information,
outputTemplate: "[{Level:u3}] {Message:lj}{NewLine}{Exception}",
CultureInfo.InvariantCulture)
.CreateLogger();
try
{
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>(selector: "#app");
builder.RootComponents.Add<HeadOutlet>(selector: "head::after");
builder.Logging.AddSerilog();
builder.Services.AddServices();
WebAssemblyHost app = builder.Build();
await app.RunAsync();
}
catch (Exception ex)
{
Log.Fatal(ex, messageTemplate: "An exception occurred while creating the WASM host");
throw;
}
Exceptions (if any)
[ FTL ] An exception occurred while creating the WASM host System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.InitializeAsync() at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHost.RunAsyncCore(CancellationToken cancellationToken, WebAssemblyCultureProvider cultureProvider) at Program.<Main>$(String[] args) in D:\workspace\projects\Hephaestus\src\presentation\Hephaestus.WebApp\Program.cs:line 43 (anonymous) @ blazor.webassembly.js:1 beginInvokeJSFromDotNet @ blazor.webassembly.js:1 Gt @ blazor.webassembly.js:1 Ii @ dotnet.7.0.0.k4xetpuqcq.js:5 _mono_wasm_invoke_js_blazor @ dotnet.7.0.0.k4xetpuqcq.js:14 $func313 @ 009924a6:0x1d4a3 $func283 @ 009924a6:0x1c8d1 $func221 @ 009924a6:0xdfdd $func220 @ 009924a6:0xce8f $func8112 @ 009924a6:0x1a1fcc $func2053 @ 009924a6:0x859fe $func2058 @ 009924a6:0x86066 $func2085 @ 009924a6:0x88125 $mono_wasm_invoke_method_ref @ 009924a6:0x9bcb Module._mono_wasm_invoke_method_ref @ dotnet.7.0.0.k4xetpuqcq.js:14 _Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS @ _Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS:26 endInvokeJSFromDotNet @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 Promise.then (async) beginInvokeJSFromDotNet @ blazor.webassembly.js:1 Gt @ blazor.webassembly.js:1 Ii @ dotnet.7.0.0.k4xetpuqcq.js:5 _mono_wasm_invoke_js_blazor @ dotnet.7.0.0.k4xetpuqcq.js:14 $func313 @ 009924a6:0x1d4a3 $func283 @ 009924a6:0x1c8d1 $func221 @ 009924a6:0xdfdd $func220 @ 009924a6:0xce8f $func8112 @ 009924a6:0x1a1fcc $func2053 @ 009924a6:0x859fe $func2051 @ 009924a6:0x85974 $func1394 @ 009924a6:0x68446 $func313 @ 009924a6:0x1d45c $func283 @ 009924a6:0x1c8d1 $func221 @ 009924a6:0xdfdd $func220 @ 009924a6:0xce8f $func8112 @ 009924a6:0x1a1fcc $func2053 @ 009924a6:0x859fe $func2058 @ 009924a6:0x86066 $func2085 @ 009924a6:0x88125 $mono_wasm_invoke_method_ref @ 009924a6:0x9bcb Module._mono_wasm_invoke_method_ref @ dotnet.7.0.0.k4xetpuqcq.js:14 _Hephaestus_WebApp__entrypoint @ _Hephaestus_WebApp__entrypoint:26 (anonymous) @ dotnet.7.0.0.k4xetpuqcq.js:5 ji @ dotnet.7.0.0.k4xetpuqcq.js:5 callEntryPoint @ blazor.webassembly.js:1 Vt @ blazor.webassembly.js:1 await in Vt (async) (anonymous) @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 blazor.webassembly.js:1
System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.)
—> System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.InitializeAsync() at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHost.RunAsyncCore(CancellationToken cancellationToken, WebAssemblyCultureProvider cultureProvider) at Program.<Main>$(String[] args) in D:\workspace\projects\Hephaestus\src\presentation\Hephaestus.WebApp\Program.cs:line 48 — End of inner exception stack trace —
.NET Version
net7.0
Anything else?
No response
Issue Analytics
- State:
- Created 9 months ago
- Comments:7 (4 by maintainers)

Top Related StackOverflow Question
The workout around works like a charm, thank you for the investigation @MackinnonBuck! I also added an update in the original issue in the browser console repo. I’m not sure if you are going to track the next steps in the same ticket, at least from my side the issue is resolved and can be closed.
Summary
The root of the problem is that
Serilog.Sinks.BrowserConsolecreates and uses its ownIJSRuntimeinstance (from its own implementation) when one isn’t provided to LoggerConfigurationBrowserConsoleExtensions.BrowserConsole().Details
Since the
IJSRuntimeinstance created by Serilog is different from theIJSRuntimeused by Blazor, it will have its own state tracking pending JS invocations,DotNetObjectReferenceinstances, etc.The
JSRuntimebase implementation tracks pending JS invocations using alongID that increments for each JS interop call. In this particular case, the invocation IDs between the twoJSRuntimeinstances conflict and cause the crash:JSRuntime, Serilog kicks off its first two interop calls toconsole.infowith IDs 2 and 3 respectively.JSRuntimeinstance to asynchronously invoke a dynamicimportfor theblazor-hotreload.jsmodule, intending to store the result as anIJSObjectReference. This invocation has an ID of 2.import()call. The return value can’t be deserialized into anIJSObjectReference, so it becomesnullon the .NET side, causing theNullReferenceException.Workaround
This can be worked around by passing the
IJSRuntimefromapp.Servicesinto the call toLoggerConfigurationBrowserConsoleExtensions.BrowserConsole().Next steps
Ultimately, the specific issue at hand is a Serilog bug. From Blazor’s perspective, all bets are off as soon as a library interferes with its internal state in a manner other than through the public API. That said, we could look into adding extra checks to catch this case rather than failing silently.