Skip to content

Blazor WebAssembly & WebView JS to .NET Streaming Interop Support #33986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e9a84a3
Prototype Large File Upload Support Blazor
TanayParikh Jun 28, 2021
fc45a1d
Blob.slice Implementation
TanayParikh Jun 28, 2021
05c0037
Allow WASM to keep working
TanayParikh Jun 28, 2021
481d564
Merge branch 'main' into taparik/largeFileInterop
TanayParikh Jun 29, 2021
c682d19
Update CircuitStreamingInterop.ts
TanayParikh Jun 29, 2021
7d4f8f8
PR Feedback
TanayParikh Jun 29, 2021
d3a5ad9
Cleanup
TanayParikh Jun 29, 2021
0e41baa
WASM
TanayParikh Jun 30, 2021
2b46a90
WebView
TanayParikh Jun 30, 2021
5ad5573
Webview Remove SendJSDataStream
TanayParikh Jun 30, 2021
f0a8866
Refactor Shared Streaming Interop Code TS
TanayParikh Jun 30, 2021
68ebb6f
WebView DotNetObjectReference Based ReceiveData
TanayParikh Jun 30, 2021
d8de554
BaseJSDataStream Refactor
TanayParikh Jul 1, 2021
fbee585
E2E tests WASM
TanayParikh Jul 1, 2021
74162f6
Merge branch 'taparik/largeFileInterop' into taparik/wasmWebViewJSToD…
TanayParikh Jul 1, 2021
d1c0d3a
Unhandled Exception
TanayParikh Jul 1, 2021
2020471
ReceiveJSDataChunk using DotNet Object Reference for WASM/WebView
TanayParikh Jul 1, 2021
577b7f6
WASM Unmarshalled Interop Support
TanayParikh Jul 1, 2021
8adbdc6
E2E tests
TanayParikh Jul 1, 2021
4cc882c
Update BaseJSDataStream.cs
TanayParikh Jul 2, 2021
857f441
Merge branch 'main' into taparik/largeFileInterop
TanayParikh Jul 9, 2021
b74b933
PR Feedback
TanayParikh Jul 9, 2021
d9e37fb
Merge branch 'main' into taparik/largeFileInterop
TanayParikh Jul 9, 2021
f3f2cbe
Merge branch 'taparik/largeFileInterop' into taparik/wasmWebViewJSToD…
TanayParikh Jul 9, 2021
21cf75f
Update Web(View, Assembly) to match interop followup items
TanayParikh Jul 9, 2021
d571a42
Merge branch 'main' into taparik/wasmWebViewJSToDotnetStreaming
TanayParikh Jul 9, 2021
97668f2
PR Feedback
TanayParikh Jul 9, 2021
32c30af
Updated Release .js
TanayParikh Jul 9, 2021
0fc102d
Create Microsoft.JSInterop.WebAssembly.WarningSuppressions.xml
TanayParikh Jul 9, 2021
dffadb9
Merge branch 'main' into taparik/wasmWebViewJSToDotnetStreaming
TanayParikh Jul 13, 2021
cffc429
Updated WASM/WebView Pull Based Implementation
TanayParikh Jul 13, 2021
a6d1842
InputFile Updated Implementation
TanayParikh Jul 13, 2021
834ecfe
Cleanup
TanayParikh Jul 13, 2021
8431126
Merge branch 'main' into taparik/wasmWebViewJSToDotnetStreaming
TanayParikh Jul 13, 2021
c01f9e3
PR Feedback
TanayParikh Jul 13, 2021
1fc7533
Remove ReadRequest
TanayParikh Jul 13, 2021
8f46b09
PR Feedback II
TanayParikh Jul 14, 2021
23bff7e
Tests
TanayParikh Jul 14, 2021
99b09e8
Merge branch 'main' into taparik/wasmWebViewJSToDotnetStreaming
TanayParikh Jul 14, 2021
33556c8
PR Feedback
TanayParikh Jul 14, 2021
de63b91
Address `JS` to `DotNet` byte[] Interop API Review Feedback (#34328)
TanayParikh Jul 15, 2021
1e94d7f
Final PR Feedback
TanayParikh Jul 15, 2021
ea0de9b
Fix WebView for large Files
TanayParikh Jul 15, 2021
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
23 changes: 10 additions & 13 deletions src/Components/Server/src/Circuits/RemoteJSDataStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,20 @@ public static async ValueTask<RemoteJSDataStream> CreateRemoteJSDataStreamAsync(
RemoteJSRuntime runtime,
IJSStreamReference jsStreamReference,
long totalLength,
long maximumIncomingBytes,
long signalRMaximumIncomingBytes,
TimeSpan jsInteropDefaultCallTimeout,
long pauseIncomingBytesThreshold = -1,
long resumeIncomingBytesThreshold = -1,
CancellationToken cancellationToken = default)
{
// Enforce minimum 1 kb, maximum 50 kb, SignalR message size.
// We budget 512 bytes overhead for the transfer, thus leaving at least 512 bytes for data
// transfer per chunk with a 1 kb message size.
// Additionally, to maintain interactivity, we put an upper limit of 50 kb on the message size.
var chunkSize = maximumIncomingBytes > 1024 ?
Math.Min(maximumIncomingBytes, 50*1024) - 512 :
var chunkSize = signalRMaximumIncomingBytes > 1024 ?
Math.Min(signalRMaximumIncomingBytes, 50*1024) - 512 :
throw new ArgumentException($"SignalR MaximumIncomingBytes must be at least 1 kb.");

var streamId = runtime.RemoteJSDataStreamNextInstanceId++;
var remoteJSDataStream = new RemoteJSDataStream(runtime, streamId, totalLength, jsInteropDefaultCallTimeout, pauseIncomingBytesThreshold, resumeIncomingBytesThreshold, cancellationToken);
var remoteJSDataStream = new RemoteJSDataStream(runtime, streamId, totalLength, jsInteropDefaultCallTimeout, cancellationToken);
await runtime.InvokeVoidAsync("Blazor._internal.sendJSDataStream", jsStreamReference, streamId, chunkSize);
return remoteJSDataStream;
}
Expand All @@ -65,8 +63,6 @@ private RemoteJSDataStream(
long streamId,
long totalLength,
TimeSpan jsInteropDefaultCallTimeout,
long pauseIncomingBytesThreshold,
long resumeIncomingBytesThreshold,
CancellationToken cancellationToken)
{
_runtime = runtime;
Expand All @@ -80,7 +76,7 @@ private RemoteJSDataStream(

_runtime.RemoteJSDataStreamInstances.Add(_streamId, this);

_pipe = new Pipe(new PipeOptions(pauseWriterThreshold: pauseIncomingBytesThreshold, resumeWriterThreshold: resumeIncomingBytesThreshold));
_pipe = new Pipe();
_pipeReaderStream = _pipe.Reader.AsStream();
PipeReader = _pipe.Reader;
}
Expand All @@ -94,9 +90,6 @@ private async Task<bool> ReceiveData(long chunkId, byte[] chunk, string error)
{
try
{
_lastDataReceivedTime = DateTimeOffset.UtcNow;
_ = ThrowOnTimeout();

if (!string.IsNullOrEmpty(error))
{
throw new InvalidOperationException($"An error occurred while reading the remote stream: {error}");
Expand All @@ -111,7 +104,7 @@ private async Task<bool> ReceiveData(long chunkId, byte[] chunk, string error)

if (chunk.Length == 0)
{
throw new EndOfStreamException($"The incoming data chunk cannot be empty.");
throw new EndOfStreamException("The incoming data chunk cannot be empty.");
}

_bytesRead += chunk.Length;
Expand All @@ -121,6 +114,10 @@ private async Task<bool> ReceiveData(long chunkId, byte[] chunk, string error)
throw new EndOfStreamException($"The incoming data stream declared a length {_totalLength}, but {_bytesRead} bytes were sent.");
}

// Start timeout _after_ performing validations on data.
_lastDataReceivedTime = DateTimeOffset.UtcNow;
_ = ThrowOnTimeout();

await _pipe.Writer.WriteAsync(chunk, _streamCancellationToken);

if (_bytesRead == _totalLength)
Expand Down
4 changes: 2 additions & 2 deletions src/Components/Server/src/Circuits/RemoteJSRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ public void MarkPermanentlyDisconnected()
_clientProxy = null;
}

protected override async Task<Stream> ReadJSDataAsStreamAsync(IJSStreamReference jsStreamReference, long totalLength, long pauseIncomingBytesThreshold = -1, long resumeIncomingBytesThreshold = -1, CancellationToken cancellationToken = default)
=> await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(this, jsStreamReference, totalLength, _maximumIncomingBytes, _options.JSInteropDefaultCallTimeout, pauseIncomingBytesThreshold, resumeIncomingBytesThreshold, cancellationToken);
protected override async Task<Stream> ReadJSDataAsStreamAsync(IJSStreamReference jsStreamReference, long totalLength, CancellationToken cancellationToken = default)
=> await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(this, jsStreamReference, totalLength, _maximumIncomingBytes, _options.JSInteropDefaultCallTimeout, cancellationToken);

public static class Log
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<Reference Include="Microsoft.Extensions.Logging" />
<!-- Required for S.T.J source generation -->
<Reference Include="System.Text.Json" PrivateAssets="All" />

<Compile Include="$(SharedSourceRoot)ValueStopwatch\*.cs" />

<Compile Include="$(SharedSourceRoot)LinkerFlags.cs" LinkBase="Shared" />
Expand Down
16 changes: 6 additions & 10 deletions src/Components/Server/test/Circuits/RemoteJSDataStreamTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task CreateRemoteJSDataStreamAsync_CreatesStream()
var jsStreamReference = Mock.Of<IJSStreamReference>();

// Act
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(_jsRuntime, jsStreamReference, totalLength: 100, maximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), pauseIncomingBytesThreshold: 50, resumeIncomingBytesThreshold: 25, cancellationToken: CancellationToken.None).DefaultTimeout();
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(_jsRuntime, jsStreamReference, totalLength: 100, signalRMaximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), cancellationToken: CancellationToken.None).DefaultTimeout();

// Assert
Assert.NotNull(remoteJSDataStream);
Expand Down Expand Up @@ -146,7 +146,7 @@ public async Task ReceiveData_ProvidedWithMoreBytesThanRemaining()
// Arrange
var jsRuntime = new TestRemoteJSRuntime(Options.Create(new CircuitOptions()), Options.Create(new HubOptions()), Mock.Of<ILogger<RemoteJSRuntime>>());
var jsStreamReference = Mock.Of<IJSStreamReference>();
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime, jsStreamReference, totalLength: 100, maximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), pauseIncomingBytesThreshold: 50, resumeIncomingBytesThreshold: 25, cancellationToken: CancellationToken.None);
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime, jsStreamReference, totalLength: 100, signalRMaximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), cancellationToken: CancellationToken.None);
var streamId = GetStreamId(remoteJSDataStream, jsRuntime);
var chunk = new byte[110]; // 100 byte totalLength for stream

Expand All @@ -166,7 +166,7 @@ public async Task ReceiveData_ProvidedWithOutOfOrderChunk_SimulatesSignalRDiscon
// Arrange
var jsRuntime = new TestRemoteJSRuntime(Options.Create(new CircuitOptions()), Options.Create(new HubOptions()), Mock.Of<ILogger<RemoteJSRuntime>>());
var jsStreamReference = Mock.Of<IJSStreamReference>();
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime, jsStreamReference, totalLength: 100, maximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), pauseIncomingBytesThreshold: 50, resumeIncomingBytesThreshold: 25, cancellationToken: CancellationToken.None);
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime, jsStreamReference, totalLength: 100, signalRMaximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), cancellationToken: CancellationToken.None);
var streamId = GetStreamId(remoteJSDataStream, jsRuntime);
var chunk = new byte[5];

Expand Down Expand Up @@ -201,10 +201,8 @@ public async Task ReceiveData_NoDataProvidedBeforeTimeout_StreamDisposed()
jsRuntime,
jsStreamReference,
totalLength: 15,
maximumIncomingBytes: 10_000,
signalRMaximumIncomingBytes: 10_000,
jsInteropDefaultCallTimeout: TimeSpan.FromSeconds(2),
pauseIncomingBytesThreshold: 50,
resumeIncomingBytesThreshold: 25,
cancellationToken: CancellationToken.None);
var streamId = GetStreamId(remoteJSDataStream, jsRuntime);
var chunk = new byte[] { 3, 5, 7 };
Expand Down Expand Up @@ -244,10 +242,8 @@ public async Task ReceiveData_ReceivesDataThenTimesout_StreamDisposed()
jsRuntime,
jsStreamReference,
totalLength: 15,
maximumIncomingBytes: 10_000,
signalRMaximumIncomingBytes: 10_000,
jsInteropDefaultCallTimeout: TimeSpan.FromSeconds(3),
pauseIncomingBytesThreshold: 50,
resumeIncomingBytesThreshold: 25,
cancellationToken: CancellationToken.None);
var streamId = GetStreamId(remoteJSDataStream, jsRuntime);
var chunk = new byte[] { 3, 5, 7 };
Expand Down Expand Up @@ -281,7 +277,7 @@ public async Task ReceiveData_ReceivesDataThenTimesout_StreamDisposed()
private static async Task<RemoteJSDataStream> CreateRemoteJSDataStreamAsync(TestRemoteJSRuntime jsRuntime = null)
{
var jsStreamReference = Mock.Of<IJSStreamReference>();
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime ?? _jsRuntime, jsStreamReference, totalLength: 100, maximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), pauseIncomingBytesThreshold: 50, resumeIncomingBytesThreshold: 25, cancellationToken: CancellationToken.None);
var remoteJSDataStream = await RemoteJSDataStream.CreateRemoteJSDataStreamAsync(jsRuntime ?? _jsRuntime, jsStreamReference, totalLength: 100, signalRMaximumIncomingBytes: 10_000, jsInteropDefaultCallTimeout: TimeSpan.FromMinutes(1), cancellationToken: CancellationToken.None);
return remoteJSDataStream;
}

Expand Down
113 changes: 113 additions & 0 deletions src/Components/Shared/src/PullFromJSDataStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.JSInterop;

namespace Microsoft.AspNetCore.Components
{
/// <Summary>
/// A stream that pulls each chunk on demand using JavaScript interop. This implementation is used for
/// WebAssembly and WebView applications.
/// </Summary>
internal sealed class PullFromJSDataStream : Stream
{
private readonly IJSRuntime _runtime;
private readonly IJSStreamReference _jsStreamReference;
private readonly long _totalLength;
private readonly CancellationToken _streamCancellationToken;
private long _offset;

public static PullFromJSDataStream CreateJSDataStream(
IJSRuntime runtime,
IJSStreamReference jsStreamReference,
long totalLength,
CancellationToken cancellationToken = default)
{
var jsDataStream = new PullFromJSDataStream(runtime, jsStreamReference, totalLength, cancellationToken);
return jsDataStream;
}

private PullFromJSDataStream(
IJSRuntime runtime,
IJSStreamReference jsStreamReference,
long totalLength,
CancellationToken cancellationToken)
{
_runtime = runtime;
_jsStreamReference = jsStreamReference;
_totalLength = totalLength;
_streamCancellationToken = cancellationToken;
_offset = 0;
}

public override bool CanRead => true;

public override bool CanSeek => false;

public override bool CanWrite => false;

public override long Length => _totalLength;

public override long Position
{
get => _offset;
set => throw new NotSupportedException();
}

public override void Flush()
=> throw new NotSupportedException();

public override int Read(byte[] buffer, int offset, int count)
=> throw new NotSupportedException("Synchronous reads are not supported.");

public override long Seek(long offset, SeekOrigin origin)
=> throw new NotSupportedException();

public override void SetLength(long value)
=> throw new NotSupportedException();

public override void Write(byte[] buffer, int offset, int count)
=> throw new NotSupportedException();

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
=> await ReadAsync(buffer.AsMemory(offset, count), cancellationToken);

public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
var bytesRead = await RequestDataFromJSAsync(buffer.Length);
ThrowIfCancellationRequested(cancellationToken);
bytesRead.CopyTo(buffer);

return bytesRead.Length;
}

private void ThrowIfCancellationRequested(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested ||
_streamCancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
}

private async ValueTask<byte[]> RequestDataFromJSAsync(int numBytesToRead)
{
numBytesToRead = (int)Math.Min(numBytesToRead, _totalLength - _offset);
var bytesRead = await _runtime.InvokeAsync<byte[]>("Blazor._internal.getJSDataStreamChunk", _jsStreamReference, _offset, numBytesToRead);
if (bytesRead.Length != numBytesToRead)
{
throw new EndOfStreamException("Failed to read the requested number of bytes from the stream.");
}

_offset += bytesRead.Length;
if (_offset == _totalLength)
{
Dispose(true);
}
return bytesRead;
}
}
}
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.

4 changes: 1 addition & 3 deletions src/Components/Web.JS/src/Boot.Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { resolveOptions, CircuitStartOptions } from './Platform/Circuits/Circuit
import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnectionHandler';
import { attachRootComponentToLogicalElement } from './Rendering/Renderer';
import { discoverComponents, discoverPersistedState, ServerComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
import { InputFile } from './InputFile';
import { sendJSDataStream } from './Platform/Circuits/CircuitStreamingInterop';

let renderingFailed = false;
Expand All @@ -29,7 +28,6 @@ async function boot(userOptions?: Partial<CircuitStartOptions>): Promise<void> {
const options = resolveOptions(userOptions);
const logger = new ConsoleLogger(options.logLevel);
Blazor.defaultReconnectionHandler = new DefaultReconnectionHandler(logger);
Blazor._internal.InputFile = InputFile;

options.reconnectionHandler = options.reconnectionHandler || Blazor.defaultReconnectionHandler;
logger.log(LogLevel.Information, 'Starting up Blazor server-side application.');
Expand Down Expand Up @@ -126,7 +124,7 @@ async function initializeConnection(options: CircuitStartOptions, logger: Logger

Blazor._internal.forceCloseConnection = () => connection.stop();

Blazor._internal.sendJSDataStream = (data: ArrayBufferView, streamId: string, chunkSize: number) => sendJSDataStream(connection, data, streamId, chunkSize);
Blazor._internal.sendJSDataStream = (data: ArrayBufferView | Blob, streamId: number, chunkSize: number) => sendJSDataStream(connection, data, streamId, chunkSize);

try {
await connection.start();
Expand Down
6 changes: 3 additions & 3 deletions src/Components/Web.JS/src/Boot.WebAssembly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { Pointer, System_Array, System_Boolean, System_Byte, System_Int, System_
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { WebAssemblyComponentAttacher } from './Platform/WebAssemblyComponentAttacher';
import { discoverComponents, discoverPersistedState, WebAssemblyComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
import { WasmInputFile } from './WasmInputFile';

declare var Module: EmscriptenModule;
let started = false;
Expand Down Expand Up @@ -43,8 +42,6 @@ async function boot(options?: Partial<WebAssemblyStartOptions>): Promise<void> {
}
});

Blazor._internal.InputFile = WasmInputFile;

Blazor._internal.applyHotReload = (id: string, metadataDelta: string, ilDeta: string) => {
DotNet.invokeMethod('Microsoft.AspNetCore.Components.WebAssembly', 'ApplyHotReloadDelta', id, metadataDelta, ilDeta);
};
Expand Down Expand Up @@ -160,6 +157,9 @@ function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any):
case DotNet.JSCallResultType.JSObjectReference:
return DotNet.createJSObjectReference(result).__jsObjectId;
case DotNet.JSCallResultType.JSStreamReference:
const streamReference = DotNet.createJSStreamReference(result);
const resultJson = JSON.stringify(streamReference);
return BINDING.js_string_to_mono_string(resultJson);
default:
throw new Error(`Invalid JS call result type '${resultType}'.`);
}
Expand Down
2 changes: 0 additions & 2 deletions src/Components/Web.JS/src/Boot.WebView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { internalFunctions as navigationManagerFunctions } from './Services/Navi
import { setEventDispatcher } from './Rendering/Events/EventDispatcher';
import { startIpcReceiver } from './Platform/WebView/WebViewIpcReceiver';
import { sendBrowserEvent, sendAttachPage, sendBeginInvokeDotNetFromJS, sendEndInvokeJSFromDotNet, sendByteArray, sendLocationChanged } from './Platform/WebView/WebViewIpcSender';
import { InputFile } from './InputFile';

let started = false;

Expand All @@ -23,7 +22,6 @@ async function boot(): Promise<void> {
sendByteArray: sendByteArray,
});

Blazor._internal.InputFile = InputFile;
navigationManagerFunctions.enableNavigationInterception();
navigationManagerFunctions.listenForNavigationEvents(sendLocationChanged);

Expand Down
6 changes: 5 additions & 1 deletion src/Components/Web.JS/src/GlobalExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnect
import { CircuitStartOptions } from './Platform/Circuits/CircuitStartOptions';
import { WebAssemblyStartOptions } from './Platform/WebAssemblyStartOptions';
import { Platform, Pointer, System_String, System_Array, System_Object, System_Boolean, System_Byte, System_Int } from './Platform/Platform';
import { getNextChunk } from './StreamingInterop';

interface IBlazor {
navigateTo: (uri: string, options: NavigationOptions) => void;
Expand Down Expand Up @@ -48,7 +49,8 @@ interface IBlazor {
getLazyAssemblies?: any
dotNetCriticalError?: any
getSatelliteAssemblies?: any,
sendJSDataStream?: (data: any, streamId: string, chunkSize: number) => void,
sendJSDataStream?: (data: any, streamId: number, chunkSize: number) => void,
getJSDataStreamChunk?: (data: any, position: number, chunkSize: number) => Promise<Uint8Array>,

// APIs invoked by hot reload
applyHotReload?: (id: string, metadataDelta: string, ilDelta: string) => void,
Expand All @@ -64,6 +66,8 @@ export const Blazor: IBlazor = {
navigationManager: navigationManagerInternalFunctions,
domWrapper: domFunctions,
Virtualize,
InputFile,
getJSDataStreamChunk: getNextChunk,
},
};

Expand Down
Loading