Aspnetcore: Storing javascript objects in C#

Created on 4 May 2018  路  1Comment  路  Source: dotnet/aspnetcore

When pass a javascript object to C# / WASM context. and storing it to an object makes it null referenced.
Below i am trying to create a C# wrapper for drawing canvas

ElementRef drawingCanvas;
....
var ctx = Get2DContext(drawingCanvas);
ctx.FillRect(10, 10, 50, 50); //this C# code throuws null, see the attached exception log

public CanvasRenderingContext2D Get2DContext(object canvasElement)
{
return new CanvasRenderingContext2D() { currentObject = RegisteredFunction.Invoke<object>("Get2DContextExt", canvasElement) };
}

public void FillRect(double x, double y, double w, double h)
{
RegisteredFunction.InvokeUnmarshalled<object>("CanvasRenderingContext2D_fillRect", currentObject, x, y, w, h);
}

protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder
{
builder.OpenElement(0, "script");
builder.AddContent(0, $"Blazor.registerFunction( 'Get2DContextExt', (obj) => {{ var ctx = obj.getContext('2d'); console.log(ctx); return ctx; }});");
builder.CloseElement();

builder.OpenElement(1, "script");
builder.AddContent(0, "Blazor.registerFunction('CanvasRenderingContext2D_fillRect', (obj , x, y, w, h) => { obj.fillRect(x, y, w, h); });");
builder.CloseElement();

}

Exception

Uncaught Error: Microsoft.AspNetCore.Blazor.Browser.Interop.JavaScriptException: obj.fillRect is not a function TypeError: obj.fillRect is not a function at Blazor.registerFunction (<anonymous>:1:90) at Array.ASM_CONSTS (mono.js:1) at _emscripten_asm_const_iiii (mono.js:1) at :54789/wasm-function[5272]:21 at :54789/wasm-function[3543]:34 at :54789/wasm-function[3548]:364 at :54789/wasm-function[3550]:224 at :54789/wasm-function[3766]:189 at :54789/wasm-function[1505]:15583 at :54789/wasm-function[867]:13 at Microsoft.AspNetCore.Blazor.Browser.Interop.RegisteredFunction.InvokeUnmarshalled[TRes] (:54789/System.String identifier, System.Object[] args) <0x1c2ca38 + 0x00034> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at CanvasTest.Common.CanvasRenderingContext2D.FillRect (:54789/System.Double x, System.Double y, System.Double w, System.Double h) <0x1c2c908 + 0x0006e> in <cceb8b67340346708bc55417fefdb664>:0 at :54789/CanvasNew.Common.AdvCanvas.IncrementCount () <0x1c1aa50 + 0x0004e> in <cceb8b67340346708bc55417fefdb664>:0 at Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker.Invoke (:54789/Microsoft.AspNetCore.Blazor.UIEventArgs e) <0x1c1a798 + 0x00076> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Components.BlazorComponent.Microsoft.AspNetCore.Blazor.Components.IHandleEvent.HandleEvent (:54789/Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker binding, Microsoft.AspNetCore.Blazor.UIEventArgs args) <0x1c1a268 + 0x0001a> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Rendering.ComponentState.DispatchEvent (:54789/Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker binding, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c1a008 + 0x0003c> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Rendering.Renderer.DispatchEvent (:54789/System.Int32 componentId, System.Int32 eventHandlerId, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c19a40 + 0x00054> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Browser.Rendering.BrowserRenderer.DispatchBrowserEvent (:54789/System.Int32 componentId, System.Int32 eventHandlerId, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c198d8 + 0x00020> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at Microsoft.AspNetCore.Blazor.Browser.Rendering.BrowserRendererEventDispatcher.DispatchEvent (:54789/System.String eventDescriptorJson, System.String eventArgsJson) <0x1bd69d8 + 0x0005a> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at Blazor.registerFunction (<anonymous>:1:90) at Array.ASM_CONSTS (mono.js:1) at _emscripten_asm_const_iiii (mono.js:1) at :54789/wasm-function[5272]:21 at :54789/wasm-function[3543]:34 at :54789/wasm-function[3548]:364 at :54789/wasm-function[3550]:224 at :54789/wasm-function[3766]:189 at :54789/wasm-function[1505]:15583 at :54789/wasm-function[867]:13 at Microsoft.AspNetCore.Blazor.Browser.Interop.RegisteredFunction.InvokeUnmarshalled[TRes] (:54789/System.String identifier, System.Object[] args) <0x1c2ca38 + 0x00034> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at CanvasTest.Common.CanvasRenderingContext2D.FillRect (:54789/System.Double x, System.Double y, System.Double w, System.Double h) <0x1c2c908 + 0x0006e> in <cceb8b67340346708bc55417fefdb664>:0 at :54789/CanvasNew.Common.AdvCanvas.IncrementCount () <0x1c1aa50 + 0x0004e> in <cceb8b67340346708bc55417fefdb664>:0 at Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker.Invoke (:54789/Microsoft.AspNetCore.Blazor.UIEventArgs e) <0x1c1a798 + 0x00076> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Components.BlazorComponent.Microsoft.AspNetCore.Blazor.Components.IHandleEvent.HandleEvent (:54789/Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker binding, Microsoft.AspNetCore.Blazor.UIEventArgs args) <0x1c1a268 + 0x0001a> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Rendering.ComponentState.DispatchEvent (:54789/Microsoft.AspNetCore.Blazor.Components.EventHandlerInvoker binding, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c1a008 + 0x0003c> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Rendering.Renderer.DispatchEvent (:54789/System.Int32 componentId, System.Int32 eventHandlerId, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c19a40 + 0x00054> in <0d9c96ffc9704aa9b088cbbe138126c6>:0 at Microsoft.AspNetCore.Blazor.Browser.Rendering.BrowserRenderer.DispatchBrowserEvent (:54789/System.Int32 componentId, System.Int32 eventHandlerId, Microsoft.AspNetCore.Blazor.UIEventArgs eventArgs) <0x1c198d8 + 0x00020> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at Microsoft.AspNetCore.Blazor.Browser.Rendering.BrowserRendererEventDispatcher.DispatchEvent (:54789/System.String eventDescriptorJson, System.String eventArgsJson) <0x1bd69d8 + 0x0005a> in <92ed9c6772a34798bccecc99cc26cbcd>:0 at Object.callMethod (MonoPlatform.ts:70) at raiseEvent (BrowserRenderer.ts:327) at EventDelegator.onEvent (BrowserRenderer.ts:19) at EventDelegator.onGlobalEvent (EventDelegator.ts:83)

area-blazor

Most helpful comment

I'm afraid one does not simply pass a JavaScript object to .NET. They are separate runtimes that don't operate directly on each other's objects. When you pass your object from JS to .NET, you're passing a JSON-serialized representation on it. When you later pass back that JSON-serialized representation, you're just getting a deserialized representation of that information, not an actual HTMLElement instance, hence it not having any HTMLElement methods.

You could pass the id (string) of an element into .NET, and then in your .NET code make calls back into JS that pass back the id and ask JS code to find the element and perform operations on it.

Longer term:

  • There are proposals in the WebAssembly spec track to add the ability for WASM code to directly reference JS objects.
  • Until then, we are also considering adding APIs that make it convenient to pass references to arbitrary JS objects that when passed back become references to the original object. That would help you in this case. It's not trivial because on the .NET side they would have to be IDisposable to avoid leaking memory in the JS side, so you'd have to remember always to dispose any such references when you were finished with them.

>All comments

I'm afraid one does not simply pass a JavaScript object to .NET. They are separate runtimes that don't operate directly on each other's objects. When you pass your object from JS to .NET, you're passing a JSON-serialized representation on it. When you later pass back that JSON-serialized representation, you're just getting a deserialized representation of that information, not an actual HTMLElement instance, hence it not having any HTMLElement methods.

You could pass the id (string) of an element into .NET, and then in your .NET code make calls back into JS that pass back the id and ask JS code to find the element and perform operations on it.

Longer term:

  • There are proposals in the WebAssembly spec track to add the ability for WASM code to directly reference JS objects.
  • Until then, we are also considering adding APIs that make it convenient to pass references to arbitrary JS objects that when passed back become references to the original object. That would help you in this case. It's not trivial because on the .NET side they would have to be IDisposable to avoid leaking memory in the JS side, so you'd have to remember always to dispose any such references when you were finished with them.
Was this page helpful?
0 / 5 - 0 ratings