Skip to content
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

Blazor Byte Array Interop Support #33015

Merged
merged 24 commits into from
Jun 4, 2021
Merged

Conversation

TanayParikh
Copy link
Contributor

@TanayParikh TanayParikh commented May 25, 2021

Implements changes discussed in #32259.

Fixes: #21877

src/Components/Server/src/ComponentHub.cs Outdated Show resolved Hide resolved
{
throw new ArgumentOutOfRangeException($"Element id '${id}' cannot be added to the byte arrays to be revived with length '${jsRuntime.ByteArraysToBeRevived.Count}'.");
}
else if (data.Length + jsRuntime.ByteArraysToBeRevivedByteLength > (31*1024)) // TODO; get this limit from SignalR somehow?
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
else if (data.Length + jsRuntime.ByteArraysToBeRevivedByteLength > (31*1024)) // TODO; get this limit from SignalR somehow?
else if (data.Length - 32k > jsRuntime.ByteArraysToBeRevivedByteLength) // TODO; get this limit from SignalR somehow?

To avoid int overflows.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe this should be:

Suggested change
else if (data.Length + jsRuntime.ByteArraysToBeRevivedByteLength > (31*1024)) // TODO; get this limit from SignalR somehow?
else if (32k - data.Length < jsRuntime.ByteArraysToBeRevivedByteLength) // TODO; get this limit from SignalR somehow?

return Array.Empty<byte>();
}

return bytes.Value.ToArray();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Still doing ToArray in place of passing through the ReadOnlySequence<byte>.

Concerns with using the ReadOnlySequence relate to the fact that it doesn't implicitly cast to byte[] so when we're examining method parameters we have a type mistmatch.

Additionally, as Javier mentioned in the other PR we need to verify the lifecycle/ownership of the ReadOnlySequence.

Copy link
Member

Choose a reason for hiding this comment

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

Concerns with using the ReadOnlySequence relate to the fact that it doesn't implicitly cast to byte[] so when we're examining method parameters we have a type mistmatch.

I think you'd need to change the receiving code (ComponentHub.SupplyByteArray) to accept a ReadOnlySequence<byte> instead of a byte[], so there wouldn't be a type mismatch.

Agreed on verifying the ownership of the buffer before doing that though.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, lets keep it as is for the time being and then we can do a quick check and change afterwards.

@TanayParikh TanayParikh force-pushed the taparik/byteArrayDirectInterop branch 3 times, most recently from efc976d to ed1412b Compare June 3, 2021 05:29
@TanayParikh TanayParikh force-pushed the taparik/byteArrayDirectInterop branch from ed1412b to f710bd0 Compare June 3, 2021 06:07
@TanayParikh
Copy link
Contributor Author

Had to revert the ByteArrayJsonConverter back to a previous version (f710bd0) due to ongoing compatibility issues in WASM/CI. Not able to repro the issue locally, and tried logging/different solutions, but not too efficient given each attempt needs to be run through the entire CI pipeline to see if it works.

f710bd0 follows the same pattern as the JS/DotnetObjectReferenceJsonConverter so I don't think this should be a big deal.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

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

This looks fantastic!

I have one small comment that needs clarification. Other than that, this is good to go!

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

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

Good to go!

@TanayParikh TanayParikh changed the title Blazorserver Byte Array Interop Support Blazor Byte Array Interop Support Jun 3, 2021
@TanayParikh TanayParikh merged commit 4dc663a into main Jun 4, 2021
@TanayParikh TanayParikh deleted the taparik/byteArrayDirectInterop branch June 4, 2021 18:09
@ghost ghost added this to the 6.0-preview6 milestone Jun 4, 2021
@TanayParikh
Copy link
Contributor Author

TanayParikh commented Jun 4, 2021

Breaking change announcement proposal:

Byte Array Interop in .NET 6.0 Preview 6

Labels:

  • Breaking Change
  • Enhancement
  • Release

Summary

Blazor Server & WebAssembly now supports optimized byte array interop which avoids encoding/decoding byte arrays into Base64, facilitating a more efficient interop process.

Breaking Change

Receiving Byte Arrays in JS

function ReceivesByteArray(data)
{
	// Previously data was a Base 64 encoded string representing the byte array
	// 6.0 Preview 6 and beyond, it'll be a Uint8Array (no longer requires processing the Base 64 encoding)
}

which can be invoked by the following C# code:

var bytes = new byte[] { 1, 5, 7 };
await _jsRuntime.InvokeVoidAsync("ReceivesByteArray", bytes);

Sending Byte Arrays from JS

If .NET is expecting a byte[] JS must provide a Uint8Array. Previously, it was possible to provide a Base64 encoded array using btoa.

For example, if you have something like this:

var bytes = await _jsRuntime.InvokeAsync<byte[]>("someJSMethodReturningAByteArray");

then you must provide a Uint8Array from JS (must not be Base 64 encoded).

Before:

function someJSMethodReturningAByteArray() {
    const data = new Uint8Array([ 1, 2, 3 ]);
    const base64EncodedData = btoa(String.fromCharCode.apply(null, data as unknown as number[]));
    return base64EncodedData;
}

After:

function someJSMethodReturningAByteArray() {
    const data = new Uint8Array([ 1, 2, 3 ]);
    return data;
}

PR: #33015
Issue: #21877

@SteveSandersonMS
Copy link
Member

Announcement looks great. Suggested tweaks:

Blazor Server & WASM now supports optimized byte array interop

Replace WASM with WebAssembly.

Receiving Byte Arrays in JS

For context, can you also show the corresponding .NET code that invokes this?

Previously, it was possible to provide a Base 64 encoding array

Typo: "Base 64 encoding array" should be "Base64 encoded array"

@TanayParikh
Copy link
Contributor Author

Thanks @SteveSandersonMS, it's official dotnet/announcements#187!

@guardrex
Copy link
Contributor

guardrex commented Jun 19, 2021

@TanayParikh / @SteveSandersonMS ... The announcement isn't labeled (and placing "in .NET 6.0 Preview 6" in the title isn't normal and doesn't filter well), so it's a bit hidden at the moment. dotnet/announcements#187

@ghost
Copy link

ghost commented Jun 19, 2021

Hi @guardrex. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

@TanayParikh
Copy link
Contributor Author

@TanayParikh / @SteveSandersonMS ... The announcement isn't labeled (and placing "in .NET 6.0 Preview 6" in the title isn't normal and doesn't filter well), so it's a bit hidden at the moment. dotnet/announcements#187

Thanks for pointing that out @guardrex, I had tried adding labels but I don't have the adequate permissions. Do you happen to have the required permissions or know how I can get them? I'd like to add in the following labels.

  • Breaking Change
  • Enhancement
  • Release
  • .NET 6.0

Also, are you familiar with how the change goes from dotnet/announcements to https://docs.microsoft.com/dotnet/core/compatibility/6.0#aspnet-core?

@guardrex
Copy link
Contributor

guardrex commented Jun 20, 2021

I don't have permission ... I'm just a docs 🐈.

Open a new issue here on the PU repo. They prefer not to work from closed issues/PRs like this.

WRT the breaking change doc ... submit a docs issue (and possibly PR) for it. It looks like the docs aren't autogenerated but actually worked up manually and then modified manually. I see dev PRs going into it on the blame .....

https://github.com/dotnet/docs/blame/main/docs/core/compatibility/6.0.md

Use the This page button at the bottom of the topic to open the issue and go from there.

@ghost
Copy link

ghost commented Jun 20, 2021

Hi @guardrex. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support byte-array transfer in JS Interop
7 participants