Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Buffers;
using System.IO;
using MessagePack;
using Microsoft.AspNetCore.SignalR.Protocol;
Expand Down Expand Up @@ -34,6 +35,16 @@ protected override object DeserializeObject(ref MessagePackReader reader, Type t
{
return reader.ReadSingle();
}
else if (type == typeof(byte[][]))
{
var length = reader.ReadArrayHeader();
var result = new byte[length][];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this is bad, length comes from user provided input, so you cannot pre-allocate the array.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated to utilize a list for the result.

for (var i = 0; i < length; i++)
{
result[i] = reader.ReadBytes().GetValueOrDefault().ToArray();
}
return result;
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -75,6 +86,14 @@ protected override void Serialize(ref MessagePackWriter writer, Type type, objec
writer.Write(bytes);
break;

case byte[][] byteArrays:
writer.WriteArrayHeader(byteArrays.Length);
foreach (var bytes in byteArrays)
{
writer.Write(bytes);
}
break;

default:
throw new FormatException($"Unsupported argument type {type}");
}
Expand Down
12 changes: 6 additions & 6 deletions src/Components/Server/src/Circuits/CircuitHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public async Task OnRenderCompletedAsync(long renderId, string errorMessageOrNul

// BeginInvokeDotNetFromJS is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson)
public async Task BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson, byte[][]? byteArrays)
{
AssertInitialized();
AssertNotDisposed();
Expand All @@ -347,7 +347,7 @@ await Renderer.Dispatcher.InvokeAsync(() =>
{
Log.BeginInvokeDotNet(_logger, callId, assemblyName, methodIdentifier, dotNetObjectId);
var invocationInfo = new DotNetInvocationInfo(assemblyName, methodIdentifier, dotNetObjectId, callId);
DotNetDispatcher.BeginInvokeDotNet(JSRuntime, invocationInfo, argsJson);
DotNetDispatcher.BeginInvokeDotNet(JSRuntime, invocationInfo, argsJson, byteArrays);
});
}
catch (Exception ex)
Expand All @@ -362,7 +362,7 @@ await Renderer.Dispatcher.InvokeAsync(() =>

// EndInvokeJSFromDotNet is used in a fire-and-forget context, so it's responsible for its own
// error handling.
public async Task EndInvokeJSFromDotNet(long asyncCall, bool succeeded, string arguments)
public async Task EndInvokeJSFromDotNet(long callId, bool succeeded, string resultOrError, byte[][]? byteArrays)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, these are better names. Thanks for cleaning this up!

{
AssertInitialized();
AssertNotDisposed();
Expand All @@ -374,14 +374,14 @@ await Renderer.Dispatcher.InvokeAsync(() =>
if (!succeeded)
{
// We can log the arguments here because it is simply the JS error with the call stack.
Log.EndInvokeJSFailed(_logger, asyncCall, arguments);
Log.EndInvokeJSFailed(_logger, callId, resultOrError);
}
else
{
Log.EndInvokeJSSucceeded(_logger, asyncCall);
Log.EndInvokeJSSucceeded(_logger, callId);
}

DotNetDispatcher.EndInvokeJS(JSRuntime, arguments);
DotNetDispatcher.EndInvokeJS(JSRuntime, resultOrError, byteArrays);
});
}
catch (Exception ex)
Expand Down
12 changes: 8 additions & 4 deletions src/Components/Server/src/Circuits/RemoteJSRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,16 @@ protected override void EndInvokeDotNet(DotNetInvocationInfo invocationInfo, in

private void EndInvokeDotNetCore(string callId, bool success, object resultOrError)
{
_clientProxy.SendAsync(
var args = new[] { callId, success, resultOrError };
var (argsJson, byteArrays) = SerializeArgs(args);

_clientProxy.SendAsync(
"JS.EndInvokeDotNet",
JsonSerializer.Serialize(new[] { callId, success, resultOrError }, JsonSerializerOptions));
argsJson,
byteArrays);
}

protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, JSCallResultType resultType, long targetInstanceId)
protected override void BeginInvokeJS(long asyncHandle, string identifier, string argsJson, byte[][]? byteArrays, JSCallResultType resultType, long targetInstanceId)
{
if (_clientProxy is null)
{
Expand All @@ -87,7 +91,7 @@ protected override void BeginInvokeJS(long asyncHandle, string identifier, strin

Log.BeginInvokeJS(_logger, asyncHandle, identifier);

_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson, (int)resultType, targetInstanceId);
_clientProxy.SendAsync("JS.BeginInvokeJS", asyncHandle, identifier, argsJson, byteArrays, (int)resultType, targetInstanceId);
}

public static class Log
Expand Down
8 changes: 4 additions & 4 deletions src/Components/Server/src/ComponentHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,26 +187,26 @@ public async ValueTask<bool> ConnectCircuit(string circuitIdSecret)
return false;
}

public async ValueTask BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson)
public async ValueTask BeginInvokeDotNetFromJS(string callId, string assemblyName, string methodIdentifier, long dotNetObjectId, string argsJson, byte[][] byteArrays)
{
var circuitHost = await GetActiveCircuitAsync();
if (circuitHost == null)
{
return;
}

_ = circuitHost.BeginInvokeDotNetFromJS(callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson);
_ = circuitHost.BeginInvokeDotNetFromJS(callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson, byteArrays);
}

public async ValueTask EndInvokeJSFromDotNet(long asyncHandle, bool succeeded, string arguments)
public async ValueTask EndInvokeJSFromDotNet(long callId, bool succeeded, string resultOrError, byte[][] byteArrays)
{
var circuitHost = await GetActiveCircuitAsync();
if (circuitHost == null)
{
return;
}

_ = circuitHost.EndInvokeJSFromDotNet(asyncHandle, succeeded, arguments);
_ = circuitHost.EndInvokeJSFromDotNet(callId, succeeded, resultOrError, byteArrays);
}

public async ValueTask DispatchBrowserEvent(string eventDescriptor, string eventArgs)
Expand Down
2 changes: 1 addition & 1 deletion src/Components/Web.JS/dist/Release/blazor.server.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Components/Web.JS/dist/Release/blazor.webview.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions src/Components/Web.JS/src/Boot.Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger

connection.on('JS.AttachComponent', (componentId, selector) => attachRootComponentToLogicalElement(0, circuit.resolveElement(selector), componentId));
connection.on('JS.BeginInvokeJS', DotNet.jsCallDispatcher.beginInvokeJSFromDotNet);
connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(DotNet.parseJsonWithRevivers(args) as [string, boolean, unknown])));
connection.on('JS.EndInvokeDotNet', (args: string, byteArrays: Uint8Array[]) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(DotNet.parseJsonWithRevivers(args, byteArrays) as [string, boolean, unknown])));

const renderQueue = RenderQueue.getOrCreate(logger);
connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => {
Expand All @@ -128,11 +128,11 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger
}

DotNet.attachDispatcher({
beginInvokeDotNetFromJS: (callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson): void => {
connection.send('BeginInvokeDotNetFromJS', callId ? callId.toString() : null, assemblyName, methodIdentifier, dotNetObjectId || 0, argsJson);
beginInvokeDotNetFromJS: (callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson, byteArrays): void => {
connection.send('BeginInvokeDotNetFromJS', callId ? callId.toString() : null, assemblyName, methodIdentifier, dotNetObjectId || 0, argsJson, byteArrays);
},
endInvokeJSFromDotNet: (asyncHandle, succeeded, argsJson): void => {
connection.send('EndInvokeJSFromDotNet', asyncHandle, succeeded, argsJson);
endInvokeJSFromDotNet: (asyncHandle, succeeded, resultOrError, byteArrays): void => {
connection.send('EndInvokeJSFromDotNet', asyncHandle, succeeded, resultOrError, byteArrays);
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export function startIpcReceiver() {

'BeginInvokeJS': DotNet.jsCallDispatcher.beginInvokeJSFromDotNet,

'EndInvokeDotNet': (asyncCallId: string, success: boolean, invocationResultOrError: string) => {
const resultOrExceptionMessage: any = DotNet.parseJsonWithRevivers(invocationResultOrError);
'EndInvokeDotNet': (asyncCallId: string, success: boolean, invocationResultOrError: string, byteArrays: Uint8Array[] | undefined) => {
const resultOrExceptionMessage: any = DotNet.parseJsonWithRevivers(invocationResultOrError, byteArrays);
DotNet.jsCallDispatcher.endInvokeDotNetFromJS(asyncCallId, success, resultOrExceptionMessage);
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ function getCaptureIdAttributeName(referenceCaptureId: string) {

// Support receiving ElementRef instances as args in interop calls
const elementRefKey = '__internalId'; // Keep in sync with ElementRef.cs
DotNet.attachReviver((key, value) => {
DotNet.attachReviver(function reviveElementReference(key: any, value: any, byteArrays: Uint8Array[] | undefined) {
if (value && typeof value === 'object' && value.hasOwnProperty(elementRefKey) && typeof value[elementRefKey] === 'string') {
return getElementByCaptureId(value[elementRefKey]);
} else {
return value;
}

// Unrecognized - let another reviver handle it
return value;
});
Loading