Larry Lustig
Larry Lustig

Reputation: 50998

Blazor (Server Side) TextArea Fails With Long-ish Strings

I'm writing a Blazor server side application for ETL. I have a form with 8 fields, one of which is a textarea created with <InputTextArea>. This field is used to cut-and-paste the contents of data from spreadsheets, CSV files, HTML tables, etc.

The OnValidSubmit for the <EditForm> is wired to a ProcessForm() function in the @code {} section of the .razor file.

Everything works fine as long as the string in the textarea is less than 20,798 characters. When I paste 20,798 or more characters into the control, however, there is a pause on submission (the contents of the browser become disabled) then the message An error has occurred. This application may no longer respond until reloaded. Reload" appears in the footer of the viewport. I'm developing in VS Code, and nothing appears in the terminal window (or any other console window), including the logging statement at the very beginning of my ProcessForm() method. However, the message Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.' does appear on the JS console of the browser.

I've seen references to maximum buffer lengths in the underlying SignalR technology, but none of the methods I saw in older posts for setting a larger buffer appear compatible with new .MapBlazorHub method of configuring Blazor (and, in any event, I would like to be able to handle arbitrarily large amounts of data).

Does anyone know how I can increase, or remove, the data-size limit in this scenario?

Upvotes: 11

Views: 1869

Answers (4)

IvanH
IvanH

Reputation: 5159

Increasing the MaximumReceiveMessageSize can increase the risk of a DoS attack. According to the ASP.NET Core Blazor SignalR guidance - Maximum receive message size:

Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it increases the risk of Denial of Service (DoS) attacks. Additionally, reading a large amount of content in to memory as strings or byte arrays can also result in allocations that work poorly with the garbage collector, resulting in additional performance penalties.

The article recommends using the Blazor InputLargeTextArea Component Sample

I'll show key parts of the solution (the whole solution is a bit too complex for a Stack Overflow answer). The component renders a TextArea and then uses JavaScript to transfer data to and from it.

Key JavaScript functions:

function getText(elem) {
    const textValue = elem.value;
    const utf8Encoder = new TextEncoder();
    const encodedTextValue = utf8Encoder.encode(textValue);
    return encodedTextValue;
}

async function setText(elem, streamRef) {
    const bytes = await streamRef.arrayBuffer();
    const utf8Decoder = new TextDecoder();
    const newTextValue = utf8Decoder.decode(bytes);
    elem.value = newTextValue;
}

C# code to get TextArea content as a stream:

   var streamRef = await JSRuntime.InvokeAsync<IJSStreamReference>(JsFunctionsPrefix + "getText", cancellationToken, _inputLargeTextAreaElement);
   var stream = await streamRef.OpenReadStreamAsync(maxLength, cancellationToken);

C# code to write a server stream to the JavaScript stream:

   using var streamRef = new DotNetStreamReference(stream);
   await JSRuntime.InvokeVoidAsync(JsFunctionsPrefix + "setText", cancellationToken, _inputLargeTextAreaElement, streamRef);

Upvotes: 0

DaveN
DaveN

Reputation: 918

Ok, for the new Blazor Web App project types (these projects COMBINE server and client side), I've found these settings need to be added to program.cs after much hair pulling & tweaking:

    // Configure Kestrel for larger request bodies
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.Limits.MaxRequestBodySize = 256 * 1024; // 256 KB
});

// Configure Form Options for larger form data
builder.Services.Configure<FormOptions>(options =>
{
    options.ValueLengthLimit = 256 * 1024; // 256 KB
    options.MultipartBodyLengthLimit = 256 * 1024; // 256 KB
    options.MultipartHeadersLengthLimit = 256 * 1024; // 256 KB
});

// SignalR Configuration for larger message sizes
builder.Services.AddSignalR(options =>
{
    options.MaximumReceiveMessageSize = 256 * 1024; // 256 KB
});

// Build the application
var app = builder.Build();

// Add middleware and configure pipeline after Build()
app.Use((context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/_blazor"))
    {
        context.Features.Set<IHttpMaxRequestBodySizeFeature>(null);
    }
    return next();
});

In this example, I needed 256K textarea to be postable.

Hope this helps anyone using these hybrid projects in Blazor!

Upvotes: 1

Ramil Aliyev 007
Ramil Aliyev 007

Reputation: 5470

I faced this problem at today. This is caused because I am trying to send a message that is over the underlying default signalr limits, which are around 32 KB.

I found below solution.

Increase the MaximumReceiveMessageSize via HubOptions. Default value is 32 KB, but you can increase it like as below:

builder.Services.AddServerSideBlazor()
                .AddHubOptions(options =>
                {
                    options.MaximumReceiveMessageSize = 1024;  // KB
                });

if you want no limit, you set null value to MaximumReceiveMessageSize like as below:

builder.Services.AddServerSideBlazor()
                .AddHubOptions(options =>
                {
                    options.MaximumReceiveMessageSize = null; // No size limit
                });

For more information, you can visit these links:

Connection Closed Error and Attempting to Reconnect

Increase the Blazor SignalR Max Message Size

Upvotes: 2

enet
enet

Reputation: 45754

I guess this is what you need. 32kb is the default as far as I can recall.

services
    .AddServerSideBlazor()
    .AddHubOptions(options => { options.MaximumReceiveMessageSize = 32 * 1024; });

Upvotes: 9

Related Questions