Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass large JS blob to Blazor byte[]

I need to record some audio, maybe even video, using Media API in JS, example for Blazor. Then, I would like to pass recorded Blob content from JS to Blazor. As far as this is audio or video content, it can be pretty big.

What I have tried so far

  1. Encoding data as ANSI string or passing an array of integers. This results in InvalidDataException, SignalR disconnect, timeout, after a minute or so SignalR gets back to life and C# receives null

  2. Encoding data as base 64 or passing UInt8Array. Outcome is the same.

  3. Passing Blob, ArrayBuffer, or FormData directly from JS. This results in empty object ValueKind: {} in C#.

The source of JS call

recorder.stop();
recorder.exportWAV(async blob => {
  const content = await (new Response(blob).arrayBuffer());
  const contentNums = new Uint8Array(content);
  const contentCodes = new TextDecoder('windows-1252').decode(contentNums);
  const data = new FormData();
  data.append('file', blob, 'Demo');
  //success(window.URL.createObjectURL(blob));
  console.log(blob)
  console.log(content)
  console.log(contentNums)
  console.log(contentCodes)
  success(Array.from(contentNums));
})

The source of C# interop call

private IJSRuntime _scriptRuntime = null;

public async Task<dynamic> GetMedia<dynamic>()
{
  return await _scriptRuntime.InvokeAsync<dynamic>('AudioFunctions.GetMediaFile');
}

Is there a way to pass large byte arrays or at least strings from JS to Blazor.NET?

like image 526
Anonymous Avatar asked Oct 30 '25 15:10

Anonymous


1 Answers

Appears to be, the hack with ANSI encoding works fine, I just needed to increase the size of SignalR messages.

Startup

public void ConfigureServices(IServiceCollection services)
{
  // ... some other services

  services.AddSignalR(o =>
  {
    o.EnableDetailedErrors = true;
    o.MaximumReceiveMessageSize = long.MaxValue;
  });
}

JS interop

window.InteropFunctions = window.InteropFunctions || {

  GetMediaFile: async (classInstance, cssClass) => {

    return await new Promise((success, error) => {

      const chunks = [];
      const recorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });

      // Event handlers for play and stop to detect when data is available

      recorder.addEventListener('stop', {

        // Encode data as ANSI string - Windows 1252 

        const response = new Blob(chunks, { type: 'audio/webm' });
        const content = await (new Response(response).arrayBuffer());
        const contentNums = new Uint8Array(content);
        const contentCodes = new TextDecoder('windows-1252').decode(contentNums);
        const audioControl = document.querySelector('.' + cssClass + ' audio');

        // Play audio in HTML 5 control

        if (audioControl) {
          audioControl.src = URL.createObjectURL(response);
        }

        // Resolve the promise and send data to Blazor.NET

        success(contentCodes);
      });

      // Grab recorded data
      
      recorder.addEventListener('dataavailable', {
        if (e.data.size > 0) {
          chunks.push(e.data);
        }
      });
      
      // Record for 5 seconds
      
      recorder.start();      
      setTimeout(() => recorder.stop(), 5000);
    });
  }
}

C# Interop

private IJSRuntime _scriptRuntime = null;

public async Task<string> GetMediaFile<string>(params object[] inputs)
{
  return await _scriptRuntime.InvokeAsync<string>("InteropFunctions.GetMediaFile", inputs);
}

Initiate interop call from .NET

var instance = DotNetObjectReference.Create(this);
var source = await _audioCommandInstance.GetMediaFile(instance, "audio-container");

if (string.IsNullOrEmpty(source) == false)
{
  var audioBytes = Encoder.GetBytes(source);
  
  await File.WriteAllBytesAsync("audio.wav", audioBytes);
}
like image 152
Anonymous Avatar answered Nov 02 '25 06:11

Anonymous



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!