From ab7325cc4c6b06eeb75468702a70a064e9c03dcc Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 4 Nov 2021 13:13:43 -0500 Subject: [PATCH] Blazor JS interop SignalR size limits (Part 2) --- .../includes/js-interop/3.1/size-limits.md | 58 +++++++++++++++++++ .../includes/js-interop/5.0/size-limits.md | 58 +++++++++++++++++++ .../js-interop/{ => 6.0}/size-limits.md | 24 ++------ .../call-dotnet-from-javascript.md | 6 +- .../call-javascript-from-dotnet.md | 6 +- 5 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 aspnetcore/blazor/includes/js-interop/3.1/size-limits.md create mode 100644 aspnetcore/blazor/includes/js-interop/5.0/size-limits.md rename aspnetcore/blazor/includes/js-interop/{ => 6.0}/size-limits.md (73%) diff --git a/aspnetcore/blazor/includes/js-interop/3.1/size-limits.md b/aspnetcore/blazor/includes/js-interop/3.1/size-limits.md new file mode 100644 index 000000000000..33bcbdc565c5 --- /dev/null +++ b/aspnetcore/blazor/includes/js-interop/3.1/size-limits.md @@ -0,0 +1,58 @@ +--- +no-loc: [Home, Privacy, Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] +--- +*This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.* + +In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by (default: 32 KB). JS to .NET SignalR messages larger than throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client. + +When SignalR logging isn't set to [Debug](xref:Microsoft.Extensions.Logging.LogLevel) or [Trace](xref:Microsoft.Extensions.Logging.LogLevel), a message size error only appears in the browser's developer tools console: + +> Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'. + +When [SignalR server-side logging](xref:signalr/diagnostics#server-side-logging) is set to [Debug](xref:Microsoft.Extensions.Logging.LogLevel) or [Trace](xref:Microsoft.Extensions.Logging.LogLevel), server-side logging surfaces an for a message size error. + +`appsettings.Development.json`: + +```json +{ + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.AspNetCore.SignalR": "Debug" + } + } +} +``` + +Error: + +> System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions. + +Increase the limit by setting in `Startup.ConfigureServices`: + +```csharp +services.AddServerSideBlazor() + .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024); +``` + +Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. 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. + +One option for reading large payloads is to send the content in smaller chunks and process the payload as a . This can be used when reading large JSON payloads or if data is available in JS as raw bytes. For an example that demonstrates sending large binary payloads in Blazor Server that uses techniques similar to the [`InputFile` component](xref:blazor/file-uploads), see the [Binary Submit sample app](https://github.com/aspnet/samples/tree/main/samples/aspnetcore/blazor/BinarySubmit). + +[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps: + +* Slice the data into smaller pieces, and send the data segments sequentially until all of the data is received by the server. +* Don't allocate large objects in JS and C# code. +* Don't block the main UI thread for long periods when sending or receiving data. +* Free consumed memory when the process is completed or cancelled. +* Enforce the following additional requirements for security purposes: + * Declare the maximum file or data size that can be passed. + * Declare the minimum upload rate from the client to the server. +* After the data is received by the server, the data can be: + * Temporarily stored in a memory buffer until all of the segments are collected. + * Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received. diff --git a/aspnetcore/blazor/includes/js-interop/5.0/size-limits.md b/aspnetcore/blazor/includes/js-interop/5.0/size-limits.md new file mode 100644 index 000000000000..33bcbdc565c5 --- /dev/null +++ b/aspnetcore/blazor/includes/js-interop/5.0/size-limits.md @@ -0,0 +1,58 @@ +--- +no-loc: [Home, Privacy, Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] +--- +*This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.* + +In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by (default: 32 KB). JS to .NET SignalR messages larger than throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client. + +When SignalR logging isn't set to [Debug](xref:Microsoft.Extensions.Logging.LogLevel) or [Trace](xref:Microsoft.Extensions.Logging.LogLevel), a message size error only appears in the browser's developer tools console: + +> Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'. + +When [SignalR server-side logging](xref:signalr/diagnostics#server-side-logging) is set to [Debug](xref:Microsoft.Extensions.Logging.LogLevel) or [Trace](xref:Microsoft.Extensions.Logging.LogLevel), server-side logging surfaces an for a message size error. + +`appsettings.Development.json`: + +```json +{ + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.AspNetCore.SignalR": "Debug" + } + } +} +``` + +Error: + +> System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions. + +Increase the limit by setting in `Startup.ConfigureServices`: + +```csharp +services.AddServerSideBlazor() + .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024); +``` + +Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. 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. + +One option for reading large payloads is to send the content in smaller chunks and process the payload as a . This can be used when reading large JSON payloads or if data is available in JS as raw bytes. For an example that demonstrates sending large binary payloads in Blazor Server that uses techniques similar to the [`InputFile` component](xref:blazor/file-uploads), see the [Binary Submit sample app](https://github.com/aspnet/samples/tree/main/samples/aspnetcore/blazor/BinarySubmit). + +[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps: + +* Slice the data into smaller pieces, and send the data segments sequentially until all of the data is received by the server. +* Don't allocate large objects in JS and C# code. +* Don't block the main UI thread for long periods when sending or receiving data. +* Free consumed memory when the process is completed or cancelled. +* Enforce the following additional requirements for security purposes: + * Declare the maximum file or data size that can be passed. + * Declare the minimum upload rate from the client to the server. +* After the data is received by the server, the data can be: + * Temporarily stored in a memory buffer until all of the segments are collected. + * Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received. diff --git a/aspnetcore/blazor/includes/js-interop/size-limits.md b/aspnetcore/blazor/includes/js-interop/6.0/size-limits.md similarity index 73% rename from aspnetcore/blazor/includes/js-interop/size-limits.md rename to aspnetcore/blazor/includes/js-interop/6.0/size-limits.md index 8114781c3324..5e301b11e127 100644 --- a/aspnetcore/blazor/includes/js-interop/size-limits.md +++ b/aspnetcore/blazor/includes/js-interop/6.0/size-limits.md @@ -31,34 +31,20 @@ Error: > System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions. -Increase the limit by setting in `Program.cs`. The following example sets the maximum receive message size to 64 KB (64 * 1024) in ASP.NET Core 6.0 or later: +Increase the limit by setting in `Program.cs`. The following example sets the maximum receive message size to 64 KB (64 * 1024): ```csharp builder.Services.AddServerSideBlazor() - .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024); -``` - -In `Startup.ConfigureServices` for versions of ASP.NET Core earlier than 6.0: - -```csharp -services.AddServerSideBlazor() - .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024); + .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024); ``` Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. 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. -[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps: -* For ASP.NET Core 6.0 and newer: - * Leverage the native streaming interop support to transfer data larger than the SignalR incoming message size limit. - * - * -* For versions of ASP.NET Core earlier than 6.0: - * Slice the data into smaller pieces, and send the data segments sequentially as a until all of the data is received by the server. - * Don't block the main UI thread for long periods when sending or receiving data. - * For an example that demonstrates sending large binary payloads in Blazor Server, see the [Binary Submit sample app](https://github.com/aspnet/samples/tree/main/samples/aspnetcore/blazor/BinarySubmit). +* Leverage the native streaming interop support to transfer data larger than the SignalR incoming message size limit: + * + * * General tips: * Don't allocate large objects in JS and C# code. * Free consumed memory when the process is completed or cancelled. diff --git a/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md b/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md index fe7c1619fd1e..5ce9d6c4389c 100644 --- a/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md +++ b/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md @@ -394,7 +394,7 @@ In the preceding example: ## Size limits on JavaScript interop calls -[!INCLUDE[](~/blazor/includes/js-interop/size-limits.md)] +[!INCLUDE[](~/blazor/includes/js-interop/6.0/size-limits.md)] ## JavaScript isolation in JavaScript modules @@ -708,7 +708,7 @@ Objects that contain circular references can't be serialized on the client for e ## Size limits on JavaScript interop calls -[!INCLUDE[](~/blazor/includes/js-interop/size-limits.md)] +[!INCLUDE[](~/blazor/includes/js-interop/5.0/size-limits.md)] ## JavaScript isolation in JavaScript modules @@ -1020,7 +1020,7 @@ Objects that contain circular references can't be serialized on the client for e ## Size limits on JavaScript interop calls -[!INCLUDE[](~/blazor/includes/js-interop/size-limits.md)] +[!INCLUDE[](~/blazor/includes/js-interop/3.1/size-limits.md)] ## Additional resources diff --git a/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md b/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md index 0bc5bc5d1884..88b818545763 100644 --- a/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md +++ b/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md @@ -581,7 +581,7 @@ For information on using a byte array when calling .NET from JavaScript, see