[EDIT] Updated this question with actual working code.
(Note: This discussion talks about the way that the array interop works, which might be relevant.)
I'm trying to transfer an array of shorts to TypeScript from Blazor using the Blazor Byte-array interop optimisation.
I have the following C# method that I invoke from JavaScript:
[JSInvokable]
public byte[] ReadDataBytes()
{
var shortArray = new short[1000]; // In real use, this comes from some data source.
var byteArray = new byte[shortArray.Length * sizeof(short)];
Buffer.BlockCopy(shortArray, 0, byteArray, 0, byteArray.Length);
return byteArray;
}
On the TypeScript side I call that method like so:
async readData(): Promise<Int16Array>
{
const byteArray = await this._dotNetObject.invokeMethodAsync<Uint8Array>("ReadDataBytes");
console.log("byteOffset = ", byteArray.byteOffset);
// Check if the byteArray is properly aligned for Int16Array
if (byteArray.byteOffset % 2 !== 0)
{
// If not aligned, create a new properly aligned buffer
const alignedBuffer = new ArrayBuffer(byteArray.byteLength);
const alignedView = new Uint8Array(alignedBuffer);
alignedView.set(byteArray);
return new Int16Array(alignedBuffer);
}
// Convert byte array directly to Int16Array (little-endian) if properly aligned
return new Int16Array(byteArray.buffer, byteArray.byteOffset, byteArray.byteLength / 2);
}
_dotNetObject is a DotNet.DotNetObject:
export declare namespace DotNet {
interface DotNetObject {
invokeMethodAsync<T>(methodIdentifier: string, ...args: any[]): Promise<T>;
invokeMethod<T>(methodIdentifier: string, ...args: any[]): T;
dispose(): void;
}
}
This works, but in my tests byteArray.byteOffset starts off at 29 for a few calls, then becomes 30 for some more calls and finally becomes 31 for all remaining calls. For example, I see the following output to the browser console:
7 byteOffset = 29
7 byteOffset = 30
119 byteOffset = 31
If I remove the code that deals with a byteOffset which isn't a multiple of 2:
async readData(): Promise<Int16Array>
{
const byteArray = await this._dotNetObject.invokeMethodAsync<Uint8Array>("ReadDataBytes");
console.log("byteOffset = ", byteArray.byteOffset);
// Convert byte array directly to Int16Array (little-endian)
return new Int16Array(byteArray.buffer, byteArray.byteOffset, byteArray.byteLength / 2);
}
Then I get the error: RangeError: start offset of Int16Array should be a multiple of 2.
Is there any way to configure things so that the data is correctly aligned to a multiple of sizeof(short) in ReadDataBytes() so that I don't need to copy the data to align it in readData()?