Skip to main content

aspnetcore-blazor10

Provides up-to-date information about ASP.NET Core 10 and Blazor .NET 10 new features. Use when the user asks about Blazor .NET 10 capabilities, ASP.NET Core 10 features, OpenAPI, Minimal APIs, SignalR, or needs guidance on ASP.NET Core/Blazor .NET 10 specific features.

Source facts

Repository
runceel/ai-dev-template
Last source activity
April 24, 2026 at 02:50
Detected SKILL.md language
English
Stars
11
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
aspnetcore-blazor10
description
Provides up-to-date information about ASP.NET Core 10 and Blazor .NET 10 new features. Use when the user asks about Blazor .NET 10 capabilities, ASP.NET Core 10 features, OpenAPI, Minimal APIs, SignalR, or needs guidance on ASP.NET Core/Blazor .NET 10 specific features.
# ASP.NET Core 10 / Blazor .NET 10 New Features Reference Source: https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-10.0 --- ## Blazor ### Blazor Component Coding Conventions 以下のルールに従ってコンポーネントを実装すること。 #### コードビハインド分離(`@code` ブロック禁止) `.razor` ファイルに `@code {}` ブロックを記述せず、C# コードは `.razor.cs` ファイルに分離する。コードビハインドクラスは `partial class` として定義する。 ```razor @* Counter.razor — マークアップのみ *@ @page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button @onclick="IncrementCount">Click me</button> ``` ```csharp // Counter.razor.cs public partial class Counter { private int currentCount; private void IncrementCount() { currentCount++; } } ``` #### DI はコンストラクターインジェクションを使用 `@inject` ディレクティブや `[Inject]` 属性ではなく、コンストラクターインジェクションを使用する。.NET 10 の Blazor コンポーネントではコンストラクターインジェクションがサポートされている。 ```csharp // MyComponent.razor.cs public partial class MyComponent(IMyService myService, NavigationManager navigationManager) { protected override async Task OnInitializedAsync() { var data = await myService.GetDataAsync(); } } ``` #### コンポーネント固有の CSS は `.razor.css` に分離 コンポーネントに固有のスタイルはコンポーネントと同名の `.razor.css` ファイルに定義する(CSS isolation)。 ```css /* Counter.razor.css */ h1 { color: #333; } button { background-color: #0078d4; color: white; } ``` --- ### QuickGrid Enhancements **`RowClass` parameter** — Apply a CSS class to a row based on row item: ```razor <QuickGrid Items="movies" RowClass="GetRowCssClass"> <PropertyColumn Property="@(m => m.Title)" /> </QuickGrid> @code { private string? GetRowCssClass(Movie item) => item.IsArchived ? "row-archived" : null; } ``` **`HideColumnOptionsAsync`** — Close column options UI programmatically: ```razor <QuickGrid @ref="grid" Items="items"> <PropertyColumn Property="@(m => m.Title)"> <ColumnOptions> <input @bind="filter" @bind:after="@(() => grid.HideColumnOptionsAsync())" /> </ColumnOptions> </PropertyColumn> </QuickGrid> ``` --- ### `[PersistentState]` — Declarative Prerendering State Persistence Before (.NET 9): ```razor @implements IDisposable @inject PersistentComponentState ApplicationState @code { public List<Movie>? MoviesList { get; set; } private PersistingComponentStateSubscription? sub; protected override async Task OnInitializedAsync() { if (!ApplicationState.TryTakeFromJson<List<Movie>>(nameof(MoviesList), out var movies)) MoviesList = await MovieService.GetMoviesAsync(); else MoviesList = movies; sub = ApplicationState.RegisterOnPersisting(() => { ApplicationState.PersistAsJson(nameof(MoviesList), MoviesList); return Task.CompletedTask; }); } public void Dispose() => sub?.Dispose(); } ``` After (.NET 10): ```razor @code { [PersistentState] public List<Movie>? MoviesList { get; set; } protected override async Task OnInitializedAsync() { MoviesList ??= await MovieService.GetMoviesAsync(); } } ``` **`AllowUpdates`** — opt-in to update state during enhanced navigation: ```csharp [PersistentState(AllowUpdates = true)] public WeatherForecast[]? Forecasts { get; set; } ``` **`RestoreBehavior`** options: ```csharp [PersistentState(RestoreBehavior = RestoreBehavior.SkipInitialValue)] public string NoPrerenderedData { get; set; } [PersistentState(RestoreBehavior = RestoreBehavior.SkipLastSnapshot)] public int CounterNotRestoredOnReconnect { get; set; } ``` **Custom serializer for persistent state:** ```csharp // Program.cs builder.Services.AddSingleton<PersistentComponentStateSerializer<TUser>, CustomUserSerializer>(); ``` --- ### Improved Form Validation Validates nested objects and collection items. Uses source generator (AOT-compatible) instead of reflection. **Setup:** ```csharp // Program.cs builder.Services.AddValidation(); ``` **Model** (must be a `.cs` file, not inline in `.razor`): ```csharp [ValidatableType] // required on root type only public class Order { public Customer Customer { get; set; } = new(); public List<OrderItem> OrderItems { get; set; } = []; } public class Customer { [Required(ErrorMessage = "Name is required.")] public string? FullName { get; set; } [Required(ErrorMessage = "Email is required.")] [EmailAddress] public string? Email { get; set; } } ``` **Component** — uses `DataAnnotationsValidator` as before: ```razor <EditForm Model="Model"> <DataAnnotationsValidator /> <InputText @bind-Value="Model!.Customer.FullName" /> <ValidationMessage For="@(() => Model!.Customer.FullName)" /> </EditForm> ``` **Validation rules** (all applied in order; short-circuits on first error): 1. Member property attributes (including nested objects) 2. Type-level attributes 3. `IValidatableObject.Validate` `[SkipValidation]` to exclude specific properties or types from validation. --- ### New JavaScript Interop APIs **Create a JS object instance:** ```csharp // Async var objRef = await JSRuntime.InvokeConstructorAsync("MyLib.MyClass", arg1, arg2); var value = await objRef.GetValueAsync<string>("propertyName"); await objRef.SetValueAsync("propertyName", newValue); // Sync (in-process) var inProc = (IJSInProcessRuntime)JSRuntime; var objRef = inProc.InvokeConstructor("MyLib.MyClass", arg1); var value = objRef.GetValue<string>("propertyName"); inProc.SetValue("propertyName", newValue); ``` **Read/write JS object properties:** ```csharp // Read var num = await JSRuntime.GetValueAsync<int>("myLib.config.retryCount"); // Write await JSRuntime.SetValueAsync("myLib.config.retryCount", 5); ``` --- ### Not Found Handling **`Router.NotFoundPage` parameter** — specify a page for 404: ```razor <Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)"> <Found Context="routeData"> <RouteView RouteData="@routeData" /> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <!-- <NotFound> is ignored when NotFoundPage is defined --> </Router> ``` **`NavigationManager.NotFound()`** — trigger Not Found programmatically: ```csharp @inject NavigationManager Nav protected override async Task OnInitializedAsync() { var item = await Service.GetItemAsync(Id); if (item is null) Nav.NotFound(); } ``` Behavior: - Static SSR: sets HTTP 404 - Interactive rendering: renders the `NotFoundPage` - Streaming rendering: renders `NotFoundPage` via enhanced navigation Subscribe to notifications: `NavigationManager.OnNotFound`. --- ### Passkey (WebAuthn/FIDO2) Support for ASP.NET Core Identity Password-less login using biometrics or security keys. Built into the Blazor Web App project template. ```csharp // Program.cs — already included in the new project template builder.Services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); ``` See: https://learn.microsoft.com/aspnet/core/security/authentication/passkeys --- ### Circuit State Persistence Server-side Blazor (SignalR) sessions survive connection loss without losing unsaved work: - Browser tab throttling - Mobile app switching - Network interruptions - Proactive pausing of inactive circuits - Enhanced navigation See: https://learn.microsoft.com/aspnet/core/blazor/state-management/server --- ### Hot Reload for Blazor WebAssembly ```xml <!-- Enabled by default for Debug configuration --> <WasmEnableHotReload>true</WasmEnableHotReload> ``` --- ### Navigation Changes - **`NavigateTo` same-page**: No longer scrolls to top (viewport preserved on query string / fragment changes) - **`NavLink` with `NavLinkMatch.All`**: Ignores query string and fragment — link stays `active` on path match Revert: set `AppContext` switch `Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragment` to `true` Override matching: ```csharp public class CustomNavLink : NavLink { protected override bool ShouldMatch(string currentUriAbsolute) { ... } } ``` --- ### Disable `NavigationException` during Static SSR ```xml <!-- Program.cs template sets this to true by default in .NET 10 --> <BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException> ``` With this set, `NavigationManager.NavigateTo` during static SSR no longer throws `NavigationException`. Code after `NavigateTo` executes before the redirect occurs. --- ### Reconnection UI (`ReconnectModal`) Template now includes a `ReconnectModal` component with collocated CSS/JS. CSP-compliant (no inline styles). New event: `components-reconnect-state-changed` New state: `"retrying"` (in addition to existing states) --- ### `OwningComponentBase` implements `IAsyncDisposable` ```csharp // DisposeAsync and DisposeAsyncCore now available public class MyComponent : OwningComponentBase { // async cleanup supported } ``` --- ### New `InputHidden` Component ```razor <EditForm Model="Parameter" OnValidSubmit="Submit" FormName="Example"> <InputHidden id="hidden" @bind-Value="Parameter" /> <button type="submit">Submit</button> </EditForm> @code { [SupplyParameterFromForm] public string Parameter { get; set; } = "stranger"; private void Submit() { } } ``` --- ### Client-Side Fingerprinting (Standalone Blazor WebAssembly) ```xml <!-- .csproj --> <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders> ``` ```html <!-- wwwroot/index.html --> <head> <script type="importmap"></script> </head> <body> <script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script> </body> ``` Fingerprint JS modules: ```html <script type="module" src="js/scripts#[.{fingerprint}].js"></script> ``` ```xml <ItemGroup> <StaticWebAssetFingerprintPattern Include="JSModule" Pattern="*.js" Expression="#[.{fingerprint}]!" /> </ItemGroup> ``` --- ### WebAssembly Environment Configuration ```xml <!-- No longer uses launchSettings.json --> <WasmApplicationEnvironmentName>Staging</WasmApplicationEnvironmentName> ``` Defaults: `Development` (build), `Production` (publish). --- ### `HttpClient` Response Streaming Enabled by Default `response.Content.ReadAsStreamAsync()` now returns `BrowserHttpReadStream` (not `MemoryStream`). Synchronous `Stream.Read` is not supported. Opt out globally: ```xml <WasmEnableStreamingResponse>false</WasmEnableStreamingResponse> ``` Opt out per request: ```csharp requestMessage.SetBrowserResponseStreamingEnabled(false); ``` --- ### Static Asset Preloading **Blazor Web Apps** — use `<ResourcePreloader />` component: ```razor <!-- App.razor --> <head> <base href="/" /> <ResourcePreloader /> </head> ``` **Standalone Blazor WebAssembly** — add `<link rel="preload" id="webassembly" />` in `wwwroot/index.html` (requires `OverrideHtmlAssetPlaceholders`). --- ### Blazor Script as Static Web Asset
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub