Aspnetcore: InvokeVoidAsync shouldn't serialize return value to .NET

Created on 29 Oct 2019  路  5Comments  路  Source: dotnet/aspnetcore

A JavaScript error appears in the browser console

blazor.server.js:1 [2019-10-29T12:25:00.705Z] Information: Normalizing '_blazor' to 'https://localhost:44387/_blazor'.
blazor.server.js:1 [2019-10-29T12:25:01.018Z] Information: WebSocket connected to wss://localhost:44387/_blazor?id=FFEeuHNqrQLnX70peuLyLg.
blazor.server.js:8 Uncaught (in promise) TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Window'
--- property 'parent' closes the circle
at JSON.stringify ()
at blazor.server.js:8
(anonymous) @ blazor.server.js:8
Promise.then (async)
beginInvokeJSFromDotNet @ blazor.server.js:8
(anonymous) @ blazor.server.js:1
e.invokeClientMethod @ blazor.server.js:1
e.processIncomingData @ blazor.server.js:1
connection.onreceive @ blazor.server.js:1
i.onmessage @ blazor.server.js:1

when opening a new tab using

JsRuntime.InvokeAsync<bool>("open", video.Link, "_blank");

affected-few area-blazor bug severity-minor

All 5 comments

This is because window.open returns a WindowProxy object (see https://developer.mozilla.org/en-US/docs/Web/API/Window/open). WindowProxy is not JSON-serializable, so can't be used as a return value to .NET code.

To fix this, don't call window.open directly, but instead call a JS function of your own that either returns nothing or returns something that is JSON-serializable.

I realized the InvokeAsync<bool> was not necessary anymore. Now there is the InvokeVoidAsync.

JsRuntime.InvokeVoidAsync("open", video.Link, "_blank");

But this is still throwing the error. In this case it shouldn't serialize anything because the code is expecting void.

IMO this should be handled by Blazor. creating Javascript to do this shouldn't be necessary.

Thanks @arivoir, that's a really good point. It's not useful for InvokeVoidAsync to serialize its return value at all, since the .NET side is going to ignore it anyway. I'm reopening this and putting it on the backlog.

You can use location.replace instead of open

Here's another repro-case (in Blazor server side, .NET5 RC2).

string s = "$('#my-button').attr('data-content', 'Hello!').popover('show')";
await JsRuntime.InvokeVoidAsync("eval", s);

This works (BTW: I know it may be bad practise to use eval and I have another solution already). But in the browser console I see this error:

blazor.server.js:1 Uncaught (in promise) TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'HTMLButtonElement'
    |     property '_blazorEvents_1' -> object with constructor 'e'
    |     property 'handlers' -> object with constructor 'Object'
    |     property 'click' -> object with constructor 'Object'
    --- property 'element' closes the circle
    at JSON.stringify (<anonymous>)
    at blazor.server.js:1
Was this page helpful?
0 / 5 - 0 ratings