1

Is it possible to return a list of object references from JS to C#? Currently I do return a list of objects (THREE.js objects) though I am unable to deserialize it into a C# IList or array to get separate IJSObjectReference instances on .NET side. I simply get one IJSObjectReference (logically possible) which is a reference to the JS array itself.

Anyone know if it is possible to deserialize a JS Array into a C# array/list/collection and in this case, for it to contain JSObject references?

This is basically what I am trying to do

const myJsFunc () = () => {
    ....
    return [someJsObject, anotherJsObject]
}

C# side

var objectReferencesArray = js.Invoke<IJSInProcessObjectReference[]>("myJsFunc", ...);

or

var objectReferencesArray = js.Invoke<IList<IJSInProcessObjectReference>>("myJsFunc", ...);

neither work. I am only able to get ONE object ref which is for the array itself.

EDIT: Still interested in hearing suggestions on this but as an update I can say that I chose to simply return the list as its own IJSInProcessObjectReference and then when I pass it back to JS, destruct it and handle it that way.

3 Answers 3

1

Updated 2024-04-04

I now have 2 ways. The original answer, now answer 2, used a library I wrote. The new answer, answer 1, does not require any additional libraries and only takes a few minor changes.

Answer 1

  • In Javascript, wrap each object in the array using DotNet.createJSObjectReference() which returns a simple object. Ex. { __jsObjectId: 1 }

  • Send the array of __jsObjectId values to Blazor as the return value of your method as a long[]

  • In Blazor, you can then create an IJSInProcessObjectReference[] using the long[] and a little reflection.

Code

Javascript side:

const myJsFunc = () => {
    // create a object reference for each and return an array of the ids
    return [window, window, null].map(o => o === null || o === void 0 ? -1 : DotNet.createJSObjectReference(o).__jsObjectId);
}

C# side:

// get the class Type used for IJSInProcessObjectReference
Type WebAssemblyJSObjectReferenceType = typeof(Microsoft.JSInterop.WebAssembly.WebAssemblyJSRuntime).Assembly.GetType("Microsoft.JSInterop.WebAssembly.WebAssemblyJSObjectReference")!;
// convert the object ids into array of IJSInProcessObjectReference
IJSInProcessObjectReference[]? objectReferencesArray = js.Invoke<long[]?>("myJsFunc")?.Select(id => 
 id < 0 ? null : (IJSInProcessObjectReference)Activator.CreateInstance(WebAssemblyJSObjectReferenceType, js, id)!).ToArray();

This is a bare min work up. You should cache the WebAssemblyJSObjectReference type by setting it to a static variable.

Answer 2

Using Nuget package SpawnDev.BlazorJS:
Program.cs

// Inject and init BlazorJSRuntime
builder.Services.AddBlazorJSRuntime();

Razor page (for example)

[Inject]
BlazorJSRuntime JS { get; set; }

...

var objectReferencesArray = JS.Call<IJSInProcessObjectReference[]>("myJsFunc", arg1, arg2, ...);

GitHub Repo: SpawnDev.BlazorJS

Documentation

SpawnDev.BlazorJS is a full Javascript interop library that contains over 300 Javascript types allowing complete access to the Javascript environment in Blazor WASM.

I am the author of SpawnDev.BlazorJS.
NuGet

Sign up to request clarification or add additional context in comments.

1 Comment

Answer 1 is almost good. Just do not take ".__jsObjectId", see my answer below.
0

My pattern is like:

JS

return values.map(c => DotNet.createJSObjectReference(c));

C#

x.Invoke<IJSInProcessObjectReference[]>(...)

Comments

-3

you cannot directly return a list of IJSObjectReference instead you can do like this

js Code

const myJsFunc = () => {
    return [JSON.stringify(someJsObject), JSON.stringify(anotherJsObject)];
}

c# Code

var jsonStringArray = js.Invoke<string[]>("myJsFunc", ...);
var objectReferencesList = new List<IJSObjectReference>();

foreach (var jsonString in jsonStringArray)
{
    var objectRef = await js.InvokeAsync<IJSObjectReference>("JSON.parse", jsonString);
    objectReferencesList.Add(objectRef);
}

this way u can get a list from JS

2 Comments

Hmm this kind of defeats the purpose of my project as I am trying to reduce the amount of JSInterop calls I need in my code. If I need to call into JS to parse the objects to IJSobjects back then there is no real difference from (in my case) just calling my function twice and returning the values separately.. Is there no known way to return a list or array in one call?
Try passing [window, window, window] from Javascript to C# using your method. It throws an exception because window cannot be serialized using JSON.stringify as you suggest. And passing the serialized objects to C# just to have C# pass them back to Javascript to call JSON.parse on them is useless and does not work. Test your code. I tested mine and yours.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.