Skip to content

Commit 9de391f

Browse files
authored
Message size limit enhancements (#29541)
1 parent 3a4c343 commit 9de391f

File tree

12 files changed

+244
-335
lines changed

12 files changed

+244
-335
lines changed

aspnetcore/blazor/forms-and-input-components.md

Lines changed: 137 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ A form is defined using the Blazor framework's <xref:Microsoft.AspNetCore.Compon
8585
@inject ILogger<FormExample1> Logger
8686
8787
<EditForm Model="@exampleModel" OnSubmit="@HandleSubmit">
88-
<InputText id="name" @bind-Value="exampleModel.Name" />
88+
<InputText @bind-Value="exampleModel.Name" />
8989
9090
<button type="submit">Submit</button>
9191
</EditForm>
@@ -106,7 +106,7 @@ In the preceding `FormExample1` component:
106106

107107
* The <xref:Microsoft.AspNetCore.Components.Forms.EditForm> component is rendered where the `<EditForm>` element appears.
108108
* The model is created in the component's `@code` block and held in a private field (`exampleModel`). The field is assigned to <xref:Microsoft.AspNetCore.Components.Forms.EditForm.Model?displayProperty=nameWithType>'s attribute (`Model`) of the `<EditForm>` element.
109-
* The <xref:Microsoft.AspNetCore.Components.Forms.InputText> component (`id="name"`) is an input component for editing string values. The `@bind-Value` directive attribute binds the `exampleModel.Name` model property to the <xref:Microsoft.AspNetCore.Components.Forms.InputText> component's <xref:Microsoft.AspNetCore.Components.Forms.InputBase%601.Value%2A> property.
109+
* The <xref:Microsoft.AspNetCore.Components.Forms.InputText> component is an input component for editing string values. The `@bind-Value` directive attribute binds the `exampleModel.Name` model property to the <xref:Microsoft.AspNetCore.Components.Forms.InputText> component's <xref:Microsoft.AspNetCore.Components.Forms.InputBase%601.Value%2A> property.
110110
* The `HandleSubmit` method is registered as a handler for the <xref:Microsoft.AspNetCore.Components.Forms.EditForm.OnSubmit> callback. The handler is called when the form is submitted by the user.
111111

112112
To demonstrate how the preceding <xref:Microsoft.AspNetCore.Components.Forms.EditForm> component works with [data annotations](xref:mvc/models/validation) validation:
@@ -159,7 +159,7 @@ In the preceding `FormExample1` component:
159159

160160
* The <xref:Microsoft.AspNetCore.Components.Forms.EditForm> component is rendered where the `<EditForm>` element appears.
161161
* The model is created in the component's `@code` block and held in a private field (`exampleModel`). The field is assigned to <xref:Microsoft.AspNetCore.Components.Forms.EditForm.Model?displayProperty=nameWithType>'s attribute (`Model`) of the `<EditForm>` element.
162-
* The <xref:Microsoft.AspNetCore.Components.Forms.InputText> component (`id="name"`) is an input component for editing string values. The `@bind-Value` directive attribute binds the `exampleModel.Name` model property to the <xref:Microsoft.AspNetCore.Components.Forms.InputText> component's <xref:Microsoft.AspNetCore.Components.Forms.InputBase%601.Value%2A> property.
162+
* The <xref:Microsoft.AspNetCore.Components.Forms.InputText> component is an input component for editing string values. The `@bind-Value` directive attribute binds the `exampleModel.Name` model property to the <xref:Microsoft.AspNetCore.Components.Forms.InputText> component's <xref:Microsoft.AspNetCore.Components.Forms.InputBase%601.Value%2A> property.
163163
* The `HandleValidSubmit` method is assigned to <xref:Microsoft.AspNetCore.Components.Forms.EditForm.OnValidSubmit>. The handler is called if the form passes validation.
164164
* The data annotations validator (<xref:Microsoft.AspNetCore.Components.Forms.DataAnnotationsValidator> component&dagger;) attaches validation support using data annotations:
165165
* If the `<input>` form field is left blank when the **`Submit`** button is selected, an error appears in the validation summary (<xref:Microsoft.AspNetCore.Components.Forms.ValidationSummary> component&Dagger;) ("`The Name field is required.`") and `HandleValidSubmit` is **not** called.
@@ -1795,12 +1795,20 @@ Set the `CustomFieldClassProvider` class as the Field CSS Class Provider on the
17951795

17961796
:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/forms-and-validation/FormExample8.razor" highlight="21":::
17971797

1798-
The preceding example checks the validity of all form fields and applies a style to each field. If the form should only apply custom styles to a subset of the fields, make `CustomFieldClassProvider` apply styles conditionally. The following `CustomFieldClassProvider2` example only applies a style to the `Name` field. For any fields with names not matching `Name`, `string.Empty` is returned, and no style is applied.
1798+
The preceding example checks the validity of all form fields and applies a style to each field. If the form should only apply custom styles to a subset of the fields, make `CustomFieldClassProvider` apply styles conditionally. The following `CustomFieldClassProvider2` example only applies a style to the `Name` field. For any fields with names not matching `Name`, `string.Empty` is returned, and no style is applied. Using reflection, the field is matched to the model member's property or field name, not an `id` assigned to the HTML entity.
17991799

18001800
`CustomFieldClassProvider2.cs`:
18011801

18021802
:::code language="csharp" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/CustomFieldClassProvider2.cs":::
18031803

1804+
> [!NOTE]
1805+
> Matching the field name in the preceding example is case sensitive, so a model property member designated "`Name`" must match a conditional check on "`Name`":
1806+
>
1807+
> * <span aria-hidden="true">✔️</span><span class="visually-hidden">Correctly matches:</span> `fieldIdentifier.FieldName == "Name"`
1808+
> * <span aria-hidden="true">❌</span><span class="visually-hidden">Fails to match:</span> `fieldIdentifier.FieldName == "name"`
1809+
> * <span aria-hidden="true">❌</span><span class="visually-hidden">Fails to match:</span> `fieldIdentifier.FieldName == "NAME"`
1810+
> * <span aria-hidden="true">❌</span><span class="visually-hidden">Fails to match:</span> `fieldIdentifier.FieldName == "nAmE"`
1811+
18041812
Add an additional property to `ExampleModel`, for example:
18051813

18061814
```csharp
@@ -1811,7 +1819,7 @@ public string? Description { get; set; }
18111819
Add the `Description` to the `ExampleForm7` component's form:
18121820

18131821
```razor
1814-
<InputText id="description" @bind-Value="exampleModel.Description" />
1822+
<InputText @bind-Value="exampleModel.Description" />
18151823
```
18161824

18171825
Update the `EditContext` instance in the component's `OnInitialized` method to use the new Field CSS Class Provider:
@@ -1820,7 +1828,7 @@ Update the `EditContext` instance in the component's `OnInitialized` method to u
18201828
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
18211829
```
18221830

1823-
Because a CSS validation class isn't applied to the `Description` field (`id="description"`), it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
1831+
Because a CSS validation class isn't applied to the `Description` field, it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
18241832

18251833
> Description is too long.
18261834
@@ -1908,7 +1916,7 @@ public string? Description { get; set; }
19081916
Add the `Description` to the `ExampleForm7` component's form:
19091917

19101918
```razor
1911-
<InputText id="description" @bind-Value="exampleModel.Description" />
1919+
<InputText @bind-Value="exampleModel.Description" />
19121920
```
19131921

19141922
Update the `EditContext` instance in the component's `OnInitialized` method to use the new Field CSS Class Provider:
@@ -1917,7 +1925,7 @@ Update the `EditContext` instance in the component's `OnInitialized` method to u
19171925
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
19181926
```
19191927

1920-
Because a CSS validation class isn't applied to the `Description` field (`id="description"`), it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
1928+
Because a CSS validation class isn't applied to the `Description` field, it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
19211929

19221930
> Description is too long.
19231931
@@ -2005,7 +2013,7 @@ public string Description { get; set; }
20052013
Add the `Description` to the `ExampleForm7` component's form:
20062014

20072015
```razor
2008-
<InputText id="description" @bind-Value="exampleModel.Description" />
2016+
<InputText @bind-Value="exampleModel.Description" />
20092017
```
20102018

20112019
Update the `EditContext` instance in the component's `OnInitialized` method to use the new Field CSS Class Provider:
@@ -2014,7 +2022,7 @@ Update the `EditContext` instance in the component's `OnInitialized` method to u
20142022
editContext.SetFieldCssClassProvider(new CustomFieldClassProvider2());
20152023
```
20162024

2017-
Because a CSS validation class isn't applied to the `Description` field (`id="description"`), it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
2025+
Because a CSS validation class isn't applied to the `Description` field, it isn't styled. However, field validation runs normally. If more than 10 characters are provided, the validation summary indicates the error:
20182026

20192027
> Description is too long.
20202028
@@ -2229,8 +2237,117 @@ A side effect of the preceding approach is that a validation summary (<xref:Micr
22292237
}
22302238
```
22312239

2240+
## Large form payloads and the SignalR message size limit
2241+
2242+
*This section only applies to Blazor Server apps and hosted Blazor WebAssembly solutions that implement SignalR.*
2243+
2244+
:::moniker range=">= aspnetcore-6.0"
2245+
2246+
If form processing fails because the component's form payload has exceeded the maximum incoming SignalR message size permitted for hub methods, the form can adopt [streaming JS interop](xref:blazor/js-interop/call-dotnet-from-javascript#stream-from-javascript-to-net) without increasing the message size limit. For more information on the size limit and the error thrown, see <xref:blazor/fundamentals/signalr#maximum-receive-message-size>.
2247+
2248+
In the following example a text area (`<textarea>`) is used with streaming JS interop to move up to 50,000 bytes of data to the server.
2249+
2250+
Add a JavaScript (JS) `getText` function to the app:
2251+
2252+
```javascript
2253+
window.getText = (elem) => {
2254+
const textValue = elem.value;
2255+
const utf8Encoder = new TextEncoder();
2256+
const encodedTextValue = utf8Encoder.encode(textValue);
2257+
return encodedTextValue;
2258+
};
2259+
```
2260+
2261+
For information on where to place JS in a Blazor app, see <xref:blazor/js-interop/index#javaScript-location>.
2262+
2263+
`ExampleModel2.cs`:
2264+
2265+
```csharp
2266+
public class ExampleModel2
2267+
{
2268+
public string TextAreaValue { get; set; } = string.Empty;
2269+
}
2270+
```
2271+
2272+
Due to security considerations, zero-length streams aren't permitted for streaming JS Interop. Therefore, the following `FormExample10` component traps a <xref:Microsoft.JSInterop.JSException> and returns an empty string if the text area is blank when the form is submitted.
2273+
2274+
`Pages/FormExample10.razor`:
2275+
2276+
```razor
2277+
@page "/form-example-10"
2278+
@inject IJSRuntime JS
2279+
@inject ILogger<FormExample10> Logger
2280+
2281+
<h1>Stream form data with JS interop</h1>
2282+
2283+
<EditForm Model="@exampleModel" OnSubmit="@HandleSubmit">
2284+
<p>
2285+
<label>
2286+
&lt;textarea&gt; value streamed for assignment to
2287+
<code>TextAreaValue (&lt;= 50,000 characters)</code>:
2288+
<textarea @ref="largeTextArea" />
2289+
</label>
2290+
</p>
2291+
2292+
<button type="submit">Submit</button>
2293+
</EditForm>
2294+
2295+
<p>
2296+
TextAreaValue length: @exampleModel.TextAreaValue1.Length
2297+
</p>
2298+
2299+
@code {
2300+
private ExampleModel2 exampleModel = new();
2301+
private ElementReference largeTextArea;
2302+
2303+
private async Task HandleSubmit()
2304+
{
2305+
exampleModel.TextAreaValue = await GetTextAsync();
2306+
2307+
Logger.LogInformation("TextAreaValue length: {Length}",
2308+
exampleModel.TextAreaValue.Length);
2309+
}
2310+
2311+
public async Task<string> GetTextAsync()
2312+
{
2313+
try
2314+
{
2315+
var streamRef =
2316+
await JS.InvokeAsync<IJSStreamReference>("getText", largeTextArea);
2317+
var stream = await streamRef.OpenReadStreamAsync(maxAllowedSize: 50_000);
2318+
var streamReader = new StreamReader(stream);
2319+
2320+
return await streamReader.ReadToEndAsync();
2321+
}
2322+
catch (JSException jsException)
2323+
{
2324+
if (jsException.InnerException is
2325+
ArgumentOutOfRangeException outOfRangeException &&
2326+
outOfRangeException.ActualValue is not null &&
2327+
outOfRangeException.ActualValue is long actualLength &&
2328+
actualLength == 0)
2329+
{
2330+
return string.Empty;
2331+
}
2332+
2333+
throw;
2334+
}
2335+
}
2336+
}
2337+
```
2338+
2339+
:::moniker-end
2340+
2341+
:::moniker range="< aspnetcore-6.0"
2342+
2343+
If form processing fails because the component's form payload has exceeded the maximum incoming SignalR message size permitted for hub methods, the message size limit can be increased. For more information on the size limit and the error thrown, see <xref:blazor/fundamentals/signalr#maximum-receive-message-size>.
2344+
2345+
:::moniker-end
2346+
22322347
## Troubleshoot
22332348

2349+
### EditForm parameter error
2350+
22342351
> InvalidOperationException: EditForm requires a Model parameter, or an EditContext parameter, but not both.
22352352
22362353
Confirm that the <xref:Microsoft.AspNetCore.Components.Forms.EditForm> assigns a <xref:Microsoft.AspNetCore.Components.Forms.EditForm.Model> **or** an <xref:Microsoft.AspNetCore.Components.Forms.EditForm.EditContext>. Don't use both for the same form.
@@ -2253,6 +2370,16 @@ private ExampleModel exampleModel = new ExampleModel();
22532370

22542371
:::moniker-end
22552372

2373+
### Connection disconnected
2374+
2375+
> Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.
2376+
2377+
> System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions.
2378+
2379+
For more information and guidance, see the following resources:
2380+
2381+
* [Large form payloads and the SignalR message size limit](#large-form-payloads-and-the-signalr-message-size-limit)
2382+
* <xref:blazor/fundamentals/signalr#maximum-receive-message-size>
22562383

22572384
## Additional resources
22582385

0 commit comments

Comments
 (0)