0

I've got a Blazor webassembly website that runs fine on the desktop in Chrome, Firefox, Brave, both locally and deployed to my server.

However, on an Android device, I get the yellow bar of death before anything even loads in Chrome for Android, Brave for Android, and Firefox for Android.

Is there some way on any mobile Android browser where I can see what got logged to the developer console in the browser?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
MikeT
  • 2,530
  • 25
  • 36
  • Both Chrome and Edge can emulate Android browsers. VS itself has an Android emulation mode with debugging. – Panagiotis Kanavos Jul 11 '22 at 12:57
  • Thank you for your response. Not sure the browser emulators would help in general as I don't think they're switching out their rendering/javascript engines. Regardless, in my case nothing worked as the issue was on my phone itself (see the github issue in my answer). – MikeT Jul 12 '22 at 19:22

2 Answers2

0

If you follow these instructions, it should work for Blazor Wasm also.

https://learn.microsoft.com/en-us/aspnet/core/blazor/hybrid/developer-tools?view=aspnetcore-6.0&pivots=android

Shuryno
  • 532
  • 3
  • 13
  • Thank you for your answer. As it turns out, in my case, nothing on my dev box would have helped as the issue was on my phone (see the github issue in my answer). – MikeT Jul 12 '22 at 19:23
0

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.

MikeT
  • 2,530
  • 25
  • 36
  • You should probably add explicit error handling and logging support to your application, sending the logs to the server. Microsoft.Extensions.Logging is already used in Blazor WASM. Serilog has [a Blazor logging provider that relays logs to the server](https://nblumhardt.com/2019/11/serilog-blazor/) – Panagiotis Kanavos Jul 13 '22 at 07:18
  • `why Blazor is running out of RAM` it's not. OOM errors are almost always thrown when the application causes so much memory fragmentation the runtime can no longer find a large enough contiguous block of memory to use. Many containers use an array internally which they reallocate when it gets full. The data is copied to the new buffer and is up for garbage collection. If you add 2M items to a list one by one you end up allocating twice the RAM because of the 10-11 reallocations. You can avoid that simply by specifying a capacity in the List constructor – Panagiotis Kanavos Jul 13 '22 at 07:22
  • @PanagiotisKanavos Thank you for your responses. If you read my answer as well as check out that github issue, you'll see this is a known issue with Blazor 6. As I mentioned, I spun up a new Blazor app from Microsoft's template, pushed it to my server, same problem. Thanks for the tip on List – MikeT Jul 13 '22 at 13:32