Skip to content
4 changes: 2 additions & 2 deletions aspnetcore/blazor/call-web-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ public class CookieHandler : DelegatingHandler
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", ["XMLHttpRequest"]);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);

return base.SendAsync(request, cancellationToken);
}
Expand Down Expand Up @@ -694,7 +694,7 @@ When composing an <xref:System.Net.Http.HttpRequestMessage>, set the browser req
var requestMessage = new HttpRequestMessage() { ... };

requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
requestMessage.Headers.Add("X-Requested-With", ["XMLHttpRequest"]);
requestMessage.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
```

## `HttpClient` and `HttpRequestMessage` with Fetch API request options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ Reusable Razor components may include forms (either `<form>` or `<EditForm>`), a
Consider the following example:

```razor
<EditForm Enhance FormName="NewProduct" Model="Model" OnValidSubmit="SaveProduct">
<EditForm Enhance FormName="NewProduct" Model="Model" OnValidSubmit="Save">
<DataAnnotationsValidator />
<ValidationSummary />

<p><label>Name: <InputText @bind-Value="Item.Name" /></label></p>
<p><label>Name: <InputText @bind-Value="Model!.Name" /></label></p>

<button type="submit">Submit</button>
</EditForm>
Expand Down
65 changes: 65 additions & 0 deletions aspnetcore/blazor/components/data-binding.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,67 @@ Binding supports [`multiple`](https://developer.mozilla.org/docs/Web/HTML/Attrib

`BindMultipleInput.razor`:

:::moniker-end

:::moniker range=">= aspnetcore-8.0"

```razor
@page "/bind-multiple-input"

<h1>Bind Multiple <code>input</code>Example</h1>

<p>
<label>
Select one or more cars:
<select @onchange="SelectedCarsChanged" multiple>
<option value="audi">Audi</option>
<option value="jeep">Jeep</option>
<option value="opel">Opel</option>
<option value="saab">Saab</option>
<option value="volvo">Volvo</option>
</select>
</label>
</p>

<p>
Selected Cars: @string.Join(", ", SelectedCars)
</p>

<p>
<label>
Select one or more cities:
<select @bind="SelectedCities" multiple>
<option value="bal">Baltimore</option>
<option value="la">Los Angeles</option>
<option value="pdx">Portland</option>
<option value="sf">San Francisco</option>
<option value="sea">Seattle</option>
</select>
</label>
</p>

<span>
Selected Cities: @string.Join(", ", SelectedCities)
</span>

@code {
public string[] SelectedCars { get; set; } = [];
public string[] SelectedCities { get; set; } = [ "bal", "sea" ];

private void SelectedCarsChanged(ChangeEventArgs e)
{
if (e.Value is not null)
{
SelectedCars = (string[])e.Value;
}
}
}
```

:::moniker-end

:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0"

```razor
@page "/bind-multiple-input"

Expand Down Expand Up @@ -452,6 +513,10 @@ Binding supports [`multiple`](https://developer.mozilla.org/docs/Web/HTML/Attrib
}
```

:::moniker-end

:::moniker range=">= aspnetcore-6.0"

For information on how empty strings and `null` values are handled in data binding, see the [Binding `<select>` element options to C# object `null` values](#binding-select-element-options-to-c-object-null-values) section.

:::moniker-end
Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/blazor/components/virtualization.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ Change the `OnInitialized` method lambda to see the component display strings:

```csharp
protected override void OnInitialized() =>
stringList ??= new() { "Here's a string!", "Here's another string!" };
stringList ??= [ "Here's a string!", "Here's another string!" ];
```

:::moniker-end
Expand Down
119 changes: 111 additions & 8 deletions aspnetcore/blazor/forms/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,61 @@ The validation for the `Defense` ship classification only occurs on the server i

`Controllers/StarshipValidation.cs`:

:::moniker range=">= aspnetcore-8.0"

```csharp
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers;

[Authorize]
[ApiController]
[Route("[controller]")]
public class StarshipValidationController(
ILogger<StarshipValidationController> logger)
: ControllerBase
{
static readonly string[] scopeRequiredByApi = [ "API.Access" ];

[HttpPost]
public async Task<IActionResult> Post(Starship model)
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);

try
{
if (model.Classification == "Defense" &&
string.IsNullOrEmpty(model.Description))
{
ModelState.AddModelError(nameof(model.Description),
"For a 'Defense' ship " +
"classification, 'Description' is required.");
}
else
{
logger.LogInformation("Processing the form asynchronously");

// async ...

return Ok(ModelState);
}
}
catch (Exception ex)
{
logger.LogError("Validation Error: {Message}", ex.Message);
}

return BadRequest(ModelState);
}
}
```

:::moniker-end

:::moniker range="< aspnetcore-8.0"

```csharp
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -402,6 +457,8 @@ public class StarshipValidationController(
}
```

:::moniker-end

Confirm or update the namespace of the preceding controller (`BlazorSample.Server.Controllers`) to match the app's controllers' namespace.

When a model binding validation error occurs on the server, an [`ApiController`](xref:web-api/index) (<xref:Microsoft.AspNetCore.Mvc.ApiControllerAttribute>) normally returns a [default bad request response](xref:web-api/index#default-badrequest-response) with a <xref:Microsoft.AspNetCore.Mvc.ValidationProblemDetails>. The response contains more data than just the validation errors, as shown in the following example when all of the fields of the `Starfleet Starship Database` form aren't submitted and the form fails validation:
Expand All @@ -411,10 +468,10 @@ When a model binding validation error occurs on the server, an [`ApiController`]
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Id": ["The Id field is required."],
"Classification": ["The Classification field is required."],
"IsValidatedDesign": ["This form disallows unapproved ships."],
"MaximumAccommodation": ["Accommodation invalid (1-100000)."]
"Id": [ "The Id field is required." ],
"Classification": [ "The Classification field is required." ],
"IsValidatedDesign": [ "This form disallows unapproved ships." ],
"MaximumAccommodation": [ "Accommodation invalid (1-100000)." ]
}
}
```
Expand All @@ -426,10 +483,10 @@ If the server API returns the preceding default JSON response, it's possible for

```json
{
"Id": ["The Id field is required."],
"Classification": ["The Classification field is required."],
"IsValidatedDesign": ["This form disallows unapproved ships."],
"MaximumAccommodation": ["Accommodation invalid (1-100000)."]
"Id": [ "The Id field is required." ],
"Classification": [ "The Classification field is required." ],
"IsValidatedDesign": [ "This form disallows unapproved ships." ],
"MaximumAccommodation": [ "Accommodation invalid (1-100000)." ]
}
```

Expand Down Expand Up @@ -951,6 +1008,50 @@ To ensure that a validation result is correctly associated with a field when usi

`CustomValidator.cs`:

:::moniker range=">= aspnetcore-8.0"

```csharp
using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object? value,
ValidationContext validationContext)
{
...

return new ValidationResult("Validation message to user.",
[ validationContext.MemberName! ]);
}
}
```

:::moniker-end

:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0"

```csharp
using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object? value,
ValidationContext validationContext)
{
...

return new ValidationResult("Validation message to user.",
new[] { validationContext.MemberName! });
}
}
```

:::moniker-end

:::moniker range="< aspnetcore-6.0"

```csharp
using System;
using System.ComponentModel.DataAnnotations;
Expand All @@ -968,6 +1069,8 @@ public class CustomValidator : ValidationAttribute
}
```

:::moniker-end

Inject services into custom validation attributes through the <xref:System.ComponentModel.DataAnnotations.ValidationContext>. The following example demonstrates a salad chef form that validates user input with dependency injection (DI).

The `SaladChef` class indicates the approved starship ingredient list for a Ten Forward salad.
Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/blazor/fundamentals/dependency-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ public class CircuitServicesAccessor
public IServiceProvider? Services
{
get => blazorServices.Value;
set => blazorServices.Value = value;
set => blazorServices.Value = value!;
}
}

Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/blazor/fundamentals/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ In the following example, the `Routes` component is in the server project, and t
```razor
<Router
AppAssembly="..."
AdditionalAssemblies="new[] { typeof(BlazorSample.Client._Imports).Assembly }">
AdditionalAssemblies="[ typeof(BlazorSample.Client._Imports).Assembly ]">
...
</Router>
```
Expand Down
10 changes: 5 additions & 5 deletions aspnetcore/blazor/globalization-localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -1042,11 +1042,11 @@ The component adopts the following approaches to work for either SSR or CSR comp
{ "es-CR", "Spanish (Costa Rica)" }
};

private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CR"),
};
private CultureInfo[] supportedCultures =
[
new CultureInfo("en-US"),
new CultureInfo("es-CR"),
];

private CultureInfo? selectedCulture;

Expand Down
6 changes: 3 additions & 3 deletions aspnetcore/blazor/hybrid/class-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ namespace {APP NAMESPACE}.Services;

public class WeatherForecastService : IWeatherForecastService
{
private static readonly string[] Summaries = new[]
{
private static readonly string[] Summaries =
[
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot"
};
];

public async Task<WeatherForecast[]?> GetForecastAsync(DateTime startDate) =>
await Task.FromResult(Enumerable.Range(1, 5)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1102,10 +1102,22 @@ The `{TIMEOUT}` placeholder is a <xref:System.TimeSpan> (for example, `TimeSpan.

Set a per-invocation timeout in component code. The specified timeout overrides the global timeout set by <xref:Microsoft.AspNetCore.Components.Server.CircuitOptions.JSInteropDefaultCallTimeout>:

:::moniker range=">= aspnetcore-8.0"

```csharp
var result = await JS.InvokeAsync<string>("{ID}", {TIMEOUT}, [ "Arg1" ]);
```

:::moniker-end

:::moniker range="< aspnetcore-8.0"

```csharp
var result = await JS.InvokeAsync<string>("{ID}", {TIMEOUT}, new[] { "Arg1" });
```

:::moniker-end

In the preceding example:

* The `{TIMEOUT}` placeholder is a <xref:System.TimeSpan> (for example, `TimeSpan.FromSeconds(80)`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Inline JavaScript isn't recommended for Blazor apps. We recommend using [JS coll

:::moniker range=">= aspnetcore-8.0"

Only place a `<script>` tag in a component file (`.razor`) if the component is guaranteed to adopt [static server-side rendering (static SSR)](xref:blazor/fundamentals/index#client-and-server-rendering-concepts) because the `<script>` tag can't be updated dynamically. Placing a `<script>` tag in a component file doesn't produce a compile-time warning or error, but script loading behavior might not match your expectations in components that adopt an interactive render mode.
Only place a `<script>` tag in a component file (`.razor`) if the component is guaranteed to adopt [static server-side rendering (static SSR)](xref:blazor/fundamentals/index#client-and-server-rendering-concepts) without [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). Placing a `<script>` tag in a component file doesn't produce a compile-time warning or error, but script loading behavior might not match your expectations in components that adopt an interactive render mode or static SSR with enhanced navigation.

:::moniker-end

Expand Down Expand Up @@ -88,7 +88,7 @@ Loading JS from the `<head>` isn't the best approach for the following reasons:

:::moniker range=">= aspnetcore-8.0"

In component markup, scripts can be loaded via a [`HeadContent` component](xref:blazor/components/control-head-content) with the usual caveat that the approach slows down page load on the client, which we recommend avoiding. When a script is loaded with a `HeadContent` component in a Blazor Server app, Blazor WebAssembly app, or a Blazor Web App using an interactive render mode (interactive SSR, CSR), navigating away from the component's page removes the `<script>` tag from the rendered `<head>` content but doesn't unload the script's JavaScript code, including event handlers that the script registers, exposed variables, and methods that the script provides. Only Blazor Web Apps using static SSR unload JavaScript code when the user navigates away from the page. Generally, you're better off adding `<script>` tags to the physical `<head>` content, unless you explicitly desire to keep such script references in the components that use them and don't mind that the code isn't unloaded on navigation events.
In component markup, scripts can be loaded via a [`HeadContent` component](xref:blazor/components/control-head-content) with the usual caveat that the approach slows down page load on the client, which we recommend avoiding. When a script is loaded with a `HeadContent` component in a Blazor Server app, Blazor WebAssembly app, or a Blazor Web App using either an interactive render mode (interactive SSR, CSR) or static SSR with enhanced navigation, navigating away from the component's page removes the `<script>` tag from the rendered `<head>` content but doesn't unload the script's JavaScript code, including event handlers that the script registers, exposed variables, and methods that the script provides. Only Blazor Web Apps using static SSR without enhanced navigation unload JavaScript code when the user navigates away from the page. Generally, you're better off adding `<script>` tags to the physical `<head>` content, unless you explicitly desire to keep such script references in the components that use them and don't mind that the code isn't unloaded on navigation events.

:::moniker-end

Expand Down
Loading
Loading