Search code examples
c#blazorblazor-jsinterop

Blazor: How to pass very long string from JS to C#?


I have a Blazor Component Library. In the library my js code generates a huge string which is about 160 000 characters. Simplified JS below (actualy this is base64 string)

export function showPrompt(message): Uint8Array {
    alert(message);
    let str = "";
    for(let i = 0; i < 164232; i++)
        str += "A";
    return new TextEncoder().encode(str);
}

My C# code is:

async void CallJS() {
    string? str = null;
    IJSStreamReference? jsStream = await Prompt("After you will press ok, long string will be generated");
    if (jsStream != null) {
        using Stream referenceStream = await jsStream.OpenReadStreamAsync();
        byte[] byteArray = new byte[referenceStream.Length];
        int byteArrayCount = await referenceStream.ReadAsync(byteArray);
        str =  System.Text.Encoding.Default.GetString(byteArray, 0, byteArrayCount);
    }
    length = str?.Length ?? 0;
}

When I use this component in Blazor Server App, C# gets only 32 thousands chars. As I understand this is due to Signal-R limitation. I've found this topic: Pass large JS blob to Blazor byte[] and tried the solution, but even with the code below, c# receives only 50 000 characters.

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

How to pass a huge string from JS to C# in Blazor?


Solution

  • I have managed to solve this problem only by chanking the message:

    TS: //Type Script Code:

    let str = "";
    
    //generate large string
    export function exportImageAndGetBase64Length(message): number {
        alert(message);
        for(let i = 0; i < 164232; i++)
            str += "A";
        return str.length;
    }
    
    //get part of the generated string
    export function getChunk(startIndex, endIndex): string {
        return str.substring(startIndex, endIndex);
    }
    
    //finish transition and clean up the string 
    export function ClearBuffer() {
        str = "";
    }
    

    Razor

    inject Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.SignalR.HubOptions> Options
    

    C#:

    async void GetLongStringFromJS() {
        int fileLength = await module.InvokeAsync<int>("exportImageAndGetBase64Length", "long string of 164232 will be generated and send to c#");
    
        HubOptions a = Options.Value;
        int maximumSingnalRMessageSize = (a.MaximumReceiveMessageSize == null || a.MaximumReceiveMessageSize > 32768) ? 32768 : (int)a.MaximumReceiveMessageSize;
    
        int chunkLength = (int)maximumSingnalRMessageSize / sizeof(char);
    
        StringBuilder sb = new StringBuilder();
        for (int startIndex = 0, endIndex = chunkLength; startIndex <= fileLength; startIndex += chunkLength, endIndex += chunkLength) {
            if (endIndex > fileLength + 1)
                endIndex = fileLength + 1;
            string chunk = await module.InvokeAsync<string>("getChunk", startIndex, endIndex);
            sb.Append(chunk);
        }
        length = sb.Length; //do somthing with your string
        await module.InvokeVoidAsync("ClearBuffer");
        this.StateHasChanged();
    }