Here's a summary of what's new in ASP.NET Core in this release:
- Persistent component state support for enhanced navigation
- New ASP.NET Core Identity metrics
- Validation improvements for Minimal APIs and Blazor
- OpenAPI schema generation improvements
ASP.NET Core updates in .NET 10 Release Candidate 1:
.NET 10 Release Candidate 1:
Blazor now supports handling persistent component state when doing enhanced navigations. State persisted during an enhanced navigation can be read by interactive components on the page.
By default, persistent component state will only be loaded by interactive components when they are initially loaded on the page. This prevents important state, like data in an edited form, from being overwritten if additional enhanced navigations occur to the same page after the component was already loaded.
If the data is read-only and doesn't change frequently, you can opt-in to allow updates during enhanced navigation by setting AllowUpdates = true on the [PersistentState] attribute. This is useful for scenarios like displaying cached data that is expensive to fetch but doesn't change often:
[PersistentState(AllowUpdates = true)]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await ForecastService.GetForecastAsync();
}To skip restoring state during prerendering, set RestoreBehavior to SkipInitialValue:
// Skip restoration during prerendering
[PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)]
public string NoPrerenderedData { get; set; }To skip restoring state during reconnection, set RestoreBehavior to SkipLastSnapshot. This can be useful if you want to ensure fresh data after reconnection:
// Receive updates during enhanced navigation
[PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)]
public int CounterNotRestoredOnReconnect { get; set; }You can also call RegisterOnRestoring on the PersistentComponentState service to register a callback for imperatively controlling how state gets restored, which gives you full control of how state gets restored (similar to how RegisterOnPersisting gives you full control of how state gets persisted).
ASP.NET Core Identity now provides built-in metrics (counters, histograms, gauges) for key user and sign-in operations. These metrics let you monitor user management activities like creating users, changing passwords, and assigning roles. You can also track login attempts, sign-ins, sign-outs, and two-factor authentication usage.
The new metrics are in the Microsoft.AspNetCore.Identity meter:
aspnetcore.identity.user.create.durationaspnetcore.identity.user.update.durationaspnetcore.identity.user.delete.durationaspnetcore.identity.user.check_password_attemptsaspnetcore.identity.user.generated_tokensaspnetcore.identity.user.verify_token_attemptsaspnetcore.identity.sign_in.authenticate.durationaspnetcore.identity.sign_in.check_password_attemptsaspnetcore.identity.sign_in.sign_insaspnetcore.identity.sign_in.sign_outsaspnetcore.identity.sign_in.two_factor_clients_rememberedaspnetcore.identity.sign_in.two_factor_clients_forgotten
For more information about using metrics in ASP.NET Core, see ASP.NET Core metrics.
Several new features and fixes have been added to validation in Minimal APIs and Blazor. These updates improve compatibility and ensure consistent behavior with System.ComponentModel.DataAnnotations.Validator.
Validation attributes can now be applied directly to classes and records, not just to properties. This lets you enforce validation rules at the type level, making it easier to validate complex objects with custom logic.
[SumLimit(42)]
record Point(int X, int Y);
class SumLimitAttribute(int Limit) : ValidationAttribute
{
protected override ValidationResult? IsValid(object? value, ValidationContext _)
{
if (value is Point point && point.X + point.Y > Limit)
{
return new ValidationResult("The sum of X and Y is too high");
}
return ValidationResult.Success;
}
}The new [SkipValidation] attribute lets you exclude specific properties, parameters, or entire types from validation.
- Apply
[SkipValidation]to a property or parameter to skip its validation. - Apply
[SkipValidation]to a type to skip validation for all its properties and parameters.
This is helpful when you use the same model in scenarios where validation is needed and others where it is not.
class Order
{
public Address PaymentAddress { get; set; }
[SkipValidation]
public Address ContactAddress { get; set; }
// ...
}
class Address
{
[Required]
public string Street { get; set; }
// ...
}Additionally, properties annotated with the [JsonIgnore] attribute are now also omitted from validation to improve consistency between serialization and validation in the context of JSON models. Note that the [SkipValidation] attribute should be preferred in most cases.
Type validation logic now matches the behavior of System.ComponentModel.DataAnnotations.Validator:
- Member properties are validated, including recursively validating nested objects.
- Type-level attributes are validated.
- The
IValidatableObject.Validatemethod is executed.
If one of these steps produces a validation error, the remaining steps are skipped.
Several OpenAPI schema generation improvements have been made in .NET 10 RC1.
OpenAPI schema generation for nullable types was improved by using the oneOf pattern instead of the nullable property for complex types and collections. The implementation:
- Uses
oneOfwithnulland the actual type schema for nullable complex types in request/response schemas - Implements proper nullability detection for parameters, properties, and return types using reflection and NullabilityInfoContext
- Prunes null types from componentized schemas to avoid duplication
This release improves the handling of JSON schemas for OpenAPI document generation by properly resolving relative JSON schema references ($ref) in the root schema document.
Prior to .NET 10, ASP.NET Core discarded descriptions on properties that were defined with $ref in the generated OpenAPI document. This was necessary because OpenAPI v3.0 did not allow sibling properties alongside $ref in schema definitions. But this restriction has been relaxed in OpenAPI 3.1, allowing descriptions to be included alongside $ref. Support was added in RC1 to include property descriptions as siblings of $ref in the generated OpenAPI schema.
Thank you @desjoerd for this contribution!
Support has been added for processing XML comments on properties of [AsParameters] parameter classes to extract metadata for use in OpenAPI documentation generation.
OpenAPI schema generation now excludes unknown HTTP methods from the generated OpenAPI document. In particular, query methods, which are standard HTTP methods but not recognized by OpenAPI, are now gracefully excluded from the generated OpenAPI document.
Thank you @martincostello for this contribution!
The OpenAPI schema generation for JSON Patch operations now correctly applies the application/json-patch+json media type to request bodies that use JSON Patch. This ensures that the generated OpenAPI document accurately reflects the expected media type for JSON Patch operations. In addition, the JSON Patch request body has a detailed schema that describes the structure of the JSON Patch document, including the operations that can be performed.
Thank you @martincostello for this contribution!
OpenAPI document generation now uses invariant culture for formatting numbers and dates in the generated OpenAPI document. This ensures that the generated document is consistent and does not vary based on the server's culture settings.
Thank you @martincostello for this contribution!
Thank you contributors! ❤️