The first thing I did was to add a global javascript exception handler:
window.onerror = function (errMsg, url, line, column, error) {
var dto = {
"columnNumber": column,
"lineNumber": line,
"message": errMsg,
"url": url
};
var json = JSON.stringify(dto);
var xhr = new XMLHttpRequest();
var url = '/path-to-log-javascript-exceptions';
xhr.open('POST', url);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
//for some reason, just calling xhr.send() doesn't work.
sendXhr(xhr, json);
var suppressErrorAlert = false;
return suppressErrorAlert;
};
function sendXhr(xhr, json) {
xhr.send(json);
}
No help (but it's good to have anyway).
Then I wrapped the code in App.razor
in an ErrorBoundary
:
<HttpService @ref="httpService" />
<ErrorBoundary>
<ChildContent>
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
</ChildContent>
<ErrorContent Context="ex">
<h1 class="text-danger">Oops. Error occurred. @msg</h1>
@*<button @onclick="() => logException(ex)">Log exception.</button>*@
@{
logException(ex);
}
</ErrorContent>
</ErrorBoundary>
@code {
//This is a wrapper I have around HttpClient for added features
public HttpService httpService { get; set; }
int calledCount;
string msg;
async Task logException(Exception e)
{
//hacky, for some reason this gets called twice
calledCount++;
if (calledCount > 1) return;
//sometimes it isn't instantiated
while (httpService == null) await Task.Delay(10);
while (e.InnerException != null) e = e.InnerException;
LogItemDto logItemDto = new LogItemDto
{
Body = e.StackTrace,
Message = e.Message,
};
var result = await httpService.PostAsync<LogItemDto>("/path-to-log-dotnet-exception", logItemDto);
if (result != null)
{
msg = "This error has been logged.";
}
else
{
msg = "Didn't log this error";
}
StateHasChanged();
}
}
No help (and not sure implementing a global exception handler this way is a good idea, gonna have to dig into the source code to see how ErrorBoundary
is implemented).
I ended up intercepting calls to console.debug()
which I adapted from this answer:
<div id="debug-bar"></div>
<script>
//how to intercept console.log() https://stackoverflow.com/a/41404998/2816057
console.log2 = console.log; // keeping original function under new name
var debugBarEl = document.getElementById('debug-bar');
console.log = console.debug = console.error = function () {
// converting arguments object to array
var args = Array.prototype.splice.call(arguments, 0);
// calling original log function with args
console.log2.apply(this, args);
var divEl = document.createElement('div');
divEl.innerText = 'Debug: ' + args.join(' ');
debugBarEl.append(divEl);
};
</script>
And that finally gave me my answer, which led me to an open issue on github.
And that issue led me to the Kiwi browser, which has developer tools which of course don't show up for me. The struggle continues, lol.
Update: I spun up a new Blazor WASM app from the template Microsoft provides, no Authentication, ASP.NET Core hosted, which is about as small as a Blazor website can be.
Pushed it to my server, same issue.
Although my phone is a cheesy 100 dollar piece of..., it's got 4 gigs of RAM with 750 megs free. I wonder why Blazor is running out of RAM.