diff --git a/.github/workflows/whats-new.yml b/.github/workflows/whats-new.yml deleted file mode 100644 index 509286ea3748..000000000000 --- a/.github/workflows/whats-new.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: 'generate what''s new article' - -# Controls when the action will run. -on: - # Triggers the workflow on push or pull request events but only for the default branch - schedule: - - cron: '0 0 1 * *' # The first of every month - workflow_dispatch: - inputs: - reason: - description: 'The reason for running the workflow' - required: true - default: 'Manual run' - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "create-what-is-new" - create-what-is-new: - # The type of runner that the job will run on - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - id-token: write - if: ${{ github.repository_owner == 'dotnet' }} - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c - - - name: "Print manual run reason" - if: github.event_name == 'workflow_dispatch' - run: | - echo "Reason: ${{ github.event.inputs.reason }}" - - - name: Azure OpenID Connect - id: azure-oidc-auth - uses: dotnet/docs-tools/.github/actions/oidc-auth-flow@main - with: - client-id: ${{ secrets.CLIENT_ID }} - tenant-id: ${{ secrets.TENANT_ID }} - audience: ${{ secrets.OSMP_API_AUDIENCE }} - - - uses: dotnet/docs-tools/WhatsNew.Cli@main - env: - GitHubKey: ${{ secrets.GITHUB_TOKEN }} - AZURE_ACCESS_TOKEN: ${{ steps.azure-oidc-auth.outputs.access-token }} - with: - owner: dotnet - repo: AspNetCore.Docs - savedir: './aspnetcore/whats-new' - - - name: create-pull-request - uses: dotnet/actions-create-pull-request@v4 - with: - branch: create-whatsnew-pull-request/patch - title: "What's new article" - commit-message: 'Bot 🤖 generated "What''s new article"' - body: "Automated creation of What's new article." diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 893a0ffe37df..449e5179adec 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1386,27 +1386,33 @@ }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-03-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod5" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-04-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod0" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-07-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod1" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-08-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod2" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-09-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod3" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-2022-10-01.md", - "redirect_url": "/aspnet/whats-new/dotnet-AspNetCore.Docs-mod4" + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false }, { "source_path": "aspnetcore/blazor/security/webassembly/hosted-with-azure-active-directory.md", @@ -1582,6 +1588,46 @@ "source_path": "aspnetcore/introduction-to-aspnet-core.md", "redirect_url": "/aspnet/core/overview", "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/index.yml", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod0.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod1.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod2.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod3.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod4.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod5.md", + "redirect_url": "/aspnet/core/release-notes/aspnetcore-10.0", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/blazor/state-management.md", + "redirect_url": "/aspnet/core/state-management/", + "redirect_document_id": false } ] } diff --git a/.whatsnew.json b/.whatsnew.json index 328938e5682b..38797cc57a50 100644 --- a/.whatsnew.json +++ b/.whatsnew.json @@ -8,9 +8,9 @@ "navigationOptions": { "maximumNumberOfArticles": 6, "tocParentNode": "What's new", - "repoTocFolder": "aspnetcore/whats-new", + "repoTocFolder": "/dev/null", "indexParentNode": "Find ASP.NET Core docs updates", - "repoIndexFolder": "aspnetcore/whats-new" + "repoIndexFolder": "/dev/null" }, "inclusionCriteria": { "minAdditionsToFile": 3 diff --git a/aspnetcore/blazor/blazor-ef-core.md b/aspnetcore/blazor/blazor-ef-core.md index 44fb1cd887e9..250789ea3aa9 100644 --- a/aspnetcore/blazor/blazor-ef-core.md +++ b/aspnetcore/blazor/blazor-ef-core.md @@ -229,17 +229,20 @@ public void Dispose() => Context?.Dispose(); includes application data in exception messages and framework logging. The logged data can include the values assigned to properties of entity instances and parameter values for commands sent to the database. Logging data with is a **security risk**, as it may expose passwords and other [Personally Identifiable Information (PII)](xref:blazor/security/index#personally-identifiable-information-pii) when it logs SQL statements executed against the database. -We recommend only enabling for development and testing: +We recommend only enabling for local development and testing: ```csharp -#if DEBUG +if (builder.Environment.IsDevelopment()) +{ services.AddDbContextFactory(opt => opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db") .EnableSensitiveDataLogging()); -#else +} +else +{ services.AddDbContextFactory(opt => opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")); -#endif +} ``` ## Additional resources diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index 2c4e4cf3cb21..decb4d76ff88 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -587,7 +587,7 @@ When using the interactive WebAssembly and Auto render modes, components are pre * The client version calls the web API with a preconfigured . * The server version can typically access the server-side resources directly. Injecting an on the server that makes calls back to the server isn't recommended, as the network request is typically unnecessary. Alternatively, the API might be external to the server project, but a service abstraction for the server is required to transform the request in some way, for example to add an access token to a proxied request. -When using the WebAssembly render mode, you also have the option of disabling prerendering, so the components only render from the client. For more information, see . +When using the WebAssembly render mode, you also have the option of disabling prerendering, so the components only render from the client. For more information, see . Examples ([sample apps](#sample-apps)): @@ -615,25 +615,29 @@ Use ***either*** of the following approaches: Example: Todo list web API in the `BlazorWebAppCallWebApi` [sample app](#sample-apps) -* If prerendering isn't required for a WebAssembly component that calls the web API, disable prerendering by following the guidance in . If you adopt this approach, you don't need to add services to the main project of the Blazor Web App because the component isn't prerendered on the server. +* If prerendering isn't required for a WebAssembly component that calls the web API, disable prerendering by following the guidance in . If you adopt this approach, you don't need to add services to the main project of the Blazor Web App because the component isn't prerendered on the server. -For more information, see [Client-side services fail to resolve during prerendering](xref:blazor/components/render-modes#client-side-services-fail-to-resolve-during-prerendering). +For more information, see the [Client-side services fail to resolve during prerendering](xref:blazor/components/prerender#client-side-services-fail-to-resolve-during-prerendering) section of the *Prerendering* article. ## Prerendered data When prerendering, components render twice: first statically, then interactively. State doesn't automatically flow from the prerendered component to the interactive one. If a component performs asynchronous initialization operations and renders different content for different states during initialization, such as a "Loading..." progress indicator, you may see a flicker when the component renders twice. - -You can address this by flowing prerendered state using the Persistent Component State API, which the `BlazorWebAppCallWebApi` and `BlazorWebAppCallWebApi_Weather` [sample apps](#sample-apps) demonstrate. When the component renders interactively, it can render the same way using the same state. However, the API doesn't currently work with enhanced navigation, which you can work around by disabling enhanced navigation on links to the page (`data-enhanced-nav=false`). For more information, see the following resources: - -* +* * -* [Support persistent component state across enhanced page navigations (`dotnet/aspnetcore` #51584)](https://github.com/dotnet/aspnetcore/issues/51584) :::moniker-end diff --git a/aspnetcore/blazor/components/cascading-values-and-parameters.md b/aspnetcore/blazor/components/cascading-values-and-parameters.md index 0874e2f1fd7f..15e71f36fe31 100644 --- a/aspnetcore/blazor/components/cascading-values-and-parameters.md +++ b/aspnetcore/blazor/components/cascading-values-and-parameters.md @@ -290,7 +290,7 @@ Add a navigation link to the `DaleksMain` component in `NavMenu.razor`: ``` -Because the 's type in this example (`NotifyingDalek`) is a class type, you can meet virtually any state management feature specification requirement. However, subscriptions create overhead and reduce performance, so benchmark the performance of this approach in your app and compare it to other [state management approaches](xref:blazor/state-management) before adopting it in a production app with constrained processing and memory resources. +Because the 's type in this example (`NotifyingDalek`) is a class type, you can meet virtually any state management feature specification requirement. However, subscriptions create overhead and reduce performance, so benchmark the performance of this approach in your app and compare it to other [state management approaches](xref:blazor/state-management/index) before adopting it in a production app with constrained processing and memory resources. Any change in state (any property value change of the class) causes all subscribed components to rerender, regardless of which part of the state they use. **Avoid creating a single large class representing the entire global application state.** Instead, create granular classes and cascade them separately with specific subscriptions to cascading parameters, ensuring that only components subscribed to a specific portion of the application state are affected by changes. @@ -517,7 +517,7 @@ Cascading parameters don't pass data across render mode boundaries: * State crossing the boundary between static and interactive rendering must be serializable. Components are arbitrary objects that reference a vast chain of other objects, including the renderer, the DI container, and every DI service instance. You must explicitly cause state to be serialized from static SSR to make it available in subsequent interactively-rendered components. Two approaches are adopted: * Via the Blazor framework, parameters passed across a static SSR to interactive rendering boundary are serialized automatically if they're JSON-serializable, or an error is thrown. - * State stored in [`PersistentComponentState`](xref:blazor/components/prerender#persist-prerendered-state) is serialized and recovered automatically if it's JSON-serializable, or an error is thrown. + * State stored in [Persistent Component State](xref:blazor/state-management/prerendered-state-persistence) is serialized and recovered automatically if it's JSON-serializable, or an error is thrown. Cascading parameters aren't JSON-serializable because the typical usage patterns for cascading parameters are somewhat like DI services. There are often platform-specific variants of cascading parameters, so it would be unhelpful to developers if the framework stopped developers from having server-interactive-specific versions or WebAssembly-specific versions. Also, many cascading parameter values in general aren't serializable, so it would be impractical to update existing apps if you had to stop using all nonserializable cascading parameter values. @@ -718,4 +718,4 @@ The following `ExampleTabSet` component uses the `TabSet` component, which conta ## Additional resources * [Generic type support: Explicit generic types based on ancestor components](xref:blazor/components/generic-type-support#explicit-generic-types-based-on-ancestor-components) -* [State management: Factor out state preservation to a common provider](xref:blazor/state-management?pivots=server#factor-out-state-preservation-to-a-common-provider) +* [State management: Protected browser storage: Factor out state preservation to a common provider](xref:blazor/state-management/protected-browser-storage#factor-out-state-preservation-to-a-common-provider) diff --git a/aspnetcore/blazor/components/data-binding.md b/aspnetcore/blazor/components/data-binding.md index c6406458ebe6..edbe3df22122 100644 --- a/aspnetcore/blazor/components/data-binding.md +++ b/aspnetcore/blazor/components/data-binding.md @@ -1043,7 +1043,7 @@ Prior to the release of .NET 7, two-way binding across components uses `get`/`se :::moniker-end -For an alternative approach suited to sharing data in memory and across components that aren't necessarily nested, see . +For an alternative approach suited to sharing data in memory and across components that aren't necessarily nested, see . ## Bound field or property expression tree diff --git a/aspnetcore/blazor/components/integration-hosted-webassembly.md b/aspnetcore/blazor/components/integration-hosted-webassembly.md index cfcbbea3c6db..256aaf5a200b 100644 --- a/aspnetcore/blazor/components/integration-hosted-webassembly.md +++ b/aspnetcore/blazor/components/integration-hosted-webassembly.md @@ -549,7 +549,6 @@ The persisted prerendered state is transferred to the client, where it's used to ## Additional Blazor WebAssembly resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) * [Prerendering support with assembly lazy loading](xref:blazor/webassembly-lazy-load-assemblies#lazy-load-assemblies-in-a-hosted-blazor-webassembly-solution) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) @@ -1064,7 +1063,6 @@ The persisted prerendered state is transferred to the client, where it's used to ## Additional Blazor WebAssembly resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) * [Prerendering support with assembly lazy loading](xref:blazor/webassembly-lazy-load-assemblies#lazy-load-assemblies-in-a-hosted-blazor-webassembly-solution) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) @@ -1322,7 +1320,6 @@ Additional work might be required depending on the static resources that compone ## Additional Blazor WebAssembly resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) * [Prerendering support with assembly lazy loading](xref:blazor/webassembly-lazy-load-assemblies#lazy-load-assemblies-in-a-hosted-blazor-webassembly-solution) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) diff --git a/aspnetcore/blazor/components/integration.md b/aspnetcore/blazor/components/integration.md index 55f43d353ff1..72c0a53eb978 100644 --- a/aspnetcore/blazor/components/integration.md +++ b/aspnetcore/blazor/components/integration.md @@ -635,7 +635,7 @@ To resolve the problem, use ***either*** of the following approaches: ## Additional Blazor Server resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) +* [State management: Protected browser storage: Handle prerendering](xref:blazor/state-management/protected-browser-storage#handle-prerendering) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) * [After component render (`OnAfterRender{Async}`)](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync) @@ -1154,7 +1154,7 @@ To resolve the problem, use ***either*** of the following approaches: ## Additional Blazor Server resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) +* [State management: Protected browser storage: Handle prerendering](xref:blazor/state-management/protected-browser-storage#handle-prerendering) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) * [After component render (`OnAfterRender{Async}`)](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync) @@ -1586,7 +1586,7 @@ To resolve the problem, use ***either*** of the following approaches: ## Additional Blazor Server resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) +* [State management: Protected browser storage: Handle prerendering](xref:blazor/state-management/protected-browser-storage#handle-prerendering) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) * [After component render (`OnAfterRender{Async}`)](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync) @@ -2016,7 +2016,7 @@ To resolve the problem, use ***either*** of the following approaches: ## Additional Blazor Server resources -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering) +* [State management: Protected browser storage: Handle prerendering](xref:blazor/state-management/protected-browser-storage#handle-prerendering) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) * [After component render (`OnAfterRender{Async}`)](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync) diff --git a/aspnetcore/blazor/components/lifecycle.md b/aspnetcore/blazor/components/lifecycle.md index 470a0503f4d1..d88af2350852 100644 --- a/aspnetcore/blazor/components/lifecycle.md +++ b/aspnetcore/blazor/components/lifecycle.md @@ -206,7 +206,7 @@ Blazor apps that prerender their content on the server call from running twice when prerendering, see the [Stateful reconnection after prerendering](#stateful-reconnection-after-prerendering) section. The content in the section focuses on Blazor Web Apps and stateful SignalR *reconnection*. To preserve state during the execution of initialization code while prerendering, see . +To prevent developer code in from running twice when prerendering, see the [Stateful reconnection after prerendering](#stateful-reconnection-after-prerendering) section. The content in the section focuses on Blazor Web Apps and stateful SignalR *reconnection*. To preserve state during the execution of initialization code while prerendering, see . :::moniker-end @@ -722,7 +722,7 @@ By combining streaming rendering with persistent component state: For more information, see the following resources: * -* . +* . :::moniker-end @@ -795,7 +795,7 @@ For more information on the . +The content in this section focuses on Blazor Web Apps and stateful SignalR *reconnection*. To preserve state during the execution of initialization code while prerendering, see . :::moniker-end diff --git a/aspnetcore/blazor/components/prerender.md b/aspnetcore/blazor/components/prerender.md index dbd31cbf94d4..22d215cbbd64 100644 --- a/aspnetcore/blazor/components/prerender.md +++ b/aspnetcore/blazor/components/prerender.md @@ -5,7 +5,7 @@ description: Learn about Razor component prerendering in ASP.NET Core Blazor app monikerRange: '>= aspnetcore-8.0' ms.author: wpickett ms.custom: mvc -ms.date: 11/12/2024 +ms.date: 08/05/2025 uid: blazor/components/prerender --- # Prerender ASP.NET Core Razor components @@ -17,357 +17,157 @@ uid: blazor/components/prerender at the ends of lines to generate a bare return in block quote output. --> -This article explains Razor component prerendering scenarios for server-rendered components in Blazor Web Apps. +This article explains Razor component prerendering scenarios for server-rendered components in Blazor Web Apps and Blazor Server apps. -*Prerendering* is the process of initially rendering page content on the server without enabling event handlers for rendered controls. The server outputs the HTML UI of the page as soon as possible in response to the initial request, which makes the app feel more responsive to users. Prerendering can also improve [Search Engine Optimization (SEO)](https://developer.mozilla.org/docs/Glossary/SEO) by rendering content for the initial HTTP response that search engines use to calculate page rank. +*Prerendering* is the process of statically rendering page content from the server to deliver HTML to the browser as quickly as possible. After the prerendered content is quickly displayed to the user, interactive content with active event handlers are rendered, replacing any content that was rendered previously. Prerendering can also improve [Search Engine Optimization (SEO)](https://developer.mozilla.org/docs/Glossary/SEO) by rendering content for the initial HTTP response that search engines use to calculate page rank. -## Persist prerendered state - -Without persisting prerendered state, state used during prerendering is lost and must be recreated when the app is fully loaded. If any state is created asynchronously, the UI may flicker as the prerendered UI is replaced when the component is rerendered. +:::moniker range=">= aspnetcore-8.0" -Consider the following `PrerenderedCounter1` counter component. The component sets an initial random counter value during prerendering in [`OnInitialized` lifecycle method](xref:blazor/components/lifecycle#component-initialization-oninitializedasync). After the SignalR connection to the client is established, the component rerenders, and the initial count value is replaced when `OnInitialized` executes a second time. +Prerendering is enabled by default for interactive components. -`PrerenderedCounter1.razor`: +Internal navigation for interactive routing doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests, including for [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). For more information, see [Static versus interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing), [Interactive routing and prerendering](xref:blazor/state-management/prerendered-state-persistence#interactive-routing-and-prerendering), and [Enhanced navigation and form handling](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). -:::code language="razor" source="~/../blazor-samples/8.0/BlazorSample_BlazorWebApp/Components/Pages/PrerenderedCounter1.razor"::: +[`OnAfterRender{Async}` component lifecycle events](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync) aren't called when prerendering, only after the component renders interactively. -Run the app and inspect logging from the component. The following is example output. +## Disable prerendering -> [!NOTE] -> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter1` component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. + -To retain the initial value of the counter during prerendering, Blazor supports persisting state in a prerendered page using the service (and for components embedded into pages or views of Razor Pages or MVC apps, the [Persist Component State Tag Helper](xref:mvc/views/tag-helpers/builtin-th/persist-component-state-tag-helper)). +Prerendering can complicate an app because the app's Razor components must render twice: once for prerendering and once for setting up interactivity. If the components are set up to run on WebAssembly, then you also must design your components so that they can run from both the server and the client. -:::moniker range=">= aspnetcore-10.0" +To disable prerendering for a *component instance*, pass the `prerender` flag with a value of `false` to the render mode: - +* `<... @rendermode="new InteractiveServerRenderMode(prerender: false)" />` +* `<... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />` +* `<... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />` -To preserve prerendered state, use the `[SupplyParameterFromPersistentComponentState]` attribute to persist state in properties. Properties with this attribute are automatically persisted using the service during prerendering. The state is retrieved when the component renders interactively or the service is instantiated. +To disable prerendering in a *component definition*: -By default, properties are serialized using the serializer with default settings. Serialization isn't trimmer safe and requires preservation of the types used. For more information, see . +* `@rendermode @(new InteractiveServerRenderMode(prerender: false))` +* `@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))` +* `@rendermode @(new InteractiveAutoRenderMode(prerender: false))` -The following counter component persists counter state during prerendering and retrieves the state to initialize the component: +To disable prerendering for the entire app, indicate the render mode at the highest-level interactive component in the app's component hierarchy that isn't a root component. -* The `[SupplyParameterFromPersistentComponentState]` attribute is applied to the `CounterState` type (`State`). -* The counter's state is assigned when `null` in `OnInitialized` and restored automatically when the component renders interactively. - -`PrerenderedCounter2.razor`: +For apps based on the Blazor Web App project template, a render mode assigned to the entire app is specified where the `Routes` component is used in the `App` component (`Components/App.razor`). The following example sets the app's render mode to Interactive Server with prerendering disabled: ```razor -@page "/prerendered-counter-2" -@inject ILogger Logger - -Prerendered Counter 2 - -

Prerendered Counter 2

- -

Current count: @State?.CurrentCount

- - - -@code { - [SupplyParameterFromPersistentComponentState] - public CounterState? State { get; set; } - - protected override void OnInitialized() - { - if (State is null) - { - State = new() { CurrentCount = Random.Shared.Next(100) }; - Logger.LogInformation("CurrentCount set to {Count}", - State.CurrentCount); - } - else - { - Logger.LogInformation("CurrentCount restored to {Count}", - State.CurrentCount); - } - } - - private void IncrementCount() - { - if (State is not null) - { - State.CurrentCount++; - } - } - - public class CounterState - { - public int CurrentCount { get; set; } - } -} + ``` - - -When the component executes, `CurrentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. - -> [!NOTE] -> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. - -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: -> :::no-loc text=" CurrentCount set to 96"::: -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: -> :::no-loc text=" CurrentCount restored to 96"::: -In the following example that serializes state for multiple components of the same type: +Making a root component, such as the `App` component, interactive with the `@rendermode` directive at the top of the root component's definition file (`.razor`) isn't supported. Therefore, prerendering can't be disabled directly by the `App` component. -* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized and deserialized during prerendering. -* The [`@key` directive attribute](xref:blazor/components/key#use-of-the-key-directive-attribute) is used to ensure that the state is correctly associated with the component instance. -* The `Element` property is initialized in the [`OnInitialized` lifecycle method](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) to avoid null reference exceptions, similarly to how null references are avoided for query parameters and form data. +Disabling prerendering using the preceding techniques only takes effect for top-level render modes. If a parent component specifies a render mode, the prerendering settings of its children are ignored. -`PersistentChild.razor`: +:::moniker-end -```razor -
-

Current count: @Element.CurrentCount

- -
+## Persist prerendered state -@code { - [SupplyParameterFromPersistentComponentState] - public State Element { get; set; } +Without persisting prerendered state, state used during prerendering is lost and must be recreated when the app is fully loaded. If any state is created asynchronously, the UI may flicker as the prerendered UI is replaced when the component is rerendered. For guidance on how to persist state during prerendering, see . - protected override void OnInitialized() - { - Element ??= new State(); - } +:::moniker range=">= aspnetcore-8.0" - private void IncrementCount() - { - Element.CurrentCount++; - } +## Client-side services fail to resolve during prerendering - private class State - { - public int CurrentCount { get; set; } - } -} -``` +Assuming that prerendering isn't disabled for a component or for the app, a component in the `.Client` project is prerendered on the server. Because the server doesn't have access to registered client-side Blazor services, it isn't possible to inject these services into a component without receiving an error that the service can't be found during prerendering. -`Parent.razor`: +For example, consider the following `Home` component in the `.Client` project in a Blazor Web App with [global Interactive WebAssembly or Interactive Auto rendering](xref:blazor/components/render-modes#apply-a-render-mode-to-the-entire-app). The component attempts to inject to obtain the environment's name. ```razor -@page "/parent" - -@foreach (var element in elements) -{ - -} -``` - -In the following example that serializes state for a dependency injection service: - -* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized during prerendering and deserialized when the app becomes interactive. -* The extension method is used to register the service for persistence. The render mode is required because the render mode can't be inferred from the service type. Use any of the following values: - * `RenderMode.Server`: The service is available for the Interactive Server render mode. - * `RenderMode.Webassembly`: The service is available for the Interactive Webassembly render mode. - * `RenderMode.InteractiveAuto`: The service is available for both the Interactive Server and Interactive Webassembly render modes if a component renders in either of those modes. -* The service is resolved during the initialization of an interactive render mode, and the properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are deserialized. - -> [!NOTE] -> Only persisting scoped services is supported. - - - -`CounterService.cs`: - -```csharp -public class CounterService -{ - [SupplyParameterFromPersistentComponentState] - public int CurrentCount { get; set; } +@page "/" +@inject IWebAssemblyHostEnvironment Environment - public void IncrementCount() - { - CurrentCount++; - } -} -``` +Home -In `Program.cs`: +

Home

-```csharp -builder.Services.RegisterPersistentService( - RenderMode.InteractiveAuto); +

+ Environment: @Environment.Environment +

``` -Serialized properties are identified from the actual service instance: - -* This approach allows marking an abstraction as a persistent service. -* Enables actual implementations to be internal or different types. -* Supports shared code in different assemblies. -* Results in each instance exposing the same properties. +No compile time error occurs, but a runtime error occurs during prerendering: -As an alternative to using the declarative model for persisting state with the `[SupplyParameterFromPersistentComponentState]` attribute, you can use the service directly, which offers greater flexibility for complex state persistence scenarios. Call to register a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown. +> :::no-loc text="Cannot provide a value for property 'Environment' on type 'BlazorSample.Client.Pages.Home'. There is no registered service of type 'Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment'."::: -The following counter component example persists counter state during prerendering and retrieves the state to initialize the component. +This error occurs because the component must compile and execute on the server during prerendering, but isn't a registered service on the server. -`PrerenderedCounter3.razor`: +If the app doesn't require the value during prerendering, this problem can be solved by injecting to obtain the service instead of the service type itself: ```razor -@page "/prerendered-counter-3" -@implements IDisposable -@inject ILogger Logger -@inject PersistentComponentState ApplicationState +@page "/" +@using Microsoft.AspNetCore.Components.WebAssembly.Hosting +@inject IServiceProvider Services -Prerendered Counter 3 +Home -

Prerendered Counter 3

+

Home

-

Current count: @currentCount

- - +

+ Environment: @environmentName +

@code { - private int currentCount; - private PersistingComponentStateSubscription persistingSubscription; + private string? environmentName; protected override void OnInitialized() { - if (!ApplicationState.TryTakeFromJson( - nameof(currentCount), out var restoredCount)) - { - currentCount = Random.Shared.Next(100); - Logger.LogInformation("currentCount set to {Count}", currentCount); - } - else + if (Services.GetService() is { } env) { - currentCount = restoredCount!; - Logger.LogInformation("currentCount restored to {Count}", currentCount); + environmentName = env.Environment; } - - // Call at the end to avoid a potential race condition at app shutdown - persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount); - } - - private Task PersistCount() - { - ApplicationState.PersistAsJson(nameof(currentCount), currentCount); - - return Task.CompletedTask; } - - private void IncrementCount() => currentCount++; - - void IDisposable.Dispose() => persistingSubscription.Dispose(); } ``` -When the component executes, `currentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. - -> [!NOTE] -> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. - -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter3[0]"::: -> :::no-loc text=" currentCount set to 96"::: -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter3[0]"::: -> :::no-loc text=" currentCount restored to 96"::: - -:::moniker-end - -:::moniker range="< aspnetcore-10.0" - -To preserve prerendered state, decide what state to persist using the service. registers a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown. - -The following counter component example persists counter state during prerendering and retrieves the state to initialize the component. - -`PrerenderedCounter2.razor`: - -:::code language="razor" source="~/../blazor-samples/8.0/BlazorSample_BlazorWebApp/Components/Pages/PrerenderedCounter2.razor"::: - -When the component executes, `currentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. - -> [!NOTE] -> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. +If you merely want to make the service injection optional, you can use constructor injection: -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: -> :::no-loc text=" currentCount set to 96"::: -> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: -> :::no-loc text=" currentCount restored to 96"::: - -:::moniker-end - -By initializing components with the same state used during prerendering, any expensive initialization steps are only executed once. The rendered UI also matches the prerendered UI, so no flicker occurs in the browser. - -The persisted prerendered state is transferred to the client, where it's used to restore the component state. During client-side rendering (CSR, `InteractiveWebAssembly`), the data is exposed to the browser and must not contain sensitive, private information. During interactive server-side rendering (interactive SSR, `InteractiveServer`), [ASP.NET Core Data Protection](xref:security/data-protection/introduction) ensures that the data is transferred securely. The `InteractiveAuto` render mode combines WebAssembly and Server interactivity, so it's necessary to consider data exposure to the browser, as in the CSR case. - -## Components embedded into pages and views (Razor Pages/MVC) +```csharp +private string? environmentName; -For components embedded into a page or view of a Razor Pages or MVC app, you must add the [Persist Component State Tag Helper](xref:mvc/views/tag-helpers/builtin-th/persist-component-state-tag-helper) with the `` HTML tag inside the closing `` tag of the app's layout. **This is only required for Razor Pages and MVC apps.** For more information, see . +public Home(IWebAssemblyHostEnvironment? env = null) +{ + environmentName = env?.Environment; +} +``` -`Pages/Shared/_Layout.cshtml`: +Another option for obtaining the environment whether the code is running on the server or on the client is to inject from the [`Microsoft.Extensions.Hosting.Abstractions` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Hosting.Abstractions). Add a package reference to the app and use the following approach: -```cshtml - - ... +```csharp +private string? environmentName; - - +public Home(IHostEnvironment? serverEnvironment = null, + IWebAssemblyHostEnvironment? wasmEnvironment = null) +{ + environmentName = serverEnvironment?.EnvironmentName; + environmentName ??= wasmEnvironment?.Environment; +} ``` -## Interactive routing and prerendering - -When the `Routes` component doesn't define a render mode, the app is using per-page/component interactivity and navigation. Using per-page/component navigation, internal† navigation is handled by [enhanced routing](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) after the app becomes interactive. †*Internal* in this context means that the URL destination of the navigation event is a Blazor endpoint inside the app. +You can also avoid the problem if you [disable prerendering](#disable-prerendering) for the component, but that's an extreme measure to take in many cases that may not meet your component's specifications. -The service only works on the initial page load and not across internal enhanced page navigation events. +There are a four approaches that you can take to address this scenario for prerendering. The following are listed from most recommended to least recommended: -If the app performs a full (non-enhanced) navigation to a page utilizing persistent component state, the persisted state is made available for the app to use when it becomes interactive. +* For shared framework services that merely aren't registered server-side in the main project, register the services in the main project, which makes them available during prerendering. For an example of this scenario, see the guidance for services in the [Blazor Web App external web APIs](xref:blazor/call-web-api#blazor-web-app-external-web-apis) section of the *Call web API* article. -If an interactive circuit has already been established and an enhanced navigation is performed to a page utilizing persistent component state, the state *isn't made available in the existing circuit for the component to use*. There's no prerendering for the internal page request, and the service isn't aware that an enhanced navigation has occurred. There's no mechanism to deliver state updates to components that are already running on an existing circuit. The reason for this is that Blazor only supports passing state from the server to the client at the time the runtime initializes, not after the runtime has started. +* Make the service optional if it isn't always needed. See the first two examples in this section. -Additional work on the Blazor framework to address this scenario is under consideration for .NET 10 (November, 2025). For more information and community discussion of *unsupported workarounds*‡, see [Support persistent component state across enhanced page navigations (`dotnet/aspnetcore` #51584)](https://github.com/dotnet/aspnetcore/issues/51584). ‡Unsupported workarounds aren't sanctioned by Microsoft for use in Blazor apps. *Use third-party packages, approaches, and code at your own risk.* +* Create a service abstraction and create implementations for the service in the `.Client` and server projects. Register the services in each project. Inject the custom service abstraction in the component. -Disabling enhanced navigation, which reduces performance but also avoids the problem of loading state with for internal page requests, is covered in . +* For services outside of the shared framework, create a custom service implementation for the service on the server. Use the service normally in interactive components of the `.Client` project. For a demonstration of this approach, see . - +:::moniker-end ## Prerendering guidance @@ -391,9 +191,7 @@ Prerendering guidance is organized in the Blazor documentation by subject matter * Components * [Control `` content during prerendering](xref:blazor/components/control-head-content#control-head-content-during-prerendering) * Render modes - * [Prerendering](xref:blazor/components/render-modes#prerendering) * [Detect rendering location, interactivity, and assigned render mode at runtime](xref:blazor/components/render-modes#detect-rendering-location-interactivity-and-assigned-render-mode-at-runtime) - * [Client-side services fail to resolve during prerendering](xref:blazor/components/render-modes#client-side-services-fail-to-resolve-during-prerendering) * [Custom shorthand render modes](xref:blazor/components/render-modes#custom-shorthand-render-modes) * Razor component lifecycle subjects that pertain to prerendering * [Component initialization (`OnInitialized{Async}`)](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) @@ -422,6 +220,6 @@ Prerendering guidance is organized in the Blazor documentation by subject matter * [Secure a SignalR hub](xref:blazor/security/webassembly/additional-scenarios#secure-a-signalr-hub) * [Interactive server-side rendering: Cross-site scripting (XSS)](xref:blazor/security/interactive-server-side-rendering#cross-site-scripting-xss) -* [State management: Handle prerendering](xref:blazor/state-management#handle-prerendering): Besides the *Handle prerendering* section, several of the article's other sections include remarks on prerendering. +* [State management: Protected browser storage: Handle prerendering](xref:blazor/state-management/protected-browser-storage#handle-prerendering): Besides the *Handle prerendering* section, several article sections in the [State management node](xref:blazor/state-management/index) include remarks on prerendering. For .NET 7 or earlier, see [Blazor WebAssembly security additional scenarios: Prerendering with authentication](xref:blazor/security/webassembly/additional-scenarios?view=aspnetcore-7.0&preserve-view=true#prerendering-with-authentication). After viewing the content in this section, reset the documentation article version selector dropdown to the latest .NET release version to ensure that documentation pages load for the latest release on subsequent visits. diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md index 2ecdde3d18c1..94e3513cf3a8 100644 --- a/aspnetcore/blazor/components/render-modes.md +++ b/aspnetcore/blazor/components/render-modes.md @@ -215,44 +215,7 @@ When using a Blazor Web App, most of the Blazor documentation example components ## Prerendering -*Prerendering* is the process of initially rendering page content on the server without enabling event handlers for rendered controls. The server outputs the HTML UI of the page as soon as possible in response to the initial request, which makes the app feel more responsive to users. Prerendering can also improve [Search Engine Optimization (SEO)](https://developer.mozilla.org/docs/Glossary/SEO) by rendering content for the initial HTTP response that search engines use to calculate page rank. - -Prerendering is enabled by default for interactive components. - -Internal navigation for interactive routing doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests, including for [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). For more information, see [Static versus interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing), [Interactive routing and prerendering](xref:blazor/components/prerender#interactive-routing-and-prerendering), and [Enhanced navigation and form handling](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling). - - - -Disabling prerendering using the following techniques only takes effect for top-level render modes. If a parent component specifies a render mode, the prerendering settings of its children are ignored. - -To disable prerendering for a *component instance*, pass the `prerender` flag with a value of `false` to the render mode: - -* `<... @rendermode="new InteractiveServerRenderMode(prerender: false)" />` -* `<... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />` -* `<... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />` - -To disable prerendering in a *component definition*: - -* `@rendermode @(new InteractiveServerRenderMode(prerender: false))` -* `@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))` -* `@rendermode @(new InteractiveAutoRenderMode(prerender: false))` - -To disable prerendering for the entire app, indicate the render mode at the highest-level interactive component in the app's component hierarchy that isn't a root component. - -For apps based on the Blazor Web App project template, a render mode assigned to the entire app is specified where the `Routes` component is used in the `App` component (`Components/App.razor`). The following example sets the app's render mode to Interactive Server with prerendering disabled: - -```razor - -``` - -Also, disable prerendering for the [`HeadOutlet` component](xref:blazor/components/control-head-content#headoutlet-component) in the `App` component: - -```razor - -``` - -Making a root component, such as the `App` component, interactive with the `@rendermode` directive at the top of the root component's definition file (`.razor`) isn't supported. Therefore, prerendering can't be disabled directly by the `App` component. +Interactive render modes (Interactive Server, Interactive WebAssembly, Interactive Auto) support prerendering by default, which initially renders the page content statically from the server to improve the initial load experience. For more information, see . :::moniker range=">= aspnetcore-9.0" @@ -844,73 +807,6 @@ In the preceding code, change the `{INTERACTIVE RENDER MODE}` placeholder to the :::moniker-end -## Client-side services fail to resolve during prerendering - -Assuming that prerendering isn't disabled for a component or for the app, a component in the `.Client` project is prerendered on the server. Because the server doesn't have access to registered client-side Blazor services, it isn't possible to inject these services into a component without receiving an error that the service can't be found during prerendering. - -For example, consider the following `Home` component in the `.Client` project in a Blazor Web App with [global Interactive WebAssembly or Interactive Auto rendering](#apply-a-render-mode-to-the-entire-app). The component attempts to inject to obtain the environment's name. - -```razor -@page "/" -@inject IWebAssemblyHostEnvironment Environment - -Home - -

Home

- -

- Environment: @Environment.Environment -

-``` - -No compile time error occurs, but a runtime error occurs during prerendering: - -> :::no-loc text="Cannot provide a value for property 'Environment' on type 'BlazorSample.Client.Pages.Home'. There is no registered service of type 'Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment'."::: - -This error occurs because the component must compile and execute on the server during prerendering, but isn't a registered service on the server. - -If the app doesn't require the value during prerendering, this problem can be solved by injecting to obtain the service instead of the service type itself: - -```razor -@page "/" -@using Microsoft.AspNetCore.Components.WebAssembly.Hosting -@inject IServiceProvider Services - -Home - -

Home

- -

- Environment: @environmentName -

- -@code { - private string? environmentName; - - protected override void OnInitialized() - { - if (Services.GetService() is { } env) - { - environmentName = env.Environment; - } - } -} -``` - -However, the preceding approach isn't useful if your logic requires a value during prerendering. - -You can also avoid the problem if you [disable prerendering](#prerendering) for the component, but that's an extreme measure to take in many cases that may not meet your component's specifications. - -There are a three approaches that you can take to address this scenario. The following are listed from most recommended to least recommended: - -* *Recommended* for shared framework services: For shared framework services that merely aren't registered server-side in the main project, register the services in the main project, which makes them available during prerendering. For an example of this scenario, see the guidance for services in . - -* *Recommended* for services outside of the shared framework: Create a custom service implementation for the service on the server. Use the service normally in interactive components of the `.Client` project. For a demonstration of this approach, see . - -* Create a service abstraction and create implementations for the service in the `.Client` and server projects. Register the services in each project. Inject the custom service in the component. - -* You might be able to add a `.Client` project package reference to a server-side package and fall back to using the server-side API when prerendering on the server. - ## Discover components from additional assemblies Additional assemblies must be disclosed to the Blazor framework to discover routable Razor components in referenced projects. For more information, see . @@ -923,7 +819,7 @@ Additional assemblies must be disclosed to the Blazor framework to discover rout The `@rendermode` directive takes a single parameter that's a static instance of type . The `@rendermode` directive attribute can take any render mode instance, static or not. The Blazor framework provides the static class with some predefined render modes for convenience, but you can create your own. -Normally, a component uses the following `@rendermode` directive to [disable prerendering](#prerendering): +Normally, a component uses the following `@rendermode` directive to [disable prerendering](xref:blazor/components/prerender#disable-prerendering): ```razor @rendermode @(new InteractiveServerRenderMode(prerender: false)) @@ -961,7 +857,7 @@ At the moment, the shorthand render mode approach is probably only useful for re *This section only applies to Blazor Web Apps.* -A top-level imports file in the `Components` folder (`Components/_Imports.razor`) injects its references into all of the components in the folder hierarchy, which includes the `App` component (`App.razor`). The `App` component is always rendered statically even if [prerendering](#prerendering) of a page component is disabled. Therefore, injecting services via the top-level imports file results in resolving *two instances* of the service in page components. +A top-level imports file in the `Components` folder (`Components/_Imports.razor`) injects its references into all of the components in the folder hierarchy, which includes the `App` component (`App.razor`). The `App` component is always rendered statically even if [prerendering of a page component is disabled](xref:blazor/components/prerender#disable-prerendering). Therefore, injecting services via the top-level imports file results in resolving *two instances* of the service in page components. To address this scenario, inject the service in a new imports file placed in the `Pages` folder (`Components/Pages/_Imports.razor`). From that location, the service is only resolved once in page components. diff --git a/aspnetcore/blazor/components/rendering.md b/aspnetcore/blazor/components/rendering.md index 95616c94a95d..0a0f331eaf71 100644 --- a/aspnetcore/blazor/components/rendering.md +++ b/aspnetcore/blazor/components/rendering.md @@ -341,7 +341,7 @@ For approaches to manage state, see the following resources: * [Bind across more than two components](xref:blazor/components/data-binding#bind-across-more-than-two-components) using data bindings. * [Pass data across a component hierarchy](xref:blazor/components/cascading-values-and-parameters#pass-data-across-a-component-hierarchy) using cascading values and parameters. -* [Server-side in-memory state container service](xref:blazor/state-management?pivots=server#in-memory-state-container-service-server) ([client-side equivalent](xref:blazor/state-management?pivots=webassembly#in-memory-state-container-service-wasm)) section of the *State management* article. +* [In-memory state container service](xref:blazor/state-management/index#in-memory-state-container-service) section of the *State management* overview. For the state manager approach, C# events are outside the Blazor rendering pipeline. Call on other components you wish to rerender in response to the state manager's events. diff --git a/aspnetcore/blazor/file-uploads.md b/aspnetcore/blazor/file-uploads.md index 448b246609cf..afc764734c95 100644 --- a/aspnetcore/blazor/file-uploads.md +++ b/aspnetcore/blazor/file-uploads.md @@ -567,7 +567,7 @@ In the Blazor Web App server project, add services must be added to the server project because the client-side component is prerendered on the server. If you [disable prerendering for the following component](xref:blazor/components/render-modes#prerendering), you aren't required to provide the services in the server project and don't need to add the preceding line to the server project. +The services must be added to the server project because the client-side component is prerendered on the server. If you [disable prerendering for the following component](xref:blazor/components/prerender#disable-prerendering), you aren't required to provide the services in the server project and don't need to add the preceding line to the server project. For more information on adding services to an ASP.NET Core app, see . diff --git a/aspnetcore/blazor/fundamentals/dependency-injection.md b/aspnetcore/blazor/fundamentals/dependency-injection.md index 8860f57c849e..a6d1813aea9c 100644 --- a/aspnetcore/blazor/fundamentals/dependency-injection.md +++ b/aspnetcore/blazor/fundamentals/dependency-injection.md @@ -191,9 +191,9 @@ Blazor Web Apps normally prerender client-side WebAssembly components. If an app Use ***either*** of the following approaches to resolve this problem: * Register the service in the main project to make it available during component prerendering. -* If prerendering isn't required for the component, disable prerendering by following the guidance in . If you adopt this approach, you don't need to register the service in the main project. +* If prerendering isn't required for the component, disable prerendering by following the guidance in . If you adopt this approach, you don't need to register the service in the main project. -For more information, see [Client-side services fail to resolve during prerendering](xref:blazor/components/render-modes#client-side-services-fail-to-resolve-during-prerendering). +For more information, see the [Client-side services fail to resolve during prerendering](xref:blazor/components/prerender#client-side-services-fail-to-resolve-during-prerendering) section of the *Prerendering* article, which appears later in the Blazor documentation. :::moniker-end @@ -203,7 +203,7 @@ Services can be configured with the lifetimes shown in the following table. | Lifetime | Description | | -------- | ----------- | -| |

Client-side doesn't currently have a concept of DI scopes. `Scoped`-registered services behave like `Singleton` services.

Server-side development supports the `Scoped` lifetime across HTTP requests but not across SignalR connection/circuit messages among components that are loaded on the client. The Razor Pages or MVC portion of the app treats scoped services normally and recreates the services on *each HTTP request* when navigating among pages or views or from a page or view to a component. Scoped services aren't reconstructed when navigating among components on the client, where the communication to the server takes place over the SignalR connection of the user's circuit, not via HTTP requests. In the following component scenarios on the client, scoped services are reconstructed because a new circuit is created for the user:

  • The user closes the browser's window. The user opens a new window and navigates back to the app.
  • The user closes a tab of the app in a browser window. The user opens a new tab and navigates back to the app.
  • The user selects the browser's reload/refresh button.

For more information on preserving user state in server-side apps, see .

| +| |

Client-side doesn't currently have a concept of DI scopes. `Scoped`-registered services behave like `Singleton` services.

Server-side development supports the `Scoped` lifetime across HTTP requests but not across SignalR connection/circuit messages among components that are loaded on the client. The Razor Pages or MVC portion of the app treats scoped services normally and recreates the services on *each HTTP request* when navigating among pages or views or from a page or view to a component. Scoped services aren't reconstructed when navigating among components on the client, where the communication to the server takes place over the SignalR connection of the user's circuit, not via HTTP requests. In the following component scenarios on the client, scoped services are reconstructed because a new circuit is created for the user:

  • The user closes the browser's window. The user opens a new window and navigates back to the app.
  • The user closes a tab of the app in a browser window. The user opens a new tab and navigates back to the app.
  • The user selects the browser's reload/refresh button.

For more information on preserving user state in server-side apps, see and .

| | | DI creates a *single instance* of the service. All components requiring a `Singleton` service receive the same instance of the service. | | | Whenever a component obtains an instance of a `Transient` service from the service container, it receives a *new instance* of the service. | diff --git a/aspnetcore/blazor/fundamentals/environments.md b/aspnetcore/blazor/fundamentals/environments.md index b245867aaf61..ab5bf2ccd0e8 100644 --- a/aspnetcore/blazor/fundamentals/environments.md +++ b/aspnetcore/blazor/fundamentals/environments.md @@ -310,7 +310,7 @@ When the component is rerendered just a second or two later, after the Blazor bu The preceding example demonstrates why we recommend setting the server environment to match the client environment for development, testing, and production deployments. -For more information, see the [Client-side services fail to resolve during prerendering](xref:blazor/components/render-modes#client-side-services-fail-to-resolve-during-prerendering) section of the *Render modes* article, which appears later in the Blazor documentation. +For more information, see the [Client-side services fail to resolve during prerendering](xref:blazor/components/prerender#client-side-services-fail-to-resolve-during-prerendering) section of the *Prerendering* article, which appears later in the Blazor documentation. :::moniker-end diff --git a/aspnetcore/blazor/fundamentals/routing.md b/aspnetcore/blazor/fundamentals/routing.md index 39121f5273ac..6cd3cc53ed30 100644 --- a/aspnetcore/blazor/fundamentals/routing.md +++ b/aspnetcore/blazor/fundamentals/routing.md @@ -23,13 +23,13 @@ This article explains how to manage Blazor app request routing and how to use th *This section applies to Blazor Web Apps.* -If [prerendering is enabled](xref:blazor/components/render-modes#prerendering), the Blazor router (`Router` component, `` in `Routes.razor`) performs static routing to components during static server-side rendering (static SSR). This type of routing is called *static routing*. +If [prerendering is enabled](xref:blazor/components/prerender), the Blazor router (`Router` component, `` in `Routes.razor`) performs static routing to components during static server-side rendering (static SSR). This type of routing is called *static routing*. When an interactive render mode is assigned to the `Routes` component, the Blazor router becomes interactive after static SSR with static routing on the server. This type of routing is called *interactive routing*. Static routers use endpoint routing and the HTTP request path to determine which component to render. When the router becomes interactive, it uses the document's URL (the URL in the browser's address bar) to determine which component to render. This means that the interactive router can dynamically change which component is rendered if the document's URL dynamically changes to another valid internal URL, and it can do so without performing an HTTP request to fetch new page content. -Interactive routing also prevents prerendering because new page content isn't requested from the server with a normal page request. For more information, see . +Interactive routing also prevents prerendering because new page content isn't requested from the server with a normal page request. For more information, see . :::moniker-end @@ -190,7 +190,7 @@ app.MapRazorComponents() An interactive render mode can be assigned to the `Routes` component (`Routes.razor`) that makes the Blazor router become interactive after static SSR and static routing on the server. For example, `` assigns interactive server-side rendering (interactive SSR) to the `Routes` component. The `Router` component inherits interactive server-side rendering (interactive SSR) from the `Routes` component. The router becomes interactive after static routing on the server. -Internal navigation for interactive routing doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests. For more information, see . +Internal navigation for interactive routing doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests. For more information, see . If the `Routes` component is defined in the server project, the parameter of the `Router` component should include the `.Client` project's assembly. This allows the router to work correctly when rendered interactively. diff --git a/aspnetcore/blazor/fundamentals/signalr.md b/aspnetcore/blazor/fundamentals/signalr.md index c587c34a3b12..fea583074ea0 100644 --- a/aspnetcore/blazor/fundamentals/signalr.md +++ b/aspnetcore/blazor/fundamentals/signalr.md @@ -145,7 +145,7 @@ For more information, see . +If prerendering is configured, prerendering occurs before the client connection to the server is established. For more information, see . :::moniker-end @@ -517,7 +517,7 @@ If reconnection fails, the user is instructed to retry or reload the page: :::moniker-end -If reconnection succeeds, user state is often lost. Custom code can be added to any component to save and reload user state across connection failures. For more information, see . +If reconnection succeeds, user state is often lost. Custom code can be added to any component to save and reload user state across connection failures. For more information, see and . :::moniker range=">= aspnetcore-10.0" @@ -730,7 +730,7 @@ When the custom reconnect modal appears, it renders the following content with a :::moniker range=">= aspnetcore-8.0" -By default, components are prerendered on the server before the client connection to the server is established. For more information, see . +By default, components are prerendered on the server before the client connection to the server is established. For more information, see . :::moniker-end diff --git a/aspnetcore/blazor/host-and-deploy/configure-linker.md b/aspnetcore/blazor/host-and-deploy/configure-linker.md index 23d9e5d32e38..dbef69cc748b 100644 --- a/aspnetcore/blazor/host-and-deploy/configure-linker.md +++ b/aspnetcore/blazor/host-and-deploy/configure-linker.md @@ -121,4 +121,4 @@ For more information, see [I18N: Pnetlib Internationalization Framework Library * * [IL trimmer concepts and related tools (`dotnet/runtime` GitHub repository)](https://github.com/dotnet/runtime/tree/main/docs/tools/illink) -* [Trim self-contained deployments and executables (server-side Blazor apps only](/dotnet/core/deploying/trimming/trim-self-contained) +* [Trim self-contained deployments and executables (server-side Blazor apps only)](/dotnet/core/deploying/trimming/trim-self-contained) diff --git a/aspnetcore/blazor/includes/prerendering.md b/aspnetcore/blazor/includes/prerendering.md index 719501f2e6b9..c158a07f5ccb 100644 --- a/aspnetcore/blazor/includes/prerendering.md +++ b/aspnetcore/blazor/includes/prerendering.md @@ -2,8 +2,15 @@ *This section applies to server-side apps that prerender Razor components. Prerendering is covered in .* + + > [!NOTE] -> Internal navigation for [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) in Blazor Web Apps doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests. If the app adopts interactive routing, perform a full page reload for component examples that demonstrate prerendering behavior. For more information, see . +> Internal navigation for [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) in Blazor Web Apps doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests. If the app adopts interactive routing, perform a full page reload for component examples that demonstrate prerendering behavior. For more information, see . :::moniker-end diff --git a/aspnetcore/blazor/security/includes/shared-state.md b/aspnetcore/blazor/security/includes/shared-state.md index 51925347010b..f0f7fd44561b 100644 --- a/aspnetcore/blazor/security/includes/shared-state.md +++ b/aspnetcore/blazor/security/includes/shared-state.md @@ -5,4 +5,4 @@ Server-side Blazor apps live in server memory, and multiple app sessions are hos You can use stateful singleton services in Blazor apps if they're specifically designed for it. For example, use of a singleton memory cache is acceptable because a memory cache requires a key to access a given entry. Assuming users don't have control over the cache keys that are used with the cache, state stored in the cache doesn't leak across circuits. -For general guidance on state management, see . +For general guidance on state management, see . diff --git a/aspnetcore/blazor/security/index.md b/aspnetcore/blazor/security/index.md index 3d9c82042c88..6db6e394b680 100644 --- a/aspnetcore/blazor/security/index.md +++ b/aspnetcore/blazor/security/index.md @@ -257,7 +257,7 @@ To inspect the Blazor framework's Identity components, access them in the `Pages When you choose the Interactive WebAssembly or Interactive Auto render modes, the server handles all authentication and authorization requests, and the Identity components render statically on the server in the Blazor Web App's main project. -The framework provides a custom in both the server and client (`.Client`) projects to flow the user's authentication state to the browser. The server project calls , while the client project calls . Authenticating on the server rather than the client allows the app to access authentication state during prerendering and before the .NET WebAssembly runtime is initialized. The custom implementations use the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) () to serialize the authentication state into HTML comments and then read it back from WebAssembly to create a new instance. For more information, see the [Manage authentication state in Blazor Web Apps](#manage-authentication-state-in-blazor-web-apps) section. +The framework provides a custom in both the server and client (`.Client`) projects to flow the user's authentication state to the browser. The server project calls , while the client project calls . Authenticating on the server rather than the client allows the app to access authentication state during prerendering and before the .NET WebAssembly runtime is initialized. The custom implementations use the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) () to serialize the authentication state into HTML comments and then read it back from WebAssembly to create a new instance. For more information, see the [Manage authentication state in Blazor Web Apps](#manage-authentication-state-in-blazor-web-apps) section. Only for Interactive Server solutions, [`IdentityRevalidatingAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/main/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs) is a server-side that revalidates the security stamp for the connected user every 30 minutes an interactive circuit is connected. @@ -265,7 +265,7 @@ Only for Interactive Server solutions, [`IdentityRevalidatingAuthenticationState :::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" -When you choose the Interactive WebAssembly or Interactive Auto render modes, the server handles all authentication and authorization requests, and the Identity components render statically on the server in the Blazor Web App's main project. The project template includes a [`PersistentAuthenticationStateProvider` class (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp.Client/PersistentAuthenticationStateProvider.cs) in the `.Client` project to synchronize the user's authentication state between the server and the browser. The class is a custom implementation of . The provider uses the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) () to prerender the authentication state and persist it to the page. +When you choose the Interactive WebAssembly or Interactive Auto render modes, the server handles all authentication and authorization requests, and the Identity components render statically on the server in the Blazor Web App's main project. The project template includes a [`PersistentAuthenticationStateProvider` class (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp.Client/PersistentAuthenticationStateProvider.cs) in the `.Client` project to synchronize the user's authentication state between the server and the browser. The class is a custom implementation of . The provider uses the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) () to prerender the authentication state and persist it to the page. In the main project of a Blazor Web App, the authentication state provider is named either [`IdentityRevalidatingAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/main/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs) (Server interactivity solutions only) or [`PersistingRevalidatingAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/PersistingRevalidatingAuthenticationStateProvider.cs) (WebAssembly or Auto interactivity solutions). @@ -277,7 +277,7 @@ Blazor Identity depends on instan For a description on how global interactive render modes are applied to non-Identity components while at the same time enforcing static SSR for the Identity components, see . -For more information on persisting prerendered state, see . +For more information on persisting prerendered state, see . [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] @@ -296,7 +296,7 @@ To address this, the best approach is to perform authentication within the ASP.N :::moniker range=">= aspnetcore-9.0" -In the server project's `Program` file, call , which serializes the returned by the server-side using the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) (): +In the server project's `Program` file, call , which serializes the returned by the server-side using the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) (): ```csharp builder.Services.AddRazorComponents() @@ -313,7 +313,7 @@ builder.Services.AddRazorComponents() options => options.SerializeAllClaims = true); ``` -In the client (`.Client`) project's `Program` file, call , which adds an where the is deserialized from the server using `AuthenticationStateData` and the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) (). There should be a corresponding call to in the server project. +In the client (`.Client`) project's `Program` file, call , which adds an where the is deserialized from the server using `AuthenticationStateData` and the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) (). There should be a corresponding call to in the server project. ```csharp builder.Services.AddAuthorizationCore(); @@ -325,9 +325,9 @@ builder.Services.AddAuthenticationStateDeserialization(); :::moniker range=">= aspnetcore-8.0 < aspnetcore-9.0" -* [`PersistingRevalidatingAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/PersistingRevalidatingAuthenticationStateProvider.cs): For Blazor Web Apps that adopt interactive server-side rendering (interactive SSR) and client-side rendering (CSR). This is a server-side that revalidates the security stamp for the connected user every 30 minutes an interactive circuit is connected. It also uses the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) to flow the authentication state to the client, which is then fixed for the lifetime of CSR. +* [`PersistingRevalidatingAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/PersistingRevalidatingAuthenticationStateProvider.cs): For Blazor Web Apps that adopt interactive server-side rendering (interactive SSR) and client-side rendering (CSR). This is a server-side that revalidates the security stamp for the connected user every 30 minutes an interactive circuit is connected. It also uses the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) to flow the authentication state to the client, which is then fixed for the lifetime of CSR. -* [`PersistingServerAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/PersistingServerAuthenticationStateProvider.cs): For Blazor Web Apps that only adopt CSR. This is a server-side that uses the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) to flow the authentication state to the client, which is then fixed for the lifetime of CSR. +* [`PersistingServerAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/PersistingServerAuthenticationStateProvider.cs): For Blazor Web Apps that only adopt CSR. This is a server-side that uses the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) to flow the authentication state to the client, which is then fixed for the lifetime of CSR. * [`PersistentAuthenticationStateProvider` (reference source)](https://github.com/dotnet/aspnetcore/blob/release/8.0/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp.Client/PersistentAuthenticationStateProvider.cs): For Blazor Web Apps that adopt CSR. This is a client-side that determines the user's authentication state by looking for data persisted in the page when it was rendered on the server. This authentication state is fixed for the lifetime of CSR. If the user needs to log in or out, a full-page reload is required. This only provides a user name and email for display purposes. It doesn't include tokens that authenticate to the server when making subsequent requests, which is handled separately using a cookie that's included on `HttpClient` requests to the server. @@ -525,7 +525,7 @@ In spite of the word "state" in the name, . +For guidance on general state management outside of ASP.NET Core Identity, see . ### Additional security abstractions @@ -627,7 +627,7 @@ internal sealed class ClientWeatherForecaster(HttpClient httpClient) The client project maintains a `Weather` component that: * Enforces authorization with an [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute). -* Uses the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) () to persist weather forecast data when the component transitions from static to interactive SSR on the server. For more information, see . +* Uses the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence) () to persist weather forecast data when the component transitions from static to interactive SSR on the server. For more information, see . :::moniker-end diff --git a/aspnetcore/blazor/security/interactive-server-side-rendering.md b/aspnetcore/blazor/security/interactive-server-side-rendering.md index 201ca46daacd..a5a0a22b2f00 100644 --- a/aspnetcore/blazor/security/interactive-server-side-rendering.md +++ b/aspnetcore/blazor/security/interactive-server-side-rendering.md @@ -14,7 +14,7 @@ uid: blazor/security/interactive-server-side-rendering This article explains how to mitigate security threats in interactive server-side Blazor. -Apps adopt a *stateful* data processing model, where the server and client maintain a long-lived relationship. The persistent state is maintained by a [circuit](xref:blazor/state-management), which can span connections that are also potentially long-lived. +Apps adopt a *stateful* data processing model, where the server and client maintain a long-lived relationship. The persistent state is maintained by a circuit, which can span connections that are also potentially long-lived. When a user visits a site, the server creates a circuit in the server's memory. The circuit indicates to the browser what content to render and responds to events, such as when the user selects a button in the UI. To perform these actions, a circuit invokes JavaScript functions in the user's browser and .NET methods on the server. This two-way JavaScript-based interaction is referred to as [JavaScript interop (JS interop)](xref:blazor/js-interop/call-javascript-from-dotnet). diff --git a/aspnetcore/blazor/security/webassembly/additional-scenarios.md b/aspnetcore/blazor/security/webassembly/additional-scenarios.md index edb0ec09b928..7266cc619cae 100644 --- a/aspnetcore/blazor/security/webassembly/additional-scenarios.md +++ b/aspnetcore/blazor/security/webassembly/additional-scenarios.md @@ -1361,7 +1361,7 @@ To configure a Blazor WebAssembly app to use the [ASP.NET Core gRPC framework](x :::moniker range=">= aspnetcore-8.0" > [!NOTE] -> Prerendering is enabled by default in Blazor Web Apps, so you must account for the component rendering first from the server and then from the client. Any prerendered state should flow to the client so that it can be reused. For more information, see . +> Prerendering is enabled by default in Blazor Web Apps, so you must account for the component rendering first from the server and then from the client. Any prerendered state should flow to the client so that it can be reused. For more information, see . :::moniker-end diff --git a/aspnetcore/blazor/state-management.md b/aspnetcore/blazor/state-management.md deleted file mode 100644 index b656599d4436..000000000000 --- a/aspnetcore/blazor/state-management.md +++ /dev/null @@ -1,890 +0,0 @@ ---- -title: ASP.NET Core Blazor state management -author: guardrex -description: Learn how to persist user data (state) in Blazor apps. -monikerRange: '>= aspnetcore-3.1' -ms.author: wpickett -ms.custom: mvc -ms.date: 11/12/2024 -uid: blazor/state-management -zone_pivot_groups: blazor-app-models ---- -# ASP.NET Core Blazor state management - -[!INCLUDE[](~/includes/not-latest-version.md)] - -This article describes common approaches for maintaining a user's data (state) while they use an app and across browser sessions. - -> [!NOTE] -> The code examples in this article adopt [nullable reference types (NRTs) and .NET compiler null-state static analysis](xref:migration/50-to-60#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis), which are supported in ASP.NET Core in .NET 6 or later. When targeting .NET 5 or earlier, remove the null type designation (`?`) from types in the article's examples. - -## Maintain user state - -:::zone pivot="server" - -Server-side Blazor is a stateful app framework. Most of the time, the app maintains a connection to the server. The user's state is held in the server's memory in a *circuit*. - -Examples of user state held in a circuit include: - -* The hierarchy of component instances and their most recent render output in the rendered UI. -* The values of fields and properties in component instances. -* Data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances that are scoped to the circuit. - -User state might also be found in JavaScript variables in the browser's memory set via [JavaScript interop](xref:blazor/js-interop/call-javascript-from-dotnet) calls. - -If a user experiences a temporary network connection loss, Blazor attempts to reconnect the user to their original circuit with their original state. However, reconnecting a user to their original circuit in the server's memory isn't always possible: - -* The server can't retain a disconnected circuit forever. The server must release a disconnected circuit after a timeout or when the server is under memory pressure. -* In multi-server, load-balanced deployment environments, individual servers may fail or be automatically removed when no longer required to handle the overall volume of requests. The original server processing requests for a user may become unavailable when the user attempts to reconnect. -* The user might close and reopen their browser or reload the page, which removes any state held in the browser's memory. For example, JavaScript variable values set through JavaScript interop calls are lost. - -When a user can't be reconnected to their original circuit, the user receives a new circuit with an empty state. This is equivalent to closing and reopening a desktop app. - -## Persist state across circuits - -Generally, maintain state across circuits where users are actively creating data, not simply reading data that already exists. - -To preserve state across circuits, the app must persist the data to some other storage location than the server's memory. State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. - -Data persistence is typically only required for high-value state that users expended effort to create. In the following examples, persisting state either saves time or aids in commercial activities: - -* Multi-step web forms: It's time-consuming for a user to re-enter data for several completed steps of a multi-step web form if their state is lost. A user loses state in this scenario if they navigate away from the form and return later. -* Shopping carts: Any commercially important component of an app that represents potential revenue can be maintained. A user who loses their state, and thus their shopping cart, may purchase fewer products or services when they return to the site later. - -An app can only persist *app state*. UIs can't be persisted, such as component instances and their render trees. Components and render trees aren't generally serializable. To persist UI state, such as the expanded nodes of a tree view control, the app must use custom code to model the behavior of the UI state as serializable app state. - -## Where to persist state - -Common locations exist for persisting state: - -:::moniker range=">= aspnetcore-10.0" - -* [Declarative model for persistent state](#declarative-model-for-persisting-state-server) -* [Server-side storage](#server-side-storage-server) -* [URL](#url-server) -* [Browser storage](#browser-storage-server) -* [In-memory state container service](#in-memory-state-container-service) -* [Cascading values and parameters](#cascading-values-and-parameters) - -:::moniker-end - -:::moniker range="< aspnetcore-10.0" - -* [Server-side storage](#server-side-storage-server) -* [URL](#url-server) -* [Browser storage](#browser-storage-server) -* [In-memory state container service](#in-memory-state-container-service) -* [Cascading values and parameters](#cascading-values-and-parameters) - -:::moniker-end - -:::moniker range=">= aspnetcore-10.0" - -

Declarative model for persisting state

- - - -Establish declarative state in a dependency injection service for use around the app by calling on the Razor components builder () with a custom service type and render mode. For more information, see . - -:::moniker-end - -

Server-side storage

- -For permanent data persistence that spans multiple users and devices, the app can use server-side storage. Options include: - -* Blob storage -* Key-value storage -* Relational database -* Table storage - -After data is saved, the user's state is retained and available in any new circuit. - -For more information on Azure data storage options, see the following: - -* [Azure Databases](https://azure.microsoft.com/product-categories/databases/) -* [Azure Storage Documentation](/azure/storage/) - -

URL

- -For transient data representing navigation state, model the data as a part of the URL. Examples of user state modeled in the URL include: - -* The ID of a viewed entity. -* The current page number in a paged grid. - -The contents of the browser's address bar are retained: - -* If the user manually reloads the page. -* If the web server becomes unavailable, and the user is forced to reload the page in order to connect to a different server. - -For information on defining URL patterns with the [`@page`](xref:mvc/views/razor#page) directive, see . - -

Browser storage

- -For transient data that the user is actively creating, a commonly used storage location is the browser's [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage) collections: - -* `localStorage` is scoped to the browser's instance. If the user reloads the page or closes and reopens the browser, the state persists. If the user opens multiple browser tabs, the state is shared across the tabs. Data persists in `localStorage` until explicitly cleared. The `localStorage` data for a document loaded in a "private browsing" or "incognito" session is cleared when the last "private" tab is closed. -* `sessionStorage` is scoped to the browser tab. If the user reloads the tab, the state persists. If the user closes the tab or the browser, the state is lost. If the user opens multiple browser tabs, each tab has its own independent version of the data. - -Generally, `sessionStorage` is safer to use. `sessionStorage` avoids the risk that a user opens multiple tabs and encounters the following: - -* Bugs in state storage across tabs. -* Confusing behavior when a tab overwrites the state of other tabs. - -`localStorage` is the better choice if the app must persist state across closing and reopening the browser. - -Caveats for using browser storage: - -* Similar to the use of a server-side database, loading and saving data are asynchronous. -* The requested page doesn't exist in the browser during prerendering, so local storage isn't available during prerendering. -* Storage of a few kilobytes of data is reasonable to persist for server-side Blazor apps. Beyond a few kilobytes, you must consider the performance implications because the data is loaded and saved across the network. -* Users may view or tamper with the data. [ASP.NET Core Data Protection](xref:security/data-protection/introduction) can mitigate the risk. For example, [ASP.NET Core Protected Browser Storage](#aspnet-core-protected-browser-storage) uses ASP.NET Core Data Protection. - -Third-party NuGet packages provide APIs for working with `localStorage` and `sessionStorage`. It's worth considering choosing a package that transparently uses [ASP.NET Core Data Protection](xref:security/data-protection/introduction). Data Protection encrypts stored data and reduces the potential risk of tampering with stored data. If JSON-serialized data is stored in plain text, users can see the data using browser developer tools and also modify the stored data. Securing trivial data isn't a problem. For example, reading or modifying the stored color of a UI element isn't a significant security risk to the user or the organization. Avoid allowing users to inspect or tamper with *sensitive data*. - -## ASP.NET Core Protected Browser Storage - -ASP.NET Core Protected Browser Storage leverages [ASP.NET Core Data Protection](xref:security/data-protection/introduction) for [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage). - -:::moniker range=">= aspnetcore-5.0" - -> [!NOTE] -> Protected Browser Storage relies on ASP.NET Core Data Protection and is only supported for server-side Blazor apps. - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -> [!WARNING] -> `Microsoft.AspNetCore.ProtectedBrowserStorage` is an unsupported, experimental package that isn't intended for production use. -> -> The package is only available for use in ASP.NET Core 3.1 apps. - -### Configuration - -1. Add a package reference to [`Microsoft.AspNetCore.ProtectedBrowserStorage`](https://www.nuget.org/packages/Microsoft.AspNetCore.ProtectedBrowserStorage). - - [!INCLUDE[](~/includes/package-reference.md)] - -1. In the `_Host.cshtml` file, add the following script inside the closing `` tag: - - ```cshtml - - ``` - -1. In `Startup.ConfigureServices`, call `AddProtectedBrowserStorage` to add `localStorage` and `sessionStorage` services to the service collection: - - ```csharp - services.AddProtectedBrowserStorage(); - ``` - -:::moniker-end - -### Save and load data within a component - -In any component that requires loading or saving data to browser storage, use the [`@inject`](xref:mvc/views/razor#inject) directive to inject an instance of either of the following: - -* `ProtectedLocalStorage` -* `ProtectedSessionStorage` - -The choice depends on which browser storage location you wish to use. In the following example, `sessionStorage` is used: - -:::moniker range=">= aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage -@inject ProtectedSessionStorage ProtectedSessionStore -``` - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.ProtectedBrowserStorage -@inject ProtectedSessionStorage ProtectedSessionStore -``` - -:::moniker-end - -The `@using` directive can be placed in the app's `_Imports.razor` file instead of in the component. Use of the `_Imports.razor` file makes the namespace available to larger segments of the app or the whole app. - -To persist the `currentCount` value in the `Counter` component of an app based on the [Blazor project template](xref:blazor/project-structure), modify the `IncrementCount` method to use `ProtectedSessionStore.SetAsync`: - -```csharp -private async Task IncrementCount() -{ - currentCount++; - await ProtectedSessionStore.SetAsync("count", currentCount); -} -``` - -In larger, more realistic apps, storage of individual fields is an unlikely scenario. Apps are more likely to store entire model objects that include complex state. `ProtectedSessionStore` automatically serializes and deserializes JSON data to store complex state objects. - -In the preceding code example, the `currentCount` data is stored as `sessionStorage['count']` in the user's browser. The data isn't stored in plain text but rather is protected using ASP.NET Core Data Protection. The encrypted data can be inspected if `sessionStorage['count']` is evaluated in the browser's developer console. - -To recover the `currentCount` data if the user returns to the `Counter` component later, including if the user is on a new circuit, use `ProtectedSessionStore.GetAsync`: - -:::moniker range=">= aspnetcore-5.0" - -```csharp -protected override async Task OnInitializedAsync() -{ - var result = await ProtectedSessionStore.GetAsync("count"); - currentCount = result.Success ? result.Value : 0; -} -``` - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -```csharp -protected override async Task OnInitializedAsync() -{ - currentCount = await ProtectedSessionStore.GetAsync("count"); -} -``` - -:::moniker-end - -If the component's parameters include navigation state, call `ProtectedSessionStore.GetAsync` and assign a non-`null` result in , not . is only called once when the component is first instantiated. isn't called again later if the user navigates to a different URL while remaining on the same page. For more information, see . - -> [!WARNING] -> The examples in this section only work if the server doesn't have prerendering enabled. With prerendering enabled, an error is generated explaining that JavaScript interop calls cannot be issued because the component is being prerendered. -> -> Either disable prerendering or add additional code to work with prerendering. To learn more about writing code that works with prerendering, see the [Handle prerendering](#handle-prerendering) section. - -### Handle the loading state - -Since browser storage is accessed asynchronously over a network connection, there's always a period of time before the data is loaded and available to a component. For the best results, render a message while loading is in progress instead of displaying blank or default data. - -:::moniker range=">= aspnetcore-6.0" - -One approach is to track whether the data is `null`, which means that the data is still loading. In the default `Counter` component, the count is held in an `int`. [Make `currentCount` nullable](/dotnet/csharp/language-reference/builtin-types/nullable-value-types) by adding a question mark (`?`) to the type (`int`): - -```csharp -private int? currentCount; -``` - -Instead of unconditionally displaying the count and **`Increment`** button, display these elements only if the data is loaded by checking : - -```razor -@if (currentCount.HasValue) -{ -

Current count: @currentCount

- -} -else -{ -

Loading...

-} -``` - -:::moniker-end - -### Handle prerendering - -During prerendering: - -* An interactive connection to the user's browser doesn't exist. -* The browser doesn't yet have a page in which it can run JavaScript code. - -`localStorage` or `sessionStorage` aren't available during prerendering. If the component attempts to interact with storage, an error is generated explaining that JavaScript interop calls cannot be issued because the component is being prerendered. - -One way to resolve the error is to disable prerendering. This is usually the best choice if the app makes heavy use of browser-based storage. Prerendering adds complexity and doesn't benefit the app because the app can't prerender any useful content until `localStorage` or `sessionStorage` are available. - -:::moniker range=">= aspnetcore-8.0" - -To disable prerendering, indicate the render mode with the `prerender` parameter set to `false` at the highest-level component in the app's component hierarchy that isn't a root component. - -> [!NOTE] -> Making a root component interactive, such as the `App` component, isn't supported. Therefore, prerendering can't be disabled directly by the `App` component. - -For apps based on the Blazor Web App project template, prerendering is typically disabled where the `Routes` component is used in the `App` component (`Components/App.razor`): - -```razor - -``` - -Also, disable prerendering for the `HeadOutlet` component: - -```razor - -``` - -For more information, see . - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -To disable prerendering, open the `_Host.cshtml` file and change the `render-mode` attribute of the [Component Tag Helper](xref:mvc/views/tag-helpers/builtin-th/component-tag-helper) to : - -```cshtml - -``` - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0" - -When prerendering is disabled, [prerendering of `` content](xref:blazor/components/control-head-content) is disabled. - -:::moniker-end - -Prerendering might be useful for other pages that don't use `localStorage` or `sessionStorage`. To retain prerendering, defer the loading operation until the browser is connected to the circuit. The following is an example for storing a counter value: - -:::moniker range=">= aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage -@inject ProtectedLocalStorage ProtectedLocalStore - -@if (isConnected) -{ -

Current count: @currentCount

- -} -else -{ -

Loading...

-} - -@code { - private int currentCount; - private bool isConnected; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - isConnected = true; - await LoadStateAsync(); - StateHasChanged(); - } - } - - private async Task LoadStateAsync() - { - var result = await ProtectedLocalStore.GetAsync("count"); - currentCount = result.Success ? result.Value : 0; - } - - private async Task IncrementCount() - { - currentCount++; - await ProtectedLocalStore.SetAsync("count", currentCount); - } -} -``` - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.ProtectedBrowserStorage -@inject ProtectedLocalStorage ProtectedLocalStore - -@if (isConnected) -{ -

Current count: @currentCount

- -} -else -{ -

Loading...

-} - -@code { - private int currentCount = 0; - private bool isConnected = false; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - isConnected = true; - await LoadStateAsync(); - StateHasChanged(); - } - } - - private async Task LoadStateAsync() - { - currentCount = await ProtectedLocalStore.GetAsync("count"); - } - - private async Task IncrementCount() - { - currentCount++; - await ProtectedLocalStore.SetAsync("count", currentCount); - } -} -``` - -:::moniker-end - -### Factor out state preservation to a common provider - -If many components rely on browser-based storage, implementing state provider code many times creates code duplication. One option for avoiding code duplication is to create a *state provider parent component* that encapsulates the state provider logic. Child components can work with persisted data without regard to the state persistence mechanism. - -In the following example of a `CounterStateProvider` component, counter data is persisted to `sessionStorage`, and it handles the loading phase by not rendering its child content until state loading is complete. - -The `CounterStateProvider` component deals with prerendering by not loading state until after component rendering in the [`OnAfterRenderAsync` lifecycle method](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync), which doesn't execute during prerendering. - -The approach in this section isn't capable of triggering rerendering of multiple subscribed components on the same page. If one subscribed component changes the state, it rerenders and can display the updated state, but a different component on the same page displaying that state displays stale data until its own next rerender. Therefore, the approach described in this section is best suited to using state in a single component on the page. - -`CounterStateProvider.razor`: - -:::moniker range=">= aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage -@inject ProtectedSessionStorage ProtectedSessionStore - -@if (isLoaded) -{ - - @ChildContent - -} -else -{ -

Loading...

-} - -@code { - private bool isLoaded; - - [Parameter] - public RenderFragment? ChildContent { get; set; } - - public int CurrentCount { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - isLoaded = true; - await LoadStateAsync(); - StateHasChanged(); - } - } - - private async Task LoadStateAsync() - { - var result = await ProtectedSessionStore.GetAsync("count"); - CurrentCount = result.Success ? result.Value : 0; - isLoaded = true; - } - - public async Task IncrementCount() - { - CurrentCount++; - await ProtectedSessionStore.SetAsync("count", CurrentCount); - } -} -``` - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -```razor -@using Microsoft.AspNetCore.ProtectedBrowserStorage -@inject ProtectedSessionStorage ProtectedSessionStore - -@if (isLoaded) -{ - - @ChildContent - -} -else -{ -

Loading...

-} - -@code { - private bool isLoaded; - - [Parameter] - public RenderFragment ChildContent { get; set; } - - public int CurrentCount { get; set; } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - isLoaded = true; - await LoadStateAsync(); - StateHasChanged(); - } - } - - private async Task LoadStateAsync() - { - CurrentCount = await ProtectedSessionStore.GetAsync("count"); - isLoaded = true; - } - - public async Task IncrementCount() - { - CurrentCount++; - await ProtectedSessionStore.SetAsync("count", CurrentCount); - } -} -``` - -:::moniker-end - -> [!NOTE] -> For more information on , see . - -:::moniker range=">= aspnetcore-8.0" - -To make the state accessible to all components in an app, wrap the `CounterStateProvider` component around the (`...`) in the `Routes` component with global interactive server-side rendering (interactive SSR). - -In the `App` component (`Components/App.razor`): - -```razor - -``` - -In the `Routes` component (`Components/Routes.razor`): - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -To use the `CounterStateProvider` component, wrap an instance of the component around any other component that requires access to the counter state. To make the state accessible to all components in an app, wrap the `CounterStateProvider` component around the in the `App` component (`App.razor`): - -:::moniker-end - -```razor - - - ... - - -``` - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - -[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)] - -:::moniker-end - -Wrapped components receive and can modify the persisted counter state. The following `Counter` component implements the pattern: - -```razor -@page "/counter" - -

Current count: @CounterStateProvider?.CurrentCount

- - -@code { - [CascadingParameter] - private CounterStateProvider? CounterStateProvider { get; set; } - - private async Task IncrementCount() - { - if (CounterStateProvider is not null) - { - await CounterStateProvider.IncrementCount(); - } - } -} -``` - -The preceding component isn't required to interact with `ProtectedBrowserStorage`, nor does it deal with a "loading" phase. - -In general, the *state provider parent component* pattern is recommended: - -* To consume state across many components. -* If there's just one top-level state object to persist. - -To persist many different state objects and consume different subsets of objects in different places, it's better to avoid persisting state globally. - -:::zone-end - -:::zone pivot="webassembly" - -User state created in a Blazor WebAssembly app is held in the browser's memory. - -Examples of user state held in browser memory include: - -* The hierarchy of component instances and their most recent render output in the rendered UI. -* The values of fields and properties in component instances. -* Data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances. -* Values set through [JavaScript interop](xref:blazor/js-interop/call-javascript-from-dotnet) calls. - -When a user closes and reopens their browser or reloads the page, user state held in the browser's memory is lost. - -> [!NOTE] -> [Protected Browser Storage](xref:blazor/state-management?pivots=server#aspnet-core-protected-browser-storage) ( namespace) relies on ASP.NET Core Data Protection and is only supported for server-side Blazor apps. - -## Persist state across browser sessions - -Generally, maintain state across browser sessions where users are actively creating data, not simply reading data that already exists. - -To preserve state across browser sessions, the app must persist the data to some other storage location than the browser's memory. State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. - -Data persistence is typically only required for high-value state that users expended effort to create. In the following examples, persisting state either saves time or aids in commercial activities: - -* Multi-step web forms: It's time-consuming for a user to re-enter data for several completed steps of a multi-step web form if their state is lost. A user loses state in this scenario if they navigate away from the form and return later. -* Shopping carts: Any commercially important component of an app that represents potential revenue can be maintained. A user who loses their state, and thus their shopping cart, may purchase fewer products or services when they return to the site later. - -An app can only persist *app state*. UIs can't be persisted, such as component instances and their render trees. Components and render trees aren't generally serializable. To persist UI state, such as the expanded nodes of a tree view control, the app must use custom code to model the behavior of the UI state as serializable app state. - -## Where to persist state - -Common locations exist for persisting state: - -:::moniker range=">= aspnetcore-10.0" - -* [Declarative model for persistent state](#declarative-model-for-persisting-state-wasm) -* [Server-side storage](#server-side-storage-wasm) -* [URL](#url-wasm) -* [Browser storage](#browser-storage-wasm) -* [In-memory state container service](#in-memory-state-container-service) -* [Cascading values and parameters](#cascading-values-and-parameters) - -:::moniker-end - -:::moniker range="< aspnetcore-10.0" - -* [Server-side storage](#server-side-storage-wasm) -* [URL](#url-wasm) -* [Browser storage](#browser-storage-wasm) -* [In-memory state container service](#in-memory-state-container-service) -* [Cascading values and parameters](#cascading-values-and-parameters) - -:::moniker-end - -:::moniker range=">= aspnetcore-10.0" - -

Declarative model for persisting state

- -Establish declarative state in a dependency injection service for use around the app by calling on the Razor components builder () with a custom service type and render mode. For more information, see . - -:::moniker-end - -

Server-side storage

- -For permanent data persistence that spans multiple users and devices, the app can use independent server-side storage accessed via a web API. Options include: - -* Blob storage -* Key-value storage -* Relational database -* Table storage - -After data is saved, the user's state is retained and available in any new browser session. - -Because Blazor WebAssembly apps run entirely in the user's browser, they require additional measures to access secure external systems, such as storage services and databases. Blazor WebAssembly apps are secured in the same manner as single-page applications (SPAs). Typically, an app authenticates a user via [OAuth](https://oauth.net)/[OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) and then interacts with storage services and databases through web API calls to a server-side app. The server-side app mediates the transfer of data between the Blazor WebAssembly app and the storage service or database. The Blazor WebAssembly app maintains an ephemeral connection to the server-side app, while the server-side app has a persistent connection to storage. - -For more information, see the following resources: - -* -* -* Blazor *Security and Identity* articles - -For more information on Azure data storage options, see the following: - -* [Azure Databases](https://azure.microsoft.com/product-categories/databases/) -* [Azure Storage Documentation](/azure/storage/) - -

URL

- -For transient data representing navigation state, model the data as a part of the URL. Examples of user state modeled in the URL include: - -* The ID of a viewed entity. -* The current page number in a paged grid. - -The contents of the browser's address bar are retained if the user manually reloads the page. - -For information on defining URL patterns with the [`@page`](xref:mvc/views/razor#page) directive, see . - -

Browser storage

- -For transient data that the user is actively creating, a commonly used storage location is the browser's [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage) collections: - -* `localStorage` is scoped to the browser's instance. If the user reloads the page or closes and reopens the browser, the state persists. If the user opens multiple browser tabs, the state is shared across the tabs. Data persists in `localStorage` until explicitly cleared. The `localStorage` data for a document loaded in a "private browsing" or "incognito" session is cleared when the last "private" tab is closed. -* `sessionStorage` is scoped to the browser tab. If the user reloads the tab, the state persists. If the user closes the tab or the browser, the state is lost. If the user opens multiple browser tabs, each tab has its own independent version of the data. - -> [!NOTE] -> `localStorage` and `sessionStorage` can be used in Blazor WebAssembly apps but only by writing custom code or using a third-party package. - -Generally, `sessionStorage` is safer to use. `sessionStorage` avoids the risk that a user opens multiple tabs and encounters the following: - -* Bugs in state storage across tabs. -* Confusing behavior when a tab overwrites the state of other tabs. - -`localStorage` is the better choice if the app must persist state across closing and reopening the browser. - -> [!WARNING] -> Users may view or tamper with the data stored in `localStorage` and `sessionStorage`. - -:::zone-end - -## In-memory state container service - -Nested components typically bind data using *chained bind* as described in . Nested and unnested components can share access to data using a registered in-memory state container. A custom state container class can use an assignable to notify components in different parts of the app of state changes. In the following example: - -* A pair of components uses a state container to track a property. -* One component in the following example is nested in the other component, but nesting isn't required for this approach to work. - -> [!IMPORTANT] -> The example in this section demonstrates how to create an in-memory state container service, register the service, and use the service in components. The example doesn't persist data without further development. For persistent storage of data, the state container must adopt an underlying storage mechanism that survives when browser memory is cleared. This can be accomplished with `localStorage`/`sessionStorage` or some other technology. - -`StateContainer.cs`: - -```csharp -public class StateContainer -{ - private string? savedString; - - public string Property - { - get => savedString ?? string.Empty; - set - { - savedString = value; - NotifyStateChanged(); - } - } - - public event Action? OnChange; - - private void NotifyStateChanged() => OnChange?.Invoke(); -} -``` - -Client-side apps (`Program` file): - -```csharp -builder.Services.AddSingleton(); -``` - -Server-side apps (`Program` file, ASP.NET Core in .NET 6 or later): - -```csharp -builder.Services.AddScoped(); -``` - -Server-side apps (`Startup.ConfigureServices` of `Startup.cs` in .NET 6 or earlier): - -```csharp -services.AddScoped(); -``` - -`Shared/Nested.razor`: - -```razor -@implements IDisposable -@inject StateContainer StateContainer - -

Nested component

- -

Nested component Property: @StateContainer.Property

- -

- -

- -@code { - protected override void OnInitialized() - { - StateContainer.OnChange += StateHasChanged; - } - - private void ChangePropertyValue() - { - StateContainer.Property = - $"New value set in the Nested component: {DateTime.Now}"; - } - - public void Dispose() - { - StateContainer.OnChange -= StateHasChanged; - } -} -``` - -`StateContainerExample.razor`: - -```razor -@page "/state-container-example" -@implements IDisposable -@inject StateContainer StateContainer - -

State Container Example component

- -

State Container component Property: @StateContainer.Property

- -

- -

- - - -@code { - protected override void OnInitialized() - { - StateContainer.OnChange += StateHasChanged; - } - - private void ChangePropertyValue() - { - StateContainer.Property = "New value set in the State " + - $"Container Example component: {DateTime.Now}"; - } - - public void Dispose() - { - StateContainer.OnChange -= StateHasChanged; - } -} -``` - -The preceding components implement , and the `OnChange` delegates are unsubscribed in the `Dispose` methods, which are called by the framework when the components are disposed. For more information, see . - -## Cascading values and parameters - -Use [cascading values and parameters](xref:blazor/components/cascading-values-and-parameters) to manage state by flowing data from an ancestor Razor component to descendent components. - -:::moniker range=">= aspnetcore-8.0" - -Root-level cascading values with a permit Razor component subscriber notifications of changed cascading values. For more information and a working example, see the `NotifyingDalek` example in . - -:::moniker-end - -## Additional approaches - -When implementing custom state storage, a useful approach is to adopt [cascading values and parameters](xref:blazor/components/cascading-values-and-parameters): - -* To consume state across many components. -* If there's just one top-level state object to persist. - -## Troubleshoot - -When using a custom state management service where you want to support state modifications from outside Blazor's synchronization context (for example from a timer or a background service), all consuming components must wrap the call in . This ensures the change notification is handled on the renderer's synchronization context. - -When the state management service doesn't call on Blazor's synchronization context, the following error is thrown: - -> :::no-loc text="System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'"::: - -For more information and an example of how to address this error, see . - -## Additional resources - -* [Save app state before an authentication operation (Blazor WebAssembly)](xref:blazor/security/webassembly/additional-scenarios#save-app-state-before-an-authentication-operation) -* Managing state via an external server API - * - * diff --git a/aspnetcore/blazor/state-management/index.md b/aspnetcore/blazor/state-management/index.md new file mode 100644 index 000000000000..a85c6c61bb65 --- /dev/null +++ b/aspnetcore/blazor/state-management/index.md @@ -0,0 +1,190 @@ +--- +title: ASP.NET Core Blazor state management overview +author: guardrex +description: Learn how to persist user data (state) in Blazor apps. +monikerRange: '>= aspnetcore-3.1' +ms.author: wpickett +ms.custom: mvc +ms.date: 08/05/2025 +uid: blazor/state-management/index +--- +# ASP.NET Core Blazor state management overview + +This article and the other articles in this node describe common approaches for maintaining a user's data (state) while they use an app and across browser sessions, including during server prerendering. + +A typical requirement during Blazor app development is sharing state across components: + +* Parent to child: A parent component passes state to a child component using parameters. +* Child to parent: A child component enables data binding to its state or provides state through callbacks. +* Parent to descendants: A parent shares state with all of its descendants using cascading values. +* App-wide: State is shared across the entire app using configured app state services. +* Per circuit: State is shared for a specific circuit using scoped app state services. + +Persisted state may need to survive pages refreshes, resumed circuits, and prerendering. State often requires central management, tracking, and testing. The locations and techniques for persisting state are highly variable. + +Blazor doesn't provide comprehensive, opinionated state management. Third-party state container products and services that work seamlessly with Blazor, such as Flux, Redux, and MobX, satisfy virtually any app requirement. + +The remainder of this article discusses general state management strategies for any type of Blazor app. + +## State management using the URL + +For transient data representing navigation state, model the data as a part of the URL. Examples of user state modeled in the URL include: + +* The ID of a viewed entity. +* The current page number in a paged grid. + +The contents of the browser's address bar are retained: + +* If the user manually reloads the page. +* *Server-side scenarios only*: If the web server becomes unavailable, and the user is forced to reload the page in order to connect to a different server. + +For information on defining URL patterns with the [`@page`](xref:mvc/views/razor#page) directive, see . + +## In-memory state container service + +Nested components typically bind data using *chained bind* as described in . Nested and unnested components can share access to data using a registered in-memory state container. A custom state container class can use an assignable to notify components in different parts of the app of state changes. In the following example: + +* A pair of components uses a state container to track a property. +* One component in the following example is nested in the other component, but nesting isn't required for this approach to work. + +> [!IMPORTANT] +> The example in this section demonstrates how to create an in-memory state container service, register the service, and use the service in components. The example doesn't persist data without further development. For persistent storage of data, the state container must adopt an underlying storage mechanism that survives when browser memory is cleared. This can be accomplished with `localStorage`/`sessionStorage` or some other technology. + +`StateContainer.cs`: + +```csharp +public class StateContainer +{ + private string? savedString; + + public string Property + { + get => savedString ?? string.Empty; + set + { + savedString = value; + NotifyStateChanged(); + } + } + + public event Action? OnChange; + + private void NotifyStateChanged() => OnChange?.Invoke(); +} +``` + +Client-side apps (`Program` file): + +```csharp +builder.Services.AddSingleton(); +``` + +Server-side apps (`Program` file, ASP.NET Core in .NET 6 or later): + +```csharp +builder.Services.AddScoped(); +``` + +Server-side apps (`Startup.ConfigureServices` of `Startup.cs`, typically in .NET 6 or earlier): + +```csharp +services.AddScoped(); +``` + +`Shared/Nested.razor`: + +```razor +@implements IDisposable +@inject StateContainer StateContainer + +

Nested component

+ +

Nested component Property: @StateContainer.Property

+ +

+ +

+ +@code { + protected override void OnInitialized() + { + StateContainer.OnChange += StateHasChanged; + } + + private void ChangePropertyValue() + { + StateContainer.Property = + $"New value set in the Nested component: {DateTime.Now}"; + } + + public void Dispose() + { + StateContainer.OnChange -= StateHasChanged; + } +} +``` + +`StateContainerExample.razor`: + +```razor +@page "/state-container-example" +@implements IDisposable +@inject StateContainer StateContainer + +

State Container Example component

+ +

State Container component Property: @StateContainer.Property

+ +

+ +

+ + + +@code { + protected override void OnInitialized() + { + StateContainer.OnChange += StateHasChanged; + } + + private void ChangePropertyValue() + { + StateContainer.Property = "New value set in the State " + + $"Container Example component: {DateTime.Now}"; + } + + public void Dispose() + { + StateContainer.OnChange -= StateHasChanged; + } +} +``` + +The preceding components implement , and the `OnChange` delegates are unsubscribed in the `Dispose` methods, which are called by the framework when the components are disposed. For more information, see . + +## Cascading values and parameters + +Use [cascading values and parameters](xref:blazor/components/cascading-values-and-parameters) to manage state by flowing data from an ancestor Razor component to descendent components: + +* To consume state across many components. +* If there's just one top-level state object to persist. + +:::moniker range=">= aspnetcore-8.0" + +Root-level cascading values with a permit Razor component subscriber notifications of changed cascading values. For more information and a working example, see the `NotifyingDalek` example in . + +:::moniker-end + +## Support state modifications from outside Blazor's synchronization context + +When using a custom state management service where you want to support state modifications from outside Blazor's synchronization context (for example from a timer or a background service), all consuming components must wrap the call in . This ensures the change notification is handled on the renderer's synchronization context. + +When the state management service doesn't call on Blazor's synchronization context, the following error is thrown: + +> :::no-loc text="System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'"::: + +For more information and an example of how to address this error, see . diff --git a/aspnetcore/blazor/state-management/prerendered-state-persistence.md b/aspnetcore/blazor/state-management/prerendered-state-persistence.md new file mode 100644 index 000000000000..79e791748901 --- /dev/null +++ b/aspnetcore/blazor/state-management/prerendered-state-persistence.md @@ -0,0 +1,355 @@ +--- +title: ASP.NET Core Blazor prerendered state persistence +author: guardrex +description: Learn how to persist user data (state) in Blazor apps using Blazor's Persistent Component State service. +monikerRange: '>= aspnetcore-8.0' +ms.author: wpickett +ms.custom: mvc +ms.date: 08/05/2025 +uid: blazor/state-management/prerendered-state-persistence +--- +# ASP.NET Core Blazor prerendered state persistence + +Without persisting component state, state used during prerendering is lost and must be recreated when the app is fully loaded. If any state is created asynchronously, the UI may flicker as the prerendered UI is replaced when the component is rerendered. + +Consider the following `PrerenderedCounter1` counter component. The component sets an initial random counter value during prerendering in [`OnInitialized` lifecycle method](xref:blazor/components/lifecycle#component-initialization-oninitializedasync). When the component then renders interactively, the initial count value is replaced when `OnInitialized` executes a second time. + +`PrerenderedCounter1.razor`: + +:::code language="razor" source="~/../blazor-samples/8.0/BlazorSample_BlazorWebApp/Components/Pages/PrerenderedCounter1.razor"::: + +> [!NOTE] +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the `PrerenderedCounter1` component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. + +Run the app and inspect logging from the component. The following is example output. + +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter1[0]"::: +> :::no-loc text=" currentCount set to 41"::: +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter1[0]"::: +> :::no-loc text=" currentCount set to 92"::: + +The first logged count occurs during prerendering. The count is set again after prerendering when the component is rerendered. There's also a flicker in the UI when the count updates from 41 to 92. + +To retain the initial value of the counter during prerendering, Blazor supports persisting state in a prerendered page using the service (and for components embedded into pages or views of Razor Pages or MVC apps, the [Persist Component State Tag Helper](xref:mvc/views/tag-helpers/builtin-th/persist-component-state-tag-helper)). + +:::moniker range=">= aspnetcore-10.0" + + + +To preserve prerendered state, use the `[SupplyParameterFromPersistentComponentState]` attribute to persist state in properties. Properties with this attribute are automatically persisted using the service during prerendering. The state is retrieved when the component renders interactively or the service is instantiated. + +By default, properties are serialized using the serializer with default settings and persisted in the prerendered HTML. Serialization isn't trimmer safe and requires preservation of the types used. For more information, see . + +The following counter component persists counter state during prerendering and retrieves the state to initialize the component: + +* The `[SupplyParameterFromPersistentComponentState]` attribute is applied to the `CounterState` type (`State`). +* The counter's state is assigned when `null` in `OnInitialized` and restored automatically when the component renders interactively. + +`PrerenderedCounter2.razor`: + +```razor +@page "/prerendered-counter-2" +@inject ILogger Logger + +Prerendered Counter 2 + +

Prerendered Counter 2

+ +

Current count: @State?.CurrentCount

+ + + +@code { + [SupplyParameterFromPersistentComponentState] + public CounterState? State { get; set; } + + protected override void OnInitialized() + { + if (State is null) + { + State = new() { CurrentCount = Random.Shared.Next(100) }; + Logger.LogInformation("CurrentCount set to {Count}", + State.CurrentCount); + } + else + { + Logger.LogInformation("CurrentCount restored to {Count}", + State.CurrentCount); + } + } + + private void IncrementCount() + { + if (State is not null) + { + State.CurrentCount++; + } + } + + public class CounterState + { + public int CurrentCount { get; set; } + } +} +``` + + + +When the component executes, `CurrentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. + +> [!NOTE] +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. + +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: +> :::no-loc text=" CurrentCount set to 96"::: +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: +> :::no-loc text=" CurrentCount restored to 96"::: + +In the following example that serializes state for multiple components of the same type: + +* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized during prerendering. +* The [`@key` directive attribute](xref:blazor/components/key#use-of-the-key-directive-attribute) is used to ensure that the state is correctly associated with the component instance. +* The `Element` property is initialized in the [`OnInitialized` lifecycle method](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) to avoid null reference exceptions, similarly to how null references are avoided for query parameters and form data. + +`PersistentChild.razor`: + +```razor +
+

Current count: @Element.CurrentCount

+ +
+ +@code { + [SupplyParameterFromPersistentComponentState] + public State Element { get; set; } + + protected override void OnInitialized() + { + Element ??= new State(); + } + + private void IncrementCount() + { + Element.CurrentCount++; + } + + private class State + { + public int CurrentCount { get; set; } + } +} +``` + +`Parent.razor`: + +```razor +@page "/parent" + +@foreach (var element in elements) +{ + +} +``` + +In the following example that serializes state for a dependency injection service: + +* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized during prerendering and deserialized when the app becomes interactive. +* The extension method is used to register the service for persistence. The render mode is required because the render mode can't be inferred from the service type. Use any of the following values: + * `RenderMode.Server`: The service is available for the Interactive Server render mode. + * `RenderMode.Webassembly`: The service is available for the Interactive Webassembly render mode. + * `RenderMode.InteractiveAuto`: The service is available for both the Interactive Server and Interactive Webassembly render modes if a component renders in either of those modes. +* The service is resolved during the initialization of an interactive render mode, and the properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are deserialized. + +> [!NOTE] +> Only persisting scoped services is supported. + + + +`CounterService.cs`: + +```csharp +public class CounterService +{ + [SupplyParameterFromPersistentComponentState] + public int CurrentCount { get; set; } + + public void IncrementCount() + { + CurrentCount++; + } +} +``` + +In `Program.cs`: + +```csharp +builder.Services.RegisterPersistentService( + RenderMode.InteractiveAuto); +``` + +Serialized properties are identified from the actual service instance: + +* This approach allows marking an abstraction as a persistent service. +* Enables actual implementations to be internal or different types. +* Supports shared code in different assemblies. +* Results in each instance exposing the same properties. + +As an alternative to using the declarative model for persisting state with the `[SupplyParameterFromPersistentComponentState]` attribute, you can use the service directly, which offers greater flexibility for complex state persistence scenarios. Call to register a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown. + +The following counter component example persists counter state during prerendering and retrieves the state to initialize the component. + +`PrerenderedCounter3.razor`: + +```razor +@page "/prerendered-counter-3" +@implements IDisposable +@inject ILogger Logger +@inject PersistentComponentState ApplicationState + +Prerendered Counter 3 + +

Prerendered Counter 3

+ +

Current count: @currentCount

+ + + +@code { + private int currentCount; + private PersistingComponentStateSubscription persistingSubscription; + + protected override void OnInitialized() + { + if (!ApplicationState.TryTakeFromJson( + nameof(currentCount), out var restoredCount)) + { + currentCount = Random.Shared.Next(100); + Logger.LogInformation("currentCount set to {Count}", currentCount); + } + else + { + currentCount = restoredCount!; + Logger.LogInformation("currentCount restored to {Count}", currentCount); + } + + // Call at the end to avoid a potential race condition at app shutdown + persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount); + } + + private Task PersistCount() + { + ApplicationState.PersistAsJson(nameof(currentCount), currentCount); + + return Task.CompletedTask; + } + + private void IncrementCount() => currentCount++; + + void IDisposable.Dispose() => persistingSubscription.Dispose(); +} +``` + +When the component executes, `currentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. + +> [!NOTE] +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. + +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter3[0]"::: +> :::no-loc text=" currentCount set to 96"::: +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter3[0]"::: +> :::no-loc text=" currentCount restored to 96"::: + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +To preserve prerendered state, decide what state to persist using the service. registers a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown. + +The following counter component example persists counter state during prerendering and retrieves the state to initialize the component. + +`PrerenderedCounter2.razor`: + +:::code language="razor" source="~/../blazor-samples/8.0/BlazorSample_BlazorWebApp/Components/Pages/PrerenderedCounter2.razor"::: + +When the component executes, `currentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output. + +> [!NOTE] +> If the app adopts [interactive routing](xref:blazor/fundamentals/routing#static-versus-interactive-routing) and the page is reached via an internal [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling), prerendering doesn't occur. Therefore, you must perform a full page reload for the component to see the following output. For more information, see the [Interactive routing and prerendering](#interactive-routing-and-prerendering) section. + +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: +> :::no-loc text=" currentCount set to 96"::: +> :::no-loc text="info: BlazorSample.Components.Pages.PrerenderedCounter2[0]"::: +> :::no-loc text=" currentCount restored to 96"::: + +:::moniker-end + +By initializing components with the same state used during prerendering, any expensive initialization steps are only executed once. The rendered UI also matches the prerendered UI, so no flicker occurs in the browser. + +The persisted prerendered state is transferred to the client, where it's used to restore the component state. During client-side rendering (CSR, `InteractiveWebAssembly`), the data is exposed to the browser and must not contain sensitive, private information. During interactive server-side rendering (interactive SSR, `InteractiveServer`), [ASP.NET Core Data Protection](xref:security/data-protection/introduction) ensures that the data is transferred securely. The `InteractiveAuto` render mode combines WebAssembly and Server interactivity, so it's necessary to consider data exposure to the browser, as in the CSR case. + +## Components embedded into pages and views (Razor Pages/MVC) + +For components embedded into a page or view of a Razor Pages or MVC app, you must add the [Persist Component State Tag Helper](xref:mvc/views/tag-helpers/builtin-th/persist-component-state-tag-helper) with the `` HTML tag inside the closing `` tag of the app's layout. **This is only required for Razor Pages and MVC apps.** For more information, see . + +`Pages/Shared/_Layout.cshtml`: + +```cshtml + + ... + + + +``` + +## Interactive routing and prerendering + +When the `Routes` component doesn't define a render mode, the app is using per-page/component interactivity and navigation. Using per-page/component navigation, internal navigation is handled by [enhanced routing](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) after the app becomes interactive. "Internal navigation" in this context means that the URL destination of the navigation event is a Blazor endpoint inside the app. + + + +The service only works on the initial page load and not across internal enhanced page navigation events. + +If the app performs a full (non-enhanced) navigation to a page utilizing persistent component state, the persisted state is made available for the app to use when it becomes interactive. + +If an interactive circuit has already been established and an enhanced navigation is performed to a page utilizing persistent component state, the state *isn't made available in the existing circuit for the component to use*. There's no prerendering for the internal page request, and the service isn't aware that an enhanced navigation has occurred. There's no mechanism to deliver state updates to components that are already running on an existing circuit. The reason for this is that Blazor only supports passing state from the server to the client at the time the runtime initializes, not after the runtime has started. + +Disabling enhanced navigation, which reduces performance but also avoids the problem of loading state with for internal page requests, is covered in . diff --git a/aspnetcore/blazor/state-management/protected-browser-storage.md b/aspnetcore/blazor/state-management/protected-browser-storage.md new file mode 100644 index 000000000000..d902a82aabfd --- /dev/null +++ b/aspnetcore/blazor/state-management/protected-browser-storage.md @@ -0,0 +1,499 @@ +--- +title: ASP.NET Core Blazor state management using protected browser storage +author: guardrex +description: Learn how to persist user data (state) in Blazor apps using browser storage. +monikerRange: '>= aspnetcore-3.1' +ms.author: wpickett +ms.custom: mvc +ms.date: 08/05/2025 +uid: blazor/state-management/protected-browser-storage +--- +# ASP.NET Core Blazor protected browser storage + +For transient data that the user is actively creating, a commonly used storage location is the browser's [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage) collections: + +* `localStorage` is scoped to the browser's instance. If the user reloads the page or closes and reopens the browser, the state persists. If the user opens multiple browser tabs, the state is shared across the tabs. Data persists in `localStorage` until explicitly cleared. The `localStorage` data for a document loaded in a "private browsing" or "incognito" session is cleared when the last "private" tab is closed. +* `sessionStorage` is scoped to the browser tab. If the user reloads the tab, the state persists. If the user closes the tab or the browser, the state is lost. If the user opens multiple browser tabs, each tab has its own independent version of the data. + +Generally, `sessionStorage` is safer to use. `sessionStorage` avoids the risk that a user opens multiple tabs and encounters the following: + +* Bugs in state storage across tabs. +* Confusing behavior when a tab overwrites the state of other tabs. + +`localStorage` is the better choice if the app must persist state across closing and reopening the browser. + +Caveats for using browser storage: + +* Similar to the use of a server-side database, loading and saving data are asynchronous. +* The requested page doesn't exist in the browser during prerendering, so local storage isn't available during prerendering. +* Storage of a few kilobytes of data is reasonable to persist for server-side Blazor apps. Beyond a few kilobytes, you must consider the performance implications because the data is loaded and saved across the network. +* Users may view or tamper with the data. [ASP.NET Core Data Protection](xref:security/data-protection/introduction) can mitigate the risk. For example, [ASP.NET Core Protected Browser Storage](#aspnet-core-protected-browser-storage) uses ASP.NET Core Data Protection. + +Third-party NuGet packages provide APIs for working with `localStorage` and `sessionStorage`. It's worth considering choosing a package that transparently uses [ASP.NET Core Data Protection](xref:security/data-protection/introduction). Data Protection encrypts stored data and reduces the potential risk of tampering with stored data. If JSON-serialized data is stored in plain text, users can see the data using browser developer tools and also modify the stored data. Securing trivial data isn't a problem. For example, reading or modifying the stored color of a UI element isn't a significant security risk to the user or the organization. Avoid allowing users to inspect or tamper with *sensitive data*. + +## ASP.NET Core Protected Browser Storage + +ASP.NET Core Protected Browser Storage leverages [ASP.NET Core Data Protection](xref:security/data-protection/introduction) for [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage). + +:::moniker range=">= aspnetcore-5.0" + +> [!NOTE] +> Protected Browser Storage relies on ASP.NET Core Data Protection and is only supported for server-side Blazor apps. + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +> [!WARNING] +> `Microsoft.AspNetCore.ProtectedBrowserStorage` is an unsupported, experimental package that isn't intended for production use. +> +> The package is only available for use in ASP.NET Core 3.1 apps. + +## Configuration + +1. Add a package reference to [`Microsoft.AspNetCore.ProtectedBrowserStorage`](https://www.nuget.org/packages/Microsoft.AspNetCore.ProtectedBrowserStorage). + + [!INCLUDE[](~/includes/package-reference.md)] + +1. In the `_Host.cshtml` file, add the following script inside the closing `` tag: + + ```cshtml + + ``` + +1. In `Startup.ConfigureServices`, call `AddProtectedBrowserStorage` to add `localStorage` and `sessionStorage` services to the service collection: + + ```csharp + services.AddProtectedBrowserStorage(); + ``` + +:::moniker-end + +## Save and load data within a component + +In any component that requires loading or saving data to browser storage, use the [`@inject`](xref:mvc/views/razor#inject) directive to inject an instance of either of the following: + +* `ProtectedLocalStorage` +* `ProtectedSessionStorage` + +The choice depends on which browser storage location you wish to use. In the following example, `sessionStorage` is used: + +:::moniker range=">= aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inject ProtectedSessionStorage ProtectedSessionStore +``` + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.ProtectedBrowserStorage +@inject ProtectedSessionStorage ProtectedSessionStore +``` + +:::moniker-end + +The `@using` directive can be placed in the app's `_Imports.razor` file instead of in the component. Use of the `_Imports.razor` file makes the namespace available to larger segments of the app or the whole app. + +To persist the `currentCount` value in the `Counter` component of an app based on the [Blazor project template](xref:blazor/project-structure), modify the `IncrementCount` method to use `ProtectedSessionStore.SetAsync`: + +```csharp +private async Task IncrementCount() +{ + currentCount++; + await ProtectedSessionStore.SetAsync("count", currentCount); +} +``` + +In larger, more realistic apps, storage of individual fields is an unlikely scenario. Apps are more likely to store entire model objects that include complex state. `ProtectedSessionStore` automatically serializes and deserializes JSON data to store complex state objects. + +In the preceding code example, the `currentCount` data is stored as `sessionStorage['count']` in the user's browser. The data isn't stored in plain text but rather is protected using ASP.NET Core Data Protection. The encrypted data can be inspected if `sessionStorage['count']` is evaluated in the browser's developer console. + +To recover the `currentCount` data if the user returns to the `Counter` component later, including if the user is on a new circuit, use `ProtectedSessionStore.GetAsync`: + +:::moniker range=">= aspnetcore-5.0" + +```csharp +protected override async Task OnInitializedAsync() +{ + var result = await ProtectedSessionStore.GetAsync("count"); + currentCount = result.Success ? result.Value : 0; +} +``` + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +```csharp +protected override async Task OnInitializedAsync() +{ + currentCount = await ProtectedSessionStore.GetAsync("count"); +} +``` + +:::moniker-end + +If the component's parameters include navigation state, call `ProtectedSessionStore.GetAsync` and assign a non-`null` result in , not . is only called once when the component is first instantiated. isn't called again later if the user navigates to a different URL while remaining on the same page. For more information, see . + +> [!WARNING] +> The examples in this section only work if the server doesn't have prerendering enabled. With prerendering enabled, an error is generated explaining that JavaScript interop calls cannot be issued because the component is being prerendered. +> +> Either disable prerendering or add additional code to work with prerendering. To learn more about writing code that works with prerendering, see the [Handle prerendering](#handle-prerendering) section. + +## Handle the loading state + +Since browser storage is accessed asynchronously over a network connection, there's always a period of time before the data is loaded and available to a component. For the best results, render a message while loading is in progress instead of displaying blank or default data. + +:::moniker range=">= aspnetcore-6.0" + +One approach is to track whether the data is `null`, which means that the data is still loading. In the default `Counter` component, the count is held in an `int`. [Make `currentCount` nullable](/dotnet/csharp/language-reference/builtin-types/nullable-value-types) by adding a question mark (`?`) to the type (`int`): + +```csharp +private int? currentCount; +``` + +Instead of unconditionally displaying the count and **`Increment`** button, display these elements only if the data is loaded by checking : + +```razor +@if (currentCount.HasValue) +{ +

Current count: @currentCount

+ +} +else +{ +

Loading...

+} +``` + +:::moniker-end + +## Handle prerendering + +During prerendering: + +* An interactive connection to the user's browser doesn't exist. +* The browser doesn't yet have a page in which it can run JavaScript code. + +`localStorage` or `sessionStorage` aren't available during prerendering. If the component attempts to interact with storage, an error is generated explaining that JavaScript interop calls cannot be issued because the component is being prerendered. + +One way to resolve the error is to disable prerendering. This is usually the best choice if the app makes heavy use of browser-based storage. Prerendering adds complexity and doesn't benefit the app because the app can't prerender any useful content until `localStorage` or `sessionStorage` are available. + +:::moniker range=">= aspnetcore-8.0" + +To disable prerendering, indicate the render mode with the `prerender` parameter set to `false` at the highest-level component in the app's component hierarchy that isn't a root component. + +> [!NOTE] +> Making a root component interactive, such as the `App` component, isn't supported. Therefore, prerendering can't be disabled directly by the `App` component. + +For apps based on the Blazor Web App project template, prerendering is typically disabled where the `Routes` component is used in the `App` component (`Components/App.razor`): + +```razor + +``` + +Also, disable prerendering for the `HeadOutlet` component: + +```razor + +``` + +For more information, see . + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + +To disable prerendering, open the `_Host.cshtml` file and change the `render-mode` attribute of the [Component Tag Helper](xref:mvc/views/tag-helpers/builtin-th/component-tag-helper) to : + +```cshtml + +``` + +:::moniker-end + +:::moniker range=">= aspnetcore-6.0" + +When prerendering is disabled, [prerendering of `` content](xref:blazor/components/control-head-content) is disabled. + +:::moniker-end + +Prerendering might be useful for other pages that don't use `localStorage` or `sessionStorage`. To retain prerendering, defer the loading operation until the browser is connected to the circuit. The following is an example for storing a counter value: + +:::moniker range=">= aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inject ProtectedLocalStorage ProtectedLocalStore + +@if (isConnected) +{ +

Current count: @currentCount

+ +} +else +{ +

Loading...

+} + +@code { + private int currentCount; + private bool isConnected; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + isConnected = true; + await LoadStateAsync(); + StateHasChanged(); + } + } + + private async Task LoadStateAsync() + { + var result = await ProtectedLocalStore.GetAsync("count"); + currentCount = result.Success ? result.Value : 0; + } + + private async Task IncrementCount() + { + currentCount++; + await ProtectedLocalStore.SetAsync("count", currentCount); + } +} +``` + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.ProtectedBrowserStorage +@inject ProtectedLocalStorage ProtectedLocalStore + +@if (isConnected) +{ +

Current count: @currentCount

+ +} +else +{ +

Loading...

+} + +@code { + private int currentCount = 0; + private bool isConnected = false; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + isConnected = true; + await LoadStateAsync(); + StateHasChanged(); + } + } + + private async Task LoadStateAsync() + { + currentCount = await ProtectedLocalStore.GetAsync("count"); + } + + private async Task IncrementCount() + { + currentCount++; + await ProtectedLocalStore.SetAsync("count", currentCount); + } +} +``` + +:::moniker-end + +## Factor out state preservation to a common provider + +If many components rely on browser-based storage, implementing state provider code many times creates code duplication. One option for avoiding code duplication is to create a *state provider parent component* that encapsulates the state provider logic. Child components can work with persisted data without regard to the state persistence mechanism. + +In the following example of a `CounterStateProvider` component, counter data is persisted to `sessionStorage`, and it handles the loading phase by not rendering its child content until state loading is complete. + +The `CounterStateProvider` component deals with prerendering by not loading state until after component rendering in the [`OnAfterRenderAsync` lifecycle method](xref:blazor/components/lifecycle#after-component-render-onafterrenderasync), which doesn't execute during prerendering. + +The approach in this section isn't capable of triggering rerendering of multiple subscribed components on the same page. If one subscribed component changes the state, it rerenders and can display the updated state, but a different component on the same page displaying that state displays stale data until its own next rerender. Therefore, the approach described in this section is best suited to using state in a single component on the page. + +`CounterStateProvider.razor`: + +:::moniker range=">= aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inject ProtectedSessionStorage ProtectedSessionStore + +@if (isLoaded) +{ + + @ChildContent + +} +else +{ +

Loading...

+} + +@code { + private bool isLoaded; + + [Parameter] + public RenderFragment? ChildContent { get; set; } + + public int CurrentCount { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + isLoaded = true; + await LoadStateAsync(); + StateHasChanged(); + } + } + + private async Task LoadStateAsync() + { + var result = await ProtectedSessionStore.GetAsync("count"); + CurrentCount = result.Success ? result.Value : 0; + isLoaded = true; + } + + public async Task IncrementCount() + { + CurrentCount++; + await ProtectedSessionStore.SetAsync("count", CurrentCount); + } +} +``` + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +```razor +@using Microsoft.AspNetCore.ProtectedBrowserStorage +@inject ProtectedSessionStorage ProtectedSessionStore + +@if (isLoaded) +{ + + @ChildContent + +} +else +{ +

Loading...

+} + +@code { + private bool isLoaded; + + [Parameter] + public RenderFragment ChildContent { get; set; } + + public int CurrentCount { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + isLoaded = true; + await LoadStateAsync(); + StateHasChanged(); + } + } + + private async Task LoadStateAsync() + { + CurrentCount = await ProtectedSessionStore.GetAsync("count"); + isLoaded = true; + } + + public async Task IncrementCount() + { + CurrentCount++; + await ProtectedSessionStore.SetAsync("count", CurrentCount); + } +} +``` + +:::moniker-end + +> [!NOTE] +> For more information on , see . + +:::moniker range=">= aspnetcore-8.0" + +To make the state accessible to all components in an app, wrap the `CounterStateProvider` component around the (`...`) in the `Routes` component with global interactive server-side rendering (interactive SSR). + +In the `App` component (`Components/App.razor`): + +```razor + +``` + +In the `Routes` component (`Components/Routes.razor`): + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + +To use the `CounterStateProvider` component, wrap an instance of the component around any other component that requires access to the counter state. To make the state accessible to all components in an app, wrap the `CounterStateProvider` component around the in the `App` component (`App.razor`): + +:::moniker-end + +```razor + + + ... + + +``` + +:::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" + +[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)] + +:::moniker-end + +Wrapped components receive and can modify the persisted counter state. The following `Counter` component implements the pattern: + +```razor +@page "/counter" + +

Current count: @CounterStateProvider?.CurrentCount

+ + +@code { + [CascadingParameter] + private CounterStateProvider? CounterStateProvider { get; set; } + + private async Task IncrementCount() + { + if (CounterStateProvider is not null) + { + await CounterStateProvider.IncrementCount(); + } + } +} +``` + +The preceding component isn't required to interact with `ProtectedBrowserStorage`, nor does it deal with a "loading" phase. + +In general, the *state provider parent component* pattern is recommended: + +* To consume state across many components. +* If there's just one top-level state object to persist. + +To persist many different state objects and consume different subsets of objects in different places, it's better to avoid persisting state globally. diff --git a/aspnetcore/blazor/state-management/server.md b/aspnetcore/blazor/state-management/server.md new file mode 100644 index 000000000000..fc340a5997f6 --- /dev/null +++ b/aspnetcore/blazor/state-management/server.md @@ -0,0 +1,235 @@ +--- +title: ASP.NET Core Blazor server-side state management +author: guardrex +description: Learn how to persist user data (state) in server-side Blazor apps. +monikerRange: '>= aspnetcore-3.1' +ms.author: wpickett +ms.custom: mvc +ms.date: 08/05/2025 +uid: blazor/state-management/server +--- +# ASP.NET Core Blazor server-side state management + +[!INCLUDE[](~/includes/not-latest-version.md)] + +This article describes common approaches for maintaining a user's data (state) in server-side Blazor scenarios. + +## Maintain user state + +Server-side Blazor is a stateful app framework. Most of the time, the app maintains a connection to the server. The user's state is held in the server's memory in a *circuit*. + +Examples of user state held in a circuit include: + +* The hierarchy of component instances and their most recent render output in the rendered UI. +* The values of fields and properties in component instances. +* Data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances that are scoped to the circuit. + +User state might also be found in JavaScript variables in the browser's memory set via [JavaScript interop](xref:blazor/js-interop/call-javascript-from-dotnet) calls. + +If a user experiences a temporary network connection loss, Blazor attempts to reconnect the user to their original circuit with their original state. However, reconnecting a user to their original circuit in the server's memory isn't always possible: + +* The server can't retain a disconnected circuit forever. The server must release a disconnected circuit after a timeout or when the server is under memory pressure. +* In multi-server, load-balanced deployment environments, individual servers may fail or be automatically removed when no longer required to handle the overall volume of requests. The original server processing requests for a user may become unavailable when the user attempts to reconnect. +* The user might close and reopen their browser or reload the page, which removes any state held in the browser's memory. For example, JavaScript variable values set through JavaScript interop calls are lost. + +When a user can't be reconnected to their original circuit, the user receives a new circuit with newly initialized state. This is equivalent to closing and reopening a desktop app. + +## When to persist user state + +State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. + +Generally, maintain state across circuits where users are actively creating data, not simply reading data that already exists. + +Data persistence is typically only required for high-value state that users expended effort to create. Persisting state either saves time or aids in commercial activities: + +* Multi-step web forms: It's time-consuming for a user to re-enter data for several completed steps of a multi-step web form if their state is lost. A user loses state in this scenario if they navigate away from the form and return later. +* Shopping carts: Any commercially important component of an app that represents potential revenue can be maintained. A user who loses their state, and thus their shopping cart, may purchase fewer products or services when they return to the website later. + +An app can only persist *app state*. UIs can't be persisted, such as component instances and their render trees. Components and render trees aren't generally serializable. To persist UI state, such as the expanded nodes of a tree view control, the app must use custom code to model the behavior of the UI state as serializable app state. + +:::moniker range=">= aspnetcore-10.0" + +## Circuit state persistence + +During server-side rendering, Blazor Web Apps can persist a user's session (circuit) state when the connection to the server is lost for an extended period of time or proactively paused, as long as a full-page refresh isn't triggered. This allows users to resume their session without losing unsaved work in the following scenarios: + +* Browser tab throttling +* Mobile device users switching apps +* Network interruptions +* Proactive resource management (pausing inactive circuits) + + + +*[Enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) with circuit state persistence isn't currently supported but planned for a future release.* + +Server resources can be freed up if the circuit state can be persisted and then resumed later: + +* Even if disconnected, a circuit might continue to perform work and consume CPU, memory, and other resources. Persisted state only consumes a fixed amount of memory that the developer controls. +* Persisted state represents a subset of the memory consumed by the app, so the server isn't required to keep track of the app's components and other server-side objects. + +State is persisted for two scenarios: + +* Component state: State that components use for Interactive Server rendering, for example, a list of items retrieved from the database or a form that the user is filling out. +* Scoped services: State held inside of a server-side service, for example, the current user. + +Conditions: + +* The feature is only effective for Interactive Server rendering. +* If the user refreshes the page (app), the persisted state is lost. +* The state must be JSON serializable. Cyclic references or ORM entities may not serialize correctly. +* Use `@key` for uniqueness when rendering components in a loop to avoid key conflicts. +* Persist only necessary state. Storing excessive data may impact performance. +* No automatic hibernation. You must opt-in and configure state persistence explicitly. +* No guarantee of recovery. If state persistence fails, the app falls back to the default disconnected experience. + +State persistence is enabled by default when is called on in the `Program` file. is the default storage implementation for single app instances and stores up to 1,000 persisted circuits for two hours, which are configurable. + +Use the following options to change the default values of the in-memory provider: + +* `PersistedCircuitInMemoryMaxRetained` (`{CIRCUIT COUNT}` placeholder): The maximum number of circuits to retain. The default is 1,000 circuits. For example, use `2000` to retain state for up to 2,000 circuits. +* `PersistedCircuitInMemoryRetentionPeriod` (`{RETENTION PERIOD}` placeholder): The maximum retention period as a . The default is two hours. For example, use `TimeSpan.FromHours(3)` for a three-hour retention period. + +```csharp +services.Configure(options => +{ + options.PersistedCircuitInMemoryMaxRetained = {CIRCUIT COUNT}; + options.PersistedCircuitInMemoryRetentionPeriod = {RETENTION PERIOD}; +}); +``` + +Persisting component state across circuits is built on top of the existing API, which continues to persist state for prerendered components that adopt an interactive render mode. For more information, see . + +> [NOTE] +> Persisting component state for prerendering works for any interactive render mode, but circuit state persistence only works for the **Interactive Server** render mode. + +Annotate component properties with `[SupplyParameterFromPersistentComponentState]` to enable circuit state persistence. The following example also keys the items with the [`@key` directive attribute](xref:blazor/components/key) to provide a unique identifier for each component instance: + +```razor +@foreach (var item in Items) +{ + +} + +@code { + [SupplyParameterFromPersistentComponentState] + public List Items { get; set; } + + protected override async Task OnInitializedAsync() + { + Items ??= await LoadItemsAsync(); + } +} +``` + +To persist state for scoped services, annotate service properties with `[SupplyParameterFromPersistentComponentState]`, add the service to the service collection, and call the extension method with the service: + +```csharp +public class CustomUserService +{ + [SupplyParameterFromPersistentComponentState] + public string UserData { get; set; } +} + +services.AddScoped(); + +services.AddRazorComponents() + .AddInteractiveServerComponents() + .RegisterPersistentService(RenderMode.InteractiveAuto); +``` + +> [NOTE] +> The preceding example persists `UserData` state when the service is used in component prerendering for both Interactive Server and Interactive WebAssembly rendering because `RenderMode.InteractiveAuto` is specified to `RegisterPersistentService`. However, circuit state persistence is only available for the **Interactive Server** render mode. + +To handle distributed state persistence (and to act as the default state persistence mechanism when configured), assign a [`HybridCache`](xref:performance/caching/overview#hybridcache) (API: ) to the app, which configures its own persistence period (`PersistedCircuitDistributedRetentionPeriod`, eight hours by default). `HybridCache` is used because it provides a unified approach to distributed storage that doesn't require separate packages for each storage provider. + +In the following example, a is implemented with the [Redis](https://redis.io/) storage provider: + +```csharp +services.AddHybridCache() + .AddRedis("{CONNECTION STRING}"); + +services.AddRazorComponents() + .AddInteractiveServerComponents(); +``` + +In the preceding example, the `{CONNECTION STRING}` placeholder represents the Redis cache connection string, which should be provided using a secure approach, such as the [Secret Manager](xref:security/app-secrets#secret-manager) tool in the Development environment or [Azure Key Vault](/azure/key-vault/) with [Azure Managed Identities](/entra/identity/managed-identities-azure-resources/overview) for Azure-deployed apps in any environment. + +## Pause and resume circuits + +Pause and resume circuits to implement custom policies that improve the scalability of an app. + +Pausing a circuit stores details about the circuit in client-side browser storage and evicts the circuit, which frees server resources. Resuming the circuit establishes a new circuit and initializes it using the persisted state. + +From a JavaScript event handler: + +* Call `Blazor.pauseCircuit` to pause a circuit. +* Call `Blazor.resumeCircuit` to resume a circuit. + +The following example assumes that a circuit isn't required for an app that isn't visible: + +```javascript +window.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + Blazor.pauseCircuit(); + } else if (document.visibilityState === 'visible') { + Blazor.resumeCircuit(); + } +}); +``` + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +## Persist state across circuits + +Generally, maintain state across circuits where users are actively creating data, not simply reading data that already exists. + +To preserve state across circuits, the app must persist the data to some other storage location than the server's memory. State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. + +Data persistence is typically only required for high-value state that users expended effort to create. In the following examples, persisting state either saves time or aids in commercial activities: + +* Multi-step web forms: It's time-consuming for a user to re-enter data for several completed steps of a multi-step web form if their state is lost. A user loses state in this scenario if they navigate away from the form and return later. +* Shopping carts: Any commercially important component of an app that represents potential revenue can be maintained. A user who loses their state, and thus their shopping cart, may purchase fewer products or services when they return to the site later. + +An app can only persist *app state*. UIs can't be persisted, such as component instances and their render trees. Components and render trees aren't generally serializable. To persist UI state, such as the expanded nodes of a tree view control, the app must use custom code to model the behavior of the UI state as serializable app state. + +:::moniker-end + +## Server-side storage + +For permanent data persistence that spans multiple users and devices, the app can use server-side storage. Options include: + +* Blob storage +* Key-value storage +* Relational database +* Table storage + +After data is saved, the user's state is retained and available in any new circuit. + +For more information on Azure data storage options, see the following: + +* [Azure Databases](https://azure.microsoft.com/product-categories/databases/) +* [Azure Storage Documentation](/azure/storage/) + +## Browser storage + +For more information, see . + +## Additional resources + +* [State management using the URL](xref:blazor/state-management/index#url) +* [In-memory state container service](xref:blazor/state-management/index#in-memory-state-container-service) +* [Cascading values and parameters](xref:blazor/state-management/index#cascading-values-and-parameters) +* [Managing state via an external server API](xref:blazor/call-web-api) diff --git a/aspnetcore/blazor/state-management/webassembly.md b/aspnetcore/blazor/state-management/webassembly.md new file mode 100644 index 000000000000..3d84d04d3863 --- /dev/null +++ b/aspnetcore/blazor/state-management/webassembly.md @@ -0,0 +1,78 @@ +--- +title: ASP.NET Core Blazor WebAssembly state management +author: guardrex +description: Learn how to persist user data (state) in Blazor WebAssembly apps. +monikerRange: '>= aspnetcore-3.1' +ms.author: wpickett +ms.custom: mvc +ms.date: 08/05/2025 +uid: blazor/state-management/webassembly +--- +# ASP.NET Core Blazor WebAssembly state management + +[!INCLUDE[](~/includes/not-latest-version.md)] + +This article describes common approaches for maintaining a user's data (state) in Blazor WebAssembly apps. + +## Maintain user state + +User state created in a Blazor WebAssembly app is held in the browser's memory. + +Examples of user state held in browser memory include: + +* The hierarchy of component instances and their most recent render output in the rendered UI. +* The values of fields and properties in component instances. +* Data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances. +* Values set through [JavaScript interop](xref:blazor/js-interop/call-javascript-from-dotnet) calls. + +When a user closes and reopens their browser or reloads the page, user state held in the browser's memory is lost. + +> [!NOTE] +> [Protected Browser Storage](xref:blazor/state-management/protected-browser-storage#aspnet-core-protected-browser-storage) ( namespace) relies on ASP.NET Core Data Protection and is only supported for server-side Blazor apps. + +## Persist state across browser sessions + +Generally, maintain state across browser sessions where users are actively creating data, not simply reading data that already exists. + +To preserve state across browser sessions, the app must persist the data to some other storage location than the browser's memory. State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. + +Data persistence is typically only required for high-value state that users expended effort to create. In the following examples, persisting state either saves time or aids in commercial activities: + +* Multi-step web forms: It's time-consuming for a user to re-enter data for several completed steps of a multi-step web form if their state is lost. A user loses state in this scenario if they navigate away from the form and return later. +* Shopping carts: Any commercially important component of an app that represents potential revenue can be maintained. A user who loses their state, and thus their shopping cart, may purchase fewer products or services when they return to the site later. + +An app can only persist *app state*. UIs can't be persisted, such as component instances and their render trees. Components and render trees aren't generally serializable. To persist UI state, such as the expanded nodes of a tree view control, the app must use custom code to model the behavior of the UI state as serializable app state. + +## Server-side storage + +For permanent data persistence that spans multiple users and devices, the app can use independent server-side storage accessed via a web API. Options include: + +* Blob storage +* Key-value storage +* Relational database +* Table storage + +After data is saved, the user's state is retained and available in any new browser session. + +Because Blazor WebAssembly apps run entirely in the user's browser, they require additional measures to access secure external systems, such as storage services and databases. Blazor WebAssembly apps are secured in the same manner as single-page applications (SPAs). Typically, an app authenticates a user via [OAuth](https://oauth.net)/[OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) and then interacts with storage services and databases through web API calls to a server-side app. The server-side app mediates the transfer of data between the Blazor WebAssembly app and the storage service or database. The Blazor WebAssembly app maintains an ephemeral connection to the server-side app, while the server-side app has a persistent connection to storage. + +For more information, see the following resources: + +* +* +* Blazor *Security and Identity* articles + +For more information on Azure data storage options, see the following: + +* [Azure Databases](https://azure.microsoft.com/product-categories/databases/) +* [Azure Storage Documentation](/azure/storage/) + +## Additional resources + +* [State management using the URL](xref:blazor/state-management/index#url) +* [In-memory state container service](xref:blazor/state-management/index#in-memory-state-container-service) +* [Cascading values and parameters](xref:blazor/state-management/index#cascading-values-and-parameters) +* [Save app state before an authentication operation (Blazor WebAssembly)](xref:blazor/security/webassembly/additional-scenarios#save-app-state-before-an-authentication-operation) +* Managing state via an external server API + * + * diff --git a/aspnetcore/client-side/using-grunt.md b/aspnetcore/client-side/using-grunt.md index db9b89f286e8..545f3909bad3 100644 --- a/aspnetcore/client-side/using-grunt.md +++ b/aspnetcore/client-side/using-grunt.md @@ -1,8 +1,8 @@ --- title: Use Grunt in ASP.NET Core -author: rick-anderson +author: wadepickett description: Use Grunt in ASP.NET Core -ms.author: riande +ms.author: wpickett ms.date: 12/05/2019 uid: client-side/using-grunt --- diff --git a/aspnetcore/diagnostics/asp0003.md b/aspnetcore/diagnostics/asp0003.md index 0b36cdda5478..39c58e85f360 100644 --- a/aspnetcore/diagnostics/asp0003.md +++ b/aspnetcore/diagnostics/asp0003.md @@ -3,7 +3,7 @@ title: "ASP0003: Do not use action results with route handlers" description: "Learn about analysis rule ASP0003: Do not use action results with route handlers" author: safia monikerRange: '>= aspnetcore-6.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0003 --- diff --git a/aspnetcore/diagnostics/asp0004.md b/aspnetcore/diagnostics/asp0004.md index f12d966111b9..b6cd988117ff 100644 --- a/aspnetcore/diagnostics/asp0004.md +++ b/aspnetcore/diagnostics/asp0004.md @@ -3,7 +3,7 @@ title: "ASP0004: Do not use action results with route handlers" description: "Learn about analysis rule ASP0004: Do not use action results with route handlers" author: safia monikerRange: '>= aspnetcore-6.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0004 --- diff --git a/aspnetcore/diagnostics/asp0005.md b/aspnetcore/diagnostics/asp0005.md index f872986c56f7..852521323767 100644 --- a/aspnetcore/diagnostics/asp0005.md +++ b/aspnetcore/diagnostics/asp0005.md @@ -3,7 +3,7 @@ title: "ASP0005: Do not place attribute on method called by route handler lambda description: "Learn about analysis rule ASP0005: Do not place attribute on method called by route handler lambda" author: safia monikerRange: '>= aspnetcore-6.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0005 --- diff --git a/aspnetcore/diagnostics/asp0006.md b/aspnetcore/diagnostics/asp0006.md index d5958ab51f38..6a3eb05d986d 100644 --- a/aspnetcore/diagnostics/asp0006.md +++ b/aspnetcore/diagnostics/asp0006.md @@ -3,7 +3,7 @@ title: "ASP0006: Do not use non-literal sequence numbers" description: "Learn about analysis rule ASP0006: Do not use non-literal sequence numbers" author: safia monikerRange: '>= aspnetcore-6.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0006 --- diff --git a/aspnetcore/diagnostics/asp0007.md b/aspnetcore/diagnostics/asp0007.md index 919653039f58..83372a4ea3a5 100644 --- a/aspnetcore/diagnostics/asp0007.md +++ b/aspnetcore/diagnostics/asp0007.md @@ -3,7 +3,7 @@ title: "ASP0007: Route parameter and argument optionality is mismatched" description: "Learn about analysis rule ASP0007: Route parameter and argument optionality is mismatched" author: safia monikerRange: '>= aspnetcore-6.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0007 --- diff --git a/aspnetcore/diagnostics/asp0013.md b/aspnetcore/diagnostics/asp0013.md index d8df9a45010e..4e4cfd82e68e 100644 --- a/aspnetcore/diagnostics/asp0013.md +++ b/aspnetcore/diagnostics/asp0013.md @@ -1,9 +1,9 @@ --- title: "ASP0013: Suggest switching from using Configure methods to WebApplicationBuilder.Configuration" description: "Learn about analysis rule ASP0013: Suggest switching from using Configure methods to WebApplicationBuilder.Configuration" -author: rick-anderson +author: wadepickett monikerRange: '>= aspnetcore-7.0' -ms.author: riande +ms.author: wpickett ms.date: 03/27/2025 uid: diagnostics/asp0013 --- diff --git a/aspnetcore/diagnostics/asp0027.md b/aspnetcore/diagnostics/asp0027.md index b81dbf10a5b8..582ed1282ccd 100644 --- a/aspnetcore/diagnostics/asp0027.md +++ b/aspnetcore/diagnostics/asp0027.md @@ -4,7 +4,7 @@ ms.date: 03/25/2025 description: "Learn about analysis rule ASP0027: Unnecessary public Program class declaration" author: benhopkinstech monikerRange: '>= aspnetcore-10.0' -ms.author: riande +ms.author: tdykstra uid: diagnostics/asp0027 --- # ASP0027: Unnecessary `public Program` class declaration diff --git a/aspnetcore/diagnostics/mvc1000.md b/aspnetcore/diagnostics/mvc1000.md index 4b606591549c..6d6013f7a3dd 100644 --- a/aspnetcore/diagnostics/mvc1000.md +++ b/aspnetcore/diagnostics/mvc1000.md @@ -3,7 +3,7 @@ title: "MVC1000: Avoid using IHtmlHelper.Partial" description: "Learn about analysis rule MVC1000: Use of IHtmlHelper.Partial should be avoided" author: pranavkm monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.date: 10/21/2021 uid: diagnostics/mvc1000 --- diff --git a/aspnetcore/diagnostics/mvc1004.md b/aspnetcore/diagnostics/mvc1004.md index 6dc0366da146..8c08eb5875cf 100644 --- a/aspnetcore/diagnostics/mvc1004.md +++ b/aspnetcore/diagnostics/mvc1004.md @@ -3,7 +3,7 @@ title: "MVC1004: Rename model bound parameter" description: "Learn about analysis rule MVC1004: Rename model bound parameter" author: pranavkm monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.date: 03/27/2025 uid: diagnostics/mvc1004 --- diff --git a/aspnetcore/diagnostics/mvc1005.md b/aspnetcore/diagnostics/mvc1005.md index 4386d3655388..b5785800ca6d 100644 --- a/aspnetcore/diagnostics/mvc1005.md +++ b/aspnetcore/diagnostics/mvc1005.md @@ -3,7 +3,7 @@ title: "MVC1005: Cannot use UseMvc with Endpoint Routing" description: "Learn about analysis rule MVC1005: Cannot use UseMvc with Endpoint Routing" author: pranavkm monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.date: 03/27/2025 uid: diagnostics/mvc1005 --- diff --git a/aspnetcore/docfx.json b/aspnetcore/docfx.json index 1fd423c6a6e4..f9bcc3176ff6 100644 --- a/aspnetcore/docfx.json +++ b/aspnetcore/docfx.json @@ -51,10 +51,8 @@ }, "fileMetadata": { "author": { - "whats-new/**/**.md": "wadepickett" }, "ms.author": { - "whats-new/**/**.md": "wpickett" }, "ms.subservice": { "introduction-to-aspnet-core.md": "index-page", @@ -75,7 +73,6 @@ "**/test/**/**.md": "testing", "**/tutorials/**/**.md": "tutorials", "**/web-api/**/**.md": "web-api", - "whats-new/**/**.md": "whats-new", "**/blazor/**/**.md": "blazor", "**/blazor/hybrid/**/**.md": "blazor-hybrid", "**/client-side/dotnet-interop/index.md": "blazor", diff --git a/aspnetcore/fundamentals/app-state.md b/aspnetcore/fundamentals/app-state.md index aaef80256af8..2f0ea7a1eb5c 100644 --- a/aspnetcore/fundamentals/app-state.md +++ b/aspnetcore/fundamentals/app-state.md @@ -15,7 +15,7 @@ By [Rick Anderson](https://twitter.com/RickAndMSFT), [Kirk Larkin](https://twitt HTTP is a stateless protocol. By default, HTTP requests are independent messages that don't retain user values. This article describes several approaches to preserve user data between requests. -For Blazor state management guidance, which adds to or supersedes the guidance in this article, see . +For Blazor state management guidance, which adds to or supersedes the guidance in this article, see . ## State management @@ -33,7 +33,17 @@ State can be stored using several approaches. Each approach is described later i ## SignalR/Blazor Server and HTTP context-based state management -[SignalR](xref:signalr/introduction) apps shouldn't use session state and other state management approaches that rely upon a stable HTTP context to store information. SignalR apps can store per-connection state in [`Context.Items` in the hub](xref:signalr/hubs). For more information and alternative state management approaches for Blazor Server apps, see . +[SignalR](xref:signalr/introduction) apps shouldn't use session state and other state management approaches that rely upon a stable HTTP context to store information. SignalR apps can store per-connection state in [`Context.Items` in the hub](xref:signalr/hubs). For more information and alternative state management approaches for Blazor Server apps, see and . + + ## Cookies @@ -313,7 +323,15 @@ State can be stored using several approaches. Each approach is described later i ## SignalR/Blazor Server and HTTP context-based state management -[SignalR](xref:signalr/introduction) apps shouldn't use session state and other state management approaches that rely upon a stable HTTP context to store information. SignalR apps can store per-connection state in [`Context.Items` in the hub](xref:signalr/hubs). For more information and alternative state management approaches for Blazor Server apps, see . +[SignalR](xref:signalr/introduction) apps shouldn't use session state and other state management approaches that rely upon a stable HTTP context to store information. SignalR apps can store per-connection state in [`Context.Items` in the hub](xref:signalr/hubs). For more information and alternative state management approaches for Blazor Server apps, see and . + + ## Cookies diff --git a/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-5-7.md b/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-5-7.md index 5cde84c3948c..68dadb621203 100644 --- a/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-5-7.md +++ b/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-5-7.md @@ -1,6 +1,6 @@ --- -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett ms.date: 04/01/2025 --- :::moniker range=">= aspnetcore-6.0 <= aspnetcore-7.0" diff --git a/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-8.md b/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-8.md index c833110f66fe..6087edac05a0 100644 --- a/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-8.md +++ b/aspnetcore/fundamentals/dependency-injection/includes/dependency-injection-8.md @@ -1,6 +1,6 @@ --- -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett ms.date: 8/17/2024 --- diff --git a/aspnetcore/fundamentals/http-logging/includes/index-6-7.md b/aspnetcore/fundamentals/http-logging/includes/index-6-7.md index 9e66494beb6c..3106488edd85 100644 --- a/aspnetcore/fundamentals/http-logging/includes/index-6-7.md +++ b/aspnetcore/fundamentals/http-logging/includes/index-6-7.md @@ -1,6 +1,6 @@ --- -author: rick-anderson -ms.author: riande +author: tdykstra +ms.author: tdykstra ms.date: 09/25/2024 --- diff --git a/aspnetcore/fundamentals/http-logging/index.md b/aspnetcore/fundamentals/http-logging/index.md index 37e539bad44e..901d37cca78f 100644 --- a/aspnetcore/fundamentals/http-logging/index.md +++ b/aspnetcore/fundamentals/http-logging/index.md @@ -212,7 +212,7 @@ The following list shows the order of precedence for logging configuration: Http logging with redaction can be enabled by calling : -[!code-csharp[](~/fundamentals/http-logging/samples/9.x/Program.cs?name=snippet7&highlight=9)] +[!code-csharp[](~/fundamentals/http-logging/samples-snapshot/9.x/Program.cs?name=snippet7&highlight=9)] For more information about .NET's data redaction library, see [Data redaction in .NET](/dotnet/core/extensions/data-redaction). diff --git a/aspnetcore/fundamentals/http-logging/samples-snapshot/9.x/Program.cs b/aspnetcore/fundamentals/http-logging/samples-snapshot/9.x/Program.cs new file mode 100644 index 000000000000..3af11c0693ef --- /dev/null +++ b/aspnetcore/fundamentals/http-logging/samples-snapshot/9.x/Program.cs @@ -0,0 +1,11 @@ +// +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddHttpLogging(logging => +{ + logging.LoggingFields = HttpLoggingFields.Duration; +}); + +builder.Services.AddRedaction(); +builder.Services.AddHttpLoggingRedaction(op => { }); +// diff --git a/aspnetcore/fundamentals/native-aot.md b/aspnetcore/fundamentals/native-aot.md index bb139e3dcd21..c93b84c1ef1e 100644 --- a/aspnetcore/fundamentals/native-aot.md +++ b/aspnetcore/fundamentals/native-aot.md @@ -1,7 +1,7 @@ --- title: ASP.NET Core support for Native AOT -author: rick-anderson -ms.author: riande +author: tdykstra +ms.author: tdykstra description: Learn about ASP.NET Core support for Native AOT content_well_notification: AI-contribution ms.custom: mvc, engagement-fy23 diff --git a/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md b/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md new file mode 100644 index 000000000000..cc1d7cf21ae9 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md @@ -0,0 +1,90 @@ +:::moniker range="= aspnetcore-9.0" + +## Use Swagger UI for local ad-hoc testing + +By default, the `Microsoft.AspNetCore.OpenApi` package doesn't ship with built-in support for visualizing or interacting with the OpenAPI document. Popular tools for visualizing or interacting with the OpenAPI document include [Swagger UI](https://swagger.io/tools/swaggerhub/) and [ReDoc](https://github.com/Redocly/redoc). Swagger UI and ReDoc can be integrated in an app in several ways. Editors such as Visual Studio and VS Code offer extensions and built-in experiences for testing against an OpenAPI document. + +The `Swashbuckle.AspNetCore.SwaggerUi` package provides a bundle of Swagger UI's web assets for use in apps. This package can be used to render a UI for the generated document. To configure this: + +* Install the `Swashbuckle.AspNetCore.SwaggerUi` package. +* Enable the swagger-ui middleware with a reference to the [OpenAPI route registered earlier](xref:fundamentals/openapi/aspnetcore-openapi#customize-the-openapi-endpoint-route). + +[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_swaggerui)] + +As a security best practice on limiting information disclosure, ***OpenAPI user interfaces (Swagger UI, ReDoc, Scalar) should only be enabled in development environments.*** For example, see [Swagger OAuth 2.0 configuration](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). + +Launch the app and navigate to `https://localhost:/swagger` to view the Swagger UI. + +To automatically launch the app at the Swagger UI URL using the `https` profile of `Properties/launchSettings.json`: + +* Confirm that `launchBrowser` is enabled (`true`). +* Set the `launchUrl` to `swagger`. + +```json +"launchBrowser": true, +"launchUrl": "swagger", +``` + +## Use Scalar for interactive API documentation + +[Scalar](https://scalar.com/) is an open-source interactive document UI for OpenAPI. Scalar can integrate with the OpenAPI endpoint provided by ASP.NET Core. To configure Scalar, install the `Scalar.AspNetCore` package. + +[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_openapiwithscalar)] + +Launch the app and navigate to `https://localhost:/scalar/v1` to view the Scalar UI. + +To automatically launch the app at the Scalar UI URL using the `https` profile of `Properties/launchSettings.json`: + +* Confirm that `launchBrowser` is enabled (`true`). +* Set the `launchUrl` to `scalar/v1`. + +```json +"launchBrowser": true, +"launchUrl": "scalar/v1", +``` + +## Lint generated OpenAPI documents with Spectral + +[Spectral](https://stoplight.io/open-source/spectral) is an open-source OpenAPI document linter. Spectral can be incorporated into an app build to verify the quality of generated OpenAPI documents. Install Spectral according to the [package installation directions](https://github.com/stoplightio/spectral#-installation). + +To take advantage of Spectral, install the `Microsoft.Extensions.ApiDescription.Server` package to enable build-time OpenAPI document generation. + +Enable document generation at build time by setting the following properties in the app's `.csproj` file": + +```xml + + $(MSBuildProjectDirectory) + true + +``` + +Run `dotnet build` to generate the document. + +```dotnetcli +dotnet build +``` + +Create a `.spectral.yml` file with the following contents. + +```text +extends: ["spectral:oas"] +``` + +Run `spectral lint` on the generated file. + +```dotnetcli +spectral lint WebMinOpenApi.json +... + +The output shows any issues with the OpenAPI document. For example: + +```output +1:1 warning oas3-api-servers OpenAPI "servers" must be present and non-empty array. +3:10 warning info-contact Info object must have "contact" object. info +3:10 warning info-description Info "description" must be present and non-empty string. info +9:13 warning operation-description Operation "description" must be present and non-empty string. paths./.get +9:13 warning operation-operationId Operation must have "operationId". paths./.get + +✖ 5 problems (0 errors, 5 warnings, 0 infos, 0 hints) +``` +:::moniker-end diff --git a/aspnetcore/fundamentals/openapi/using-openapi-documents.md b/aspnetcore/fundamentals/openapi/using-openapi-documents.md index 30e2bb19a1cc..e53730d2da32 100644 --- a/aspnetcore/fundamentals/openapi/using-openapi-documents.md +++ b/aspnetcore/fundamentals/openapi/using-openapi-documents.md @@ -5,16 +5,16 @@ description: Learn how to use OpenAPI documents in an ASP.NET Core app. ms.author: safia monikerRange: '>= aspnetcore-6.0' ms.custom: mvc -ms.date: 05/09/2025 +ms.date: 08/04/2025 uid: fundamentals/openapi/using-openapi-documents --- # Use openAPI documents -:::moniker range=">= aspnetcore-9.0" +:::moniker range=">= aspnetcore-10.0" ## Use Swagger UI for local ad-hoc testing -By default, the `Microsoft.AspNetCore.OpenApi` package doesn't ship with built-in support for visualizing or interacting with the OpenAPI document. Popular tools for visualizing or interacting with the OpenAPI document include [Swagger UI](https://swagger.io/tools/swaggerhub/) and [ReDoc](https://github.com/Redocly/redoc). Swagger UI and ReDoc can be integrated in an app in several ways. Editors such as Visual Studio and VS Code offer extensions and built-in experiences for testing against an OpenAPI document. +By default, the `Microsoft.AspNetCore.OpenApi` package doesn't ship with built-in support for visualizing or interacting with the OpenAPI document. Popular tools for visualizing or interacting with the OpenAPI document include [Swagger UI](https://swagger.io/tools/swaggerhub/) and [ReDoc](https://github.com/Redocly/redoc). Swagger UI and ReDoc can be integrated in an app in several ways. Editors such as Visual Studio and Visual Studio Code offer extensions and built-in experiences for testing against an OpenAPI document. The `Swashbuckle.AspNetCore.SwaggerUi` package provides a bundle of Swagger UI's web assets for use in apps. This package can be used to render a UI for the generated document. To configure this: @@ -59,7 +59,7 @@ To automatically launch the app at the Scalar UI URL using the `https` profile o [Spectral](https://stoplight.io/open-source/spectral) is an open-source OpenAPI document linter. Spectral can be incorporated into an app build to verify the quality of generated OpenAPI documents. Install Spectral according to the [package installation directions](https://github.com/stoplightio/spectral#-installation). -To take advantage of Spectral, install the `Microsoft.Extensions.ApiDescription.Server` package to enable build-time OpenAPI document generation. +To take advantage of Spectral for linting OpenAPI documents at build time, first install the `Microsoft.Extensions.ApiDescription.Server` package to enable build-time OpenAPI document generation. Enable document generation at build time by setting the following properties in the app's `.csproj` file": @@ -99,6 +99,38 @@ The output shows any issues with the OpenAPI document. For example: ✖ 5 problems (0 errors, 5 warnings, 0 infos, 0 hints) ``` + +## Support for injecting `IOpenApiDocumentProvider` + +You can inject `Microsoft.AspNetCore.OpenApi.Services.IOpenApiDocumentProvider` into your services through dependency injection to access OpenAPI documents programmatically, even outside HTTP request contexts. + +```csharp +public class DocumentService +{ + private readonly IOpenApiDocumentProvider _documentProvider; + + public DocumentService(IOpenApiDocumentProvider documentProvider) + { + _documentProvider = documentProvider; + } + + public async Task GetApiDocumentAsync() + { + return await _documentProvider.GetOpenApiDocumentAsync("v1"); + } +} +``` + +Register the service in your DI container: + +```csharp +builder.Services.AddScoped(); +``` + +This enables scenarios such as generating client SDKs, validating API contracts in background processes, or exporting documents to external systems. + +Support for injecting `IOpenApiDocumentProvider` was introduced in ASP.NET Core in .NET 10. For more information, see [dotnet/aspnetcore #61463](https://github.com/dotnet/aspnetcore/pull/61463). :::moniker-end [!INCLUDE[](~/fundamentals/openapi/includes/using-openapi-documents-6-8.md)] +[!INCLUDE[](~/fundamentals/openapi/includes/using-openapi-documents-9.md)] diff --git a/aspnetcore/fundamentals/servers/httpsys.md b/aspnetcore/fundamentals/servers/httpsys.md index ec06debdf3f7..a9ba0d75605f 100644 --- a/aspnetcore/fundamentals/servers/httpsys.md +++ b/aspnetcore/fundamentals/servers/httpsys.md @@ -5,7 +5,7 @@ description: Learn about HTTP.sys, a web server for ASP.NET Core on Windows. Bui monikerRange: '>= aspnetcore-2.1' ms.author: tdykstra ms.custom: mvc -ms.date: 06/13/2025 +ms.date: 08/04/2025 uid: fundamentals/servers/httpsys --- # HTTP.sys web server implementation in ASP.NET Core @@ -32,6 +32,7 @@ HTTP.sys supports the following features: * Response caching * WebSockets (Windows 8 or later) * Customizable security descriptors +* Automatic memory pool eviction Supported Windows versions: @@ -340,6 +341,8 @@ Requirements to run gRPC with HTTP.sys: For information about how to get traces from HTTP.sys, see [HTTP.sys Manageability Scenarios](/windows/win32/http/http-sys-manageability-scenarios). +[!INCLUDE[](includes/memory-eviction2.md)] + ## Additional resources * [Enable Windows Authentication with HTTP.sys](xref:security/authentication/windowsauth#httpsys) diff --git a/aspnetcore/fundamentals/servers/includes/memory-eviction2.md b/aspnetcore/fundamentals/servers/includes/memory-eviction2.md new file mode 100644 index 000000000000..2f7645e11a8a --- /dev/null +++ b/aspnetcore/fundamentals/servers/includes/memory-eviction2.md @@ -0,0 +1,26 @@ +## Automatic eviction from memory pool + +The memory pools used by Kestrel, IIS, and HTTP.sys automatically evict memory blocks when the application is idle or under low load. The feature runs automatically and doesn't need to be enabled or configured manually. + +In versions of .NET earlier than 10, memory allocated by the pool remains reserved, even when not in use. This automatic eviction feature reduces overall memory usage and helps applications stay responsive under varying workloads. + +### Use memory pool metrics + +The default memory pool used by the ASP.NET Core server implementations includes metrics, which can be used to monitor and analyze memory usage patterns. The metrics are under the name `"Microsoft.AspNetCore.MemoryPool"`. + +For information about metrics and how to use them, see . + +## Manage memory pools + +Besides using memory pools efficiently by evicting unneeded memory blocks, ASP.NET Core provides a built-in [IMemoryPoolFactory](https://source.dot.net/#Microsoft.AspNetCore.Connections.Abstractions/IMemoryPoolFactory.cs) and an implementation. It makes the implementation available to your application through dependency injection. + +The following code example shows a simple background service that uses the built-in memory pool factory implementation to create memory pools. These pools benefit from the automatic eviction feature: + +:::code language="csharp" source="~/fundamentals/servers/snippets/10.x/my-background-service.cs"::: + +To use a custom memory pool factory, make a class that implements `IMemoryPoolFactory` and register it with dependency injection, as the following example does. Memory pools created this way also benefit from the automatic eviction feature: + +:::code language="csharp" source="~/fundamentals/servers/snippets/10.x/memory-pool-factory.cs"::: + +When you're using a memory pool, be aware of the pool's . + diff --git a/aspnetcore/fundamentals/servers/kestrel.md b/aspnetcore/fundamentals/servers/kestrel.md index 7d9e2b6cbcdd..8d61fcdf606a 100644 --- a/aspnetcore/fundamentals/servers/kestrel.md +++ b/aspnetcore/fundamentals/servers/kestrel.md @@ -5,7 +5,7 @@ description: Learn about Kestrel, the cross-platform web server for ASP.NET Core monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra ms.custom: mvc -ms.date: 04/04/2023 +ms.date: 08/04/2023 uid: fundamentals/servers/kestrel --- # Kestrel web server in ASP.NET Core @@ -14,7 +14,7 @@ uid: fundamentals/servers/kestrel By [Tom Dykstra](https://github.com/tdykstra), [Chris Ross](https://github.com/Tratcher), and [Stephen Halter](https://twitter.com/halter73) -:::moniker range=">= aspnetcore-8.0" +:::moniker range=">= aspnetcore-10.0" Kestrel is a cross-platform [web server for ASP.NET Core](xref:fundamentals/servers/index). Kestrel is the recommended server for ASP.NET Core, and it's configured by default in ASP.NET Core project templates. @@ -33,6 +33,7 @@ Kestrel's features include: * Building a reverse proxy with [YARP](https://github.com/microsoft/reverse-proxy). * **Extensibility:** Customize Kestrel through configuration, middleware, and custom transports. * **Performance diagnostics:** Kestrel provides built-in performance diagnostics features, such as logging and metrics. +* **Memory management:** Kestrel includes features for efficient memory management, such as automatic eviction from memory pool. ## Get started @@ -58,6 +59,9 @@ The following timeouts and rate limits aren't enforced when a debugger is attach * * + +[!INCLUDE[](includes/memory-eviction2.md)] + ## Additional resources diff --git a/aspnetcore/fundamentals/servers/kestrel/includes/kestrel6.md b/aspnetcore/fundamentals/servers/kestrel/includes/kestrel6.md index d7641c9a06b1..24807fb25bd4 100644 --- a/aspnetcore/fundamentals/servers/kestrel/includes/kestrel6.md +++ b/aspnetcore/fundamentals/servers/kestrel/includes/kestrel6.md @@ -1,4 +1,4 @@ -:::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" +:::moniker range=">= aspnetcore-6.0 <=aspnetcore-9.0" Kestrel is a cross-platform [web server for ASP.NET Core](xref:fundamentals/servers/index). Kestrel is the web server that's included and enabled by default in ASP.NET Core project templates. diff --git a/aspnetcore/fundamentals/servers/snippets/10.x/memory-pool-factory.cs b/aspnetcore/fundamentals/servers/snippets/10.x/memory-pool-factory.cs new file mode 100644 index 000000000000..b27408d817e7 --- /dev/null +++ b/aspnetcore/fundamentals/servers/snippets/10.x/memory-pool-factory.cs @@ -0,0 +1,13 @@ +services.AddSingleton, +CustomMemoryPoolFactory>(); + +public class CustomMemoryPoolFactory : IMemoryPoolFactory +{ + public MemoryPool Create() + { + // Return a custom MemoryPool implementation + // or the default, as is shown here. + return MemoryPool.Shared; + } +} + diff --git a/aspnetcore/fundamentals/servers/snippets/10.x/my-background-service.cs b/aspnetcore/fundamentals/servers/snippets/10.x/my-background-service.cs new file mode 100644 index 000000000000..c92dd2457b0b --- /dev/null +++ b/aspnetcore/fundamentals/servers/snippets/10.x/my-background-service.cs @@ -0,0 +1,28 @@ +public class MyBackgroundService : BackgroundService +{ + private readonly MemoryPool _memoryPool; + + public MyBackgroundService(IMemoryPoolFactory factory) + { + _memoryPool = factory.Create(); + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + try + { + await Task.Delay(20, stoppingToken); + // do work that needs memory + // consider checking _memoryPool.MaxBufferSize + var rented = _memoryPool.Rent(100); + rented.Dispose(); + } + catch (OperationCanceledException) + { + return; + } + } + } +} diff --git a/aspnetcore/fundamentals/servers/yarp/config-providers.md b/aspnetcore/fundamentals/servers/yarp/config-providers.md index cd2a5b872e16..fa5f09c82f0c 100644 --- a/aspnetcore/fundamentals/servers/yarp/config-providers.md +++ b/aspnetcore/fundamentals/servers/yarp/config-providers.md @@ -2,8 +2,8 @@ uid: fundamentals/servers/yarp/config-providers title: YARP Extensibility Configuration Providers description: YARP Extensibility Configuration Providers -author: samsp-msft -ms.author: samsp +author: wadepickett +ms.author: wpickett ms.date: 2/6/2025 ms.topic: article content_well_notification: AI-contribution diff --git a/aspnetcore/fundamentals/static-files.md b/aspnetcore/fundamentals/static-files.md index 9db4ab9ac29f..98e8919953c0 100644 --- a/aspnetcore/fundamentals/static-files.md +++ b/aspnetcore/fundamentals/static-files.md @@ -1,9 +1,9 @@ --- title: Static files in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to serve and secure static files and configure static file hosting middleware behaviors in an ASP.NET Core web app. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 03/18/2025 uid: fundamentals/static-files diff --git a/aspnetcore/fundamentals/troubleshoot-aspnet-core-localization.md b/aspnetcore/fundamentals/troubleshoot-aspnet-core-localization.md index 1bdcb9f12911..ebb0a9ef5896 100644 --- a/aspnetcore/fundamentals/troubleshoot-aspnet-core-localization.md +++ b/aspnetcore/fundamentals/troubleshoot-aspnet-core-localization.md @@ -2,7 +2,7 @@ title: Troubleshoot ASP.NET Core localization author: hishamco description: Learn how to diagnose problems with localization in ASP.NET Core apps. -ms.author: riande +ms.author: tdykstra ms.date: 05/03/2024 uid: fundamentals/troubleshoot-aspnet-core-localization --- diff --git a/aspnetcore/fundamentals/url-rewriting.md b/aspnetcore/fundamentals/url-rewriting.md index 962e00c8bb80..3852d6c26e39 100644 --- a/aspnetcore/fundamentals/url-rewriting.md +++ b/aspnetcore/fundamentals/url-rewriting.md @@ -1,9 +1,9 @@ --- title: URL Rewriting Middleware in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn about URL rewriting and redirecting with URL Rewriting Middleware in ASP.NET Core applications. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc, sfi-image-nochange ms.date: 3/3/2022 uid: fundamentals/url-rewriting diff --git a/aspnetcore/grpc/interprocess-namedpipes.md b/aspnetcore/grpc/interprocess-namedpipes.md index 70e046df7e58..957c8ff22887 100644 --- a/aspnetcore/grpc/interprocess-namedpipes.md +++ b/aspnetcore/grpc/interprocess-namedpipes.md @@ -4,7 +4,8 @@ author: jamesnk description: Learn how to use gRPC for inter-process communication with Named pipes. monikerRange: '>= aspnetcore-8.0' ms.author: wpickett -ms.date: 01/18/2023 +ai-usage: ai-assisted +ms.date: 08/01/2025 uid: grpc/interprocess-namedpipes --- # Inter-process communication with gRPC and Named pipes @@ -47,6 +48,75 @@ The preceding example: * Calls `ListenNamedPipe` to listen to a named pipe with the specified name. * Creates a named pipe endpoint that isn't configured to use HTTPS. For information about enabling HTTPS, see [Kestrel HTTPS endpoint configuration](xref:fundamentals/servers/kestrel/endpoints#listenoptionsusehttps). +### Configuring PipeSecurity for Named Pipes + +To control which users or groups can connect, use the [`NamedPipeTransportOptions`](xref:Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.NamedPipeTransportOptions) class. This allows a custom [`PipeSecurity`](xref:System.IO.Pipes.PipeSecurity) object to be specified. + +Example: + +```csharp +using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes; +using System.IO.Pipes; +using System.Security.AccessControl; + +var builder = WebApplication.CreateBuilder(args); +builder.WebHost.ConfigureKestrel(serverOptions => +{ + serverOptions.ListenNamedPipe("MyPipeName", listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + + // Configure PipeSecurity + listenOptions.UseNamedPipes(options => + { + var pipeSecurity = new PipeSecurity(); + // Grant read/write access to the Users group + pipeSecurity.AddAccessRule(new PipeAccessRule( + "Users", + PipeAccessRights.ReadWrite, + AccessControlType.Allow)); + // Add additional rules as needed + + options.PipeSecurity = pipeSecurity; + }); + }); +}); +``` + +The preceding example: + +* Uses `UseNamedPipes` to access and configure . +* Sets the property to control which users or groups can connect to the named pipe. +* Grants read/write access to the `Users` group. Additional security rules can be added as needed for the scenario. + +### Customize Kestrel named pipe endpoints + +Kestrel's named pipe support enables advanced customization, allowing you to configure different security settings for each endpoint using the `CreateNamedPipeServerStream` option. This approach is ideal for scenarios where multiple named pipe endpoints require unique access controls. The ability to customize pipes per endpoint is available starting with .NET 9. + +An example of where this is useful is a Kestrel app that requires two pipe endpoints with different access security. The `CreateNamedPipeServerStream` option can be used to create pipes with custom security settings, depending on the pipe name. + +```csharp + +var builder = WebApplication.CreateBuilder(); +builder.WebHost.ConfigureKestrel(options => +{ + options.ListenNamedPipe("pipe1"); + options.ListenNamedPipe("pipe2"); +}); + +builder.WebHost.UseNamedPipes(options => +{ + options.CreateNamedPipeServerStream = (context) => + { + var pipeSecurity = CreatePipeSecurity(context.NamedPipeEndpoint.PipeName); + + return NamedPipeServerStreamAcl.Create(context.NamedPipeEndpoint.PipeName, PipeDirection.InOut, + NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, + context.PipeOptions, inBufferSize: 0, outBufferSize: 0, pipeSecurity); + }; +}); +``` + ## Client configuration `GrpcChannel` supports making gRPC calls over custom transports. When a channel is created, it can be configured with a that has a custom . The callback allows the client to make connections over custom transports and then send HTTP requests over that transport. diff --git a/aspnetcore/host-and-deploy/iis/development-time-iis-support.md b/aspnetcore/host-and-deploy/iis/development-time-iis-support.md index 580eeec9a0ea..54ff070dabcc 100644 --- a/aspnetcore/host-and-deploy/iis/development-time-iis-support.md +++ b/aspnetcore/host-and-deploy/iis/development-time-iis-support.md @@ -1,9 +1,9 @@ --- title: Development-time IIS support in Visual Studio for ASP.NET Core -author: rick-anderson +author: tdykstra description: Discover support for debugging ASP.NET Core apps when running with IIS on Windows Server. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 02/07/2020 uid: host-and-deploy/iis/development-time-iis-support diff --git a/aspnetcore/host-and-deploy/iis/logging-and-diagnostics.md b/aspnetcore/host-and-deploy/iis/logging-and-diagnostics.md index fff94338a7ba..2edf3b8c4e96 100644 --- a/aspnetcore/host-and-deploy/iis/logging-and-diagnostics.md +++ b/aspnetcore/host-and-deploy/iis/logging-and-diagnostics.md @@ -1,9 +1,9 @@ --- title: Log creation and redirection with the ASP.NET Core Module -author: rick-anderson +author: wadepickett description: Configure IIS and the ASP.NET Core Module to capture logs and diagnostic information. monikerRange: '>= aspnetcore-5.0' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 02/07/2020 uid: host-and-deploy/iis/logging-and-diagnostics diff --git a/aspnetcore/host-and-deploy/iis/modules.md b/aspnetcore/host-and-deploy/iis/modules.md index cb1fbe9c3f38..7fc5a261f4e1 100644 --- a/aspnetcore/host-and-deploy/iis/modules.md +++ b/aspnetcore/host-and-deploy/iis/modules.md @@ -1,9 +1,9 @@ --- title: IIS modules with ASP.NET Core -author: rick-anderson +author: wadepickett description: Discover active and inactive IIS modules for ASP.NET Core apps and how to manage IIS modules. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 01/13/2020 uid: host-and-deploy/iis/modules diff --git a/aspnetcore/host-and-deploy/iis/out-of-process-hosting.md b/aspnetcore/host-and-deploy/iis/out-of-process-hosting.md index e6d160000aef..8afe5a04cd0d 100644 --- a/aspnetcore/host-and-deploy/iis/out-of-process-hosting.md +++ b/aspnetcore/host-and-deploy/iis/out-of-process-hosting.md @@ -1,9 +1,9 @@ --- title: Out-of-process hosting with IIS and ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn about out-of-process Hosting with IIS and the ASP.NET Core Module. monikerRange: '>= aspnetcore-5.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 02/07/2020 uid: host-and-deploy/iis/out-of-process-hosting diff --git a/aspnetcore/host-and-deploy/iis/protocols.md b/aspnetcore/host-and-deploy/iis/protocols.md index ae8f666608b5..54ff50aea84b 100644 --- a/aspnetcore/host-and-deploy/iis/protocols.md +++ b/aspnetcore/host-and-deploy/iis/protocols.md @@ -1,9 +1,9 @@ --- title: Use ASP.NET Core with HTTP/2 on IIS -author: rick-anderson +author: tdykstra description: Learn how to use HTTP/2 features with IIS. monikerRange: '>= aspnetcore-5.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 01/13/2020 uid: host-and-deploy/iis/protocols diff --git a/aspnetcore/host-and-deploy/iis/transform-webconfig.md b/aspnetcore/host-and-deploy/iis/transform-webconfig.md index da8be7f05179..5b9be342f9a4 100644 --- a/aspnetcore/host-and-deploy/iis/transform-webconfig.md +++ b/aspnetcore/host-and-deploy/iis/transform-webconfig.md @@ -1,9 +1,9 @@ --- title: Transform web.config -author: rick-anderson +author: tdykstra description: Learn how to transform the web.config file when publishing an ASP.NET Core app. monikerRange: '>= aspnetcore-2.2' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 01/13/2020 uid: host-and-deploy/iis/transform-webconfig diff --git a/aspnetcore/host-and-deploy/iis/web-config.md b/aspnetcore/host-and-deploy/iis/web-config.md index f51fc546f362..429c094e7389 100644 --- a/aspnetcore/host-and-deploy/iis/web-config.md +++ b/aspnetcore/host-and-deploy/iis/web-config.md @@ -1,9 +1,9 @@ --- title: web.config file -author: rick-anderson +author: tdykstra description: Discover what is inside of the web.config file and how to configure different ASP.NET Core Module options. monikerRange: '>= aspnetcore-5.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc, sfi-ropc-nochange ms.date: 02/07/2020 uid: host-and-deploy/iis/web-config diff --git a/aspnetcore/host-and-deploy/proxy-load-balancer.md b/aspnetcore/host-and-deploy/proxy-load-balancer.md index 0c21c9dd79d1..18831d273c80 100644 --- a/aspnetcore/host-and-deploy/proxy-load-balancer.md +++ b/aspnetcore/host-and-deploy/proxy-load-balancer.md @@ -1,9 +1,9 @@ --- title: Configure ASP.NET Core to work with proxy servers and load balancers -author: rick-anderson +author: tdykstra description: Learn about configuration for apps hosted behind proxy servers and load balancers, which often obscure important request information. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.custom: mvc, linux-related-content ms.date: 1/07/2022 uid: host-and-deploy/proxy-load-balancer diff --git a/aspnetcore/migration/20_21.md b/aspnetcore/migration/20_21.md index fcfb840f2fdb..be118e733795 100644 --- a/aspnetcore/migration/20_21.md +++ b/aspnetcore/migration/20_21.md @@ -1,8 +1,8 @@ --- title: Migrate from ASP.NET Core 2.0 to 2.1 -author: rick-anderson +author: wadepickett description: This article covers the basics of migrating an ASP.NET Core 2.0 app to 2.1. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 06/09/2019 uid: migration/20_21 diff --git a/aspnetcore/migration/22-to-30.md b/aspnetcore/migration/22-to-30.md index 87a1de648d0d..df68517a08e7 100644 --- a/aspnetcore/migration/22-to-30.md +++ b/aspnetcore/migration/22-to-30.md @@ -1,8 +1,8 @@ --- title: Migrate from ASP.NET Core 2.2 to 3.0 -author: rick-anderson +author: wadepickett description: Learn how to migrate an ASP.NET Core 2.2 project to ASP.NET Core 3.0. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 06/02/2023 uid: migration/22-to-30 diff --git a/aspnetcore/migration/31-to-60.md b/aspnetcore/migration/31-to-60.md index 6a353974957b..602d49c33892 100644 --- a/aspnetcore/migration/31-to-60.md +++ b/aspnetcore/migration/31-to-60.md @@ -1,8 +1,8 @@ --- title: Migrate from ASP.NET Core 3.1 to .NET 6 -author: rick-anderson +author: wadepickett description: Learn how to migrate an ASP.NET Core 3.1 project to ASP.NET Core in .NET 6. -ms.author: riande +ms.author: wpickett ms.custom: sfi-ropc-nochange monikerRange: '>= aspnetcore-3.1' ms.date: 10/25/2021 diff --git a/aspnetcore/migration/50-to-60-samples.md b/aspnetcore/migration/50-to-60-samples.md index 404c82d4faf0..29ad17616d40 100644 --- a/aspnetcore/migration/50-to-60-samples.md +++ b/aspnetcore/migration/50-to-60-samples.md @@ -1,9 +1,9 @@ --- title: Code samples migrated to the new minimal hosting model in 6.0 -author: rick-anderson +author: wadepickett description: Learn how to migrate ASP.NET Core samples to the new minimal hosting model in 6.0. monikerRange: '>= aspnetcore-5.0' -ms.author: riande +ms.author: wpickett ms.date: 10/22/2021 uid: migration/50-to-60-samples --- diff --git a/aspnetcore/migration/50-to-60.md b/aspnetcore/migration/50-to-60.md index bcd3ca5af9e8..c01cab86613a 100644 --- a/aspnetcore/migration/50-to-60.md +++ b/aspnetcore/migration/50-to-60.md @@ -1,8 +1,8 @@ --- title: Migrate from ASP.NET Core in .NET 5 to .NET 6 -author: rick-anderson +author: wadepickett description: Learn how to migrate an ASP.NET Core in .NET 5 project to .NET 6. -ms.author: riande +ms.author: wpickett monikerRange: '>= aspnetcore-5.0' ms.date: 04/11/2022 uid: migration/50-to-60 diff --git a/aspnetcore/migration/Logging-nonaspnetcore.md b/aspnetcore/migration/Logging-nonaspnetcore.md index afb725800f34..1d388113e7d9 100644 --- a/aspnetcore/migration/Logging-nonaspnetcore.md +++ b/aspnetcore/migration/Logging-nonaspnetcore.md @@ -1,8 +1,8 @@ --- title: Migrate from Microsoft.Extensions.Logging 2.1 to 2.2 or 3.0 -author: rick-anderson +author: tdykstra description: Learn how to migrate a non-ASP.NET Core application that uses Microsoft.Extensions.Logging from 2.1 to 2.2 or 3.0. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 01/04/2019 uid: migration/logging-nonaspnetcore diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index daa5eb997907..d920e7d37eda 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -1,8 +1,8 @@ --- title: ASP.NET Framework to Core Authentication Migration description: ASP.NET Framework to Core Authentication Migration -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett monikerRange: '>= aspnetcore-6.0' ms.date: 07/17/2025 ms.topic: article diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index d62f0364bfcb..539f37959a3b 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -1,8 +1,8 @@ --- title: ASP.NET to ASP.NET Core session state migration description: ASP.NET to ASP.NET Core session state migration -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett monikerRange: '>= aspnetcore-6.0' ms.date: 07/17/2025 ms.topic: article diff --git a/aspnetcore/migration/fx-to-core/tooling.md b/aspnetcore/migration/fx-to-core/tooling.md index 344c30bf570e..ed1d3a0e0c23 100644 --- a/aspnetcore/migration/fx-to-core/tooling.md +++ b/aspnetcore/migration/fx-to-core/tooling.md @@ -1,8 +1,8 @@ --- title: Learn to upgrade from ASP.NET MVC, Web API, and Web Forms to ASP.NET Core description: Learn how to upgrade ASP.NET Framework MVC, Web API, or Web Forms projects to ASP.NET Core using migration tooling -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett ms.date: 07/17/2025 uid: migration/fx-to-core/tooling --- diff --git a/aspnetcore/mvc/views/tag-helpers/built-in/persist-component-state.md b/aspnetcore/mvc/views/tag-helpers/built-in/persist-component-state.md index b002589f0fee..ebe51af969c0 100644 --- a/aspnetcore/mvc/views/tag-helpers/built-in/persist-component-state.md +++ b/aspnetcore/mvc/views/tag-helpers/built-in/persist-component-state.md @@ -49,7 +49,7 @@ In `Pages/Shared/_Layout.cshtml` for embedded components that are either WebAsse Decide what state to persist using the service. [`PersistentComponentState.RegisterOnPersisting`](xref:Microsoft.AspNetCore.Components.PersistentComponentState.RegisterOnPersisting%2A) registers a callback to persist the component state before the app is paused. The state is retrieved when the application resumes. -For more information and examples, see . +For more information and examples, see . :::moniker-end diff --git a/aspnetcore/performance/rate-limit-samples.md b/aspnetcore/performance/rate-limit-samples.md index f644ed8b94b9..5388fd102148 100644 --- a/aspnetcore/performance/rate-limit-samples.md +++ b/aspnetcore/performance/rate-limit-samples.md @@ -1,7 +1,7 @@ --- title: Rate limiting middleware samples -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett monikerRange: '>= aspnetcore-7.0' description: Samples for using ASP.NET rate limitng middleware ms.custom: mvc diff --git a/aspnetcore/performance/rate-limit.md b/aspnetcore/performance/rate-limit.md index c0895054b735..ac73236772ae 100644 --- a/aspnetcore/performance/rate-limit.md +++ b/aspnetcore/performance/rate-limit.md @@ -1,7 +1,7 @@ --- title: Rate limiting middleware in ASP.NET Core -author: rick-anderson -ms.author: riande +author: wadepickett +ms.author: wpickett monikerRange: '>= aspnetcore-7.0' description: Learn how limit requests in ASP.NET Core apps ms.custom: mvc diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index 5a6a3efbf3d5..9858b1617a1c 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -294,7 +294,7 @@ else } ``` -State can be serialized for multiple components of the same type, and you can establish declarative state in a service for use around the app by calling `RegisterPersistentService` on the Razor components builder () with a custom service type and render mode. For more information, see . +State can be serialized for multiple components of the same type, and you can establish declarative state in a service for use around the app by calling `RegisterPersistentService` on the Razor components builder () with a custom service type and render mode. For more information, see . ### New JavaScript interop features @@ -414,7 +414,7 @@ The now includes a `Not * **Interactive rendering**: Signals the Blazor router ([`Router` component](xref:blazor/fundamentals/routing?view=aspnetcore-10.0#route-templates)) to render Not Found content. -* **Streaming rendering**: If [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) is active, [streaming rendering](xref:blazor/components/rendering#streaming-rendering) renders Not Found content without reloading the page. When enhanced navigation is blocked, the framework redirects to Not Found content with a page refresh. +* **Streaming rendering**: If [enhanced navigation](xref:blazor/fundamentals/routing?view=aspnetcore-10.0#enhanced-navigation-and-form-handling) is active, [streaming rendering](xref:blazor/components/rendering#streaming-rendering) renders Not Found content without reloading the page. When enhanced navigation is blocked, the framework redirects to Not Found content with a page refresh. Streaming rendering can only render components that have a route, such as a [`NotFoundPage` assignment](#blazor-router-has-a-notfoundpage-parameter) (`NotFoundPage="..."`) or a [Status Code Pages Re-execution Middleware page assignment](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) (). The Not Found render fragment (`...`) and the `DefaultNotFound` 404 content ("`Not found`" plain text) don't have routes, so they can't be used during streaming rendering. @@ -452,7 +452,7 @@ For more information, see ` headers with a `LinkPreload` component (``) for preloading WebAssembly assets in Blazor Web Apps. This permits the app base path configuration (``) to correctly identify the app's root. -Removing the component disables the feature if the app is using a [`loadBootResource` callback](xref:blazor/fundamentals/startup#load-client-side-boot-resources) to modify URLs. +Removing the component disables the feature if the app is using a [`loadBootResource` callback](xref:blazor/fundamentals/startup?view=aspnetcore-10.0#load-client-side-boot-resources) to modify URLs. The Blazor Web App template adopts the feature by default in .NET 10, and apps upgrading to .NET 10 can implement the feature by placing the `LinkPreload` component after the base URL tag (``) in the `App` component's head content (`App.razor`): @@ -573,124 +573,4 @@ During server-side rendering, Blazor Web Apps can now persist a user's session ( *[Enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) with circuit state persistence isn't currently supported but planned for a future release.* -Persisting state requires fewer server resources than persisting circuits: - -* Even if disconnected, a circuit might continue to perform work and consume CPU, memory, and other resources. Persisted state only consumes a fixed amount of memory that the developer controls. -* Persisted state represents a subset of the memory consumed by the app, so the server isn't required to keep track of the app's components and other server-side objects. - -State is persisted for two scenarios: - -* Component state: State that components use for Interactive Server rendering, for example, a list of items retrieved from the database or a form that the user is filling out. -* Scoped services: State held inside of a server-side service, for example, the current user. - -Conditions: - -* The feature is only effective for Interactive Server rendering. -* If the user refreshes the page (app), the persisted state is lost. -* The state must be JSON serializable. Cyclic references or ORM entities may not serialize correctly. -* Use `@key` for uniqueness when rendering components in a loop to avoid key conflicts. -* Persist only necessary state. Storing excessive data may impact performance. -* No automatic hibernation. You must opt-in and configure state persistence explicitly. -* No guarantee of recovery. If state persistence fails, the app falls back to the default disconnected experience. - -State persistence is enabled by default when is called on in the `Program` file. is the default storage implementation for single app instances and stores up to 1,000 persisted circuits for two hours, which are configurable. - -Use the following options to change the default values of the in-memory provider: - -* `PersistedCircuitInMemoryMaxRetained` (`{CIRCUIT COUNT}` placeholder): The maximum number of circuits to retain. The default is 1,000 circuits. For example, use `2000` to retain state for up to 2,000 circuits. -* `PersistedCircuitInMemoryRetentionPeriod` (`{RETENTION PERIOD}` placeholder): The maximum retention period as a . The default is two hours. For example, use `TimeSpan.FromHours(3)` for a three-hour retention period. - -```csharp -services.Configure(options => -{ - options.PersistedCircuitInMemoryMaxRetained = {CIRCUIT COUNT}; - options.PersistedCircuitInMemoryRetentionPeriod = {RETENTION PERIOD}; -}); -``` - -Persisting component state across circuits is built on top of the existing API, which continues to persist state for prerendered components that adopt an interactive render mode. - -> [NOTE] -> Persisting component state for prerendering works for any interactive render mode, but circuit state persistence only works for the **Interactive Server** render mode. - -Annotate component properties with `[SupplyFromPersistentComponentState]` to enable circuit state persistence. The following example also keys the items with the [`@key` directive attribute](xref:blazor/components/key) to provide a unique identifier for each component instance: - -```razor -@foreach (var item in Items) -{ - -} - -@code { - [SupplyFromPersistentComponentState] - public List Items { get; set; } - - protected override async Task OnInitializedAsync() - { - Items ??= await LoadItemsAsync(); - } -} -``` - -To persist State for scoped services, annotate service properties with `[SupplyFromPersistentComponentState]`, add the service to the service collection, and call the extension method with the service: - -```csharp -public class CustomUserService -{ - [SupplyFromPersistentComponentState] - public string UserData { get; set; } -} - -services.AddScoped(); - -services.AddRazorComponents() - .AddInteractiveServerComponents() - .RegisterPersistentService(RenderMode.InteractiveAuto); -``` - -> [NOTE] -> The preceding example persists `UserData` state when the service is used in component prerendering for both Interactive Server and Interactive WebAssembly rendering because `RenderMode.InteractiveAuto` is specified to `RegisterPersistentService`. However, circuit state persistence is only available for the **Interactive Server** render mode. - -For more information, see . - -To handle distributed state persistence (and to act as the default state persistence mechanism when configured), assign a [`HybridCache`](xref:performance/caching/overview#hybridcache) (API: ) to the app, which configures its own persistence period (`PersistedCircuitDistributedRetentionPeriod`, eight hours by default). `HybridCache` is used because it provides a unified approach to distributed storage that doesn't require separate packages for each storage provider. - -In the following example, a is implemented with the [Redis](https://redis.io/) storage provider: - -```csharp -services.AddHybridCache() - .AddRedis("{CONNECTION STRING}"); - -services.AddRazorComponents() - .AddInteractiveServerComponents(); -``` - -In the preceding example, the `{CONNECTION STRING}` placeholder represents the Redis cache connection string, which should be provided using a secure approach, such as the [Secret Manager](xref:security/app-secrets#secret-manager) tool in the Development environment or [Azure Key Vault](/azure/key-vault/) with [Azure Managed Identities](/entra/identity/managed-identities-azure-resources/overview) for Azure-deployed apps in any environment. - -To proactively pause and resume circuits in custom resource management scenarios, call `Blazor.pauseCircuit` and `Blazor.resumeCircuit` from a JavaScript event handler. In the following example, changes in the the visibility of the app either pause or resume the user's circuit: - -```javascript -window.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'hidden') { - Blazor.pauseCircuit(); - } else if (document.visibilityState === 'visible') { - Blazor.resumeCircuit(); - } -}); -``` - -> [!NOTE] -> Support for circuit state persistence with enhanced navigation is planned for a future release. -> -> The following API renaming is planned for the upcoming Preview 7 release in August: -> -> `[SupplyFromPersistentComponentState]` will be renamed to `[PersistentState]`. -> `Blazor.pauseCircuit` will be renamed to `Blazor.pause`. -> `Blazor.resumeCircuit` will be renamed to `Blazor.resume`. - - +For more information, see . diff --git a/aspnetcore/release-notes/aspnetcore-5.0.md b/aspnetcore/release-notes/aspnetcore-5.0.md index 0fd936bf7a24..81fe92c7d32d 100644 --- a/aspnetcore/release-notes/aspnetcore-5.0.md +++ b/aspnetcore/release-notes/aspnetcore-5.0.md @@ -176,7 +176,7 @@ Blazor security now uses Microsoft Identity v2.0 ([`Microsoft.Identity.Web`](htt ### Protected Browser Storage for Blazor Server -Blazor Server apps can now use built-in support for storing app state in the browser that has been protected from tampering using ASP.NET Core data protection. Data can be stored in either local browser storage or session storage. For more information, see . +Blazor Server apps can now use built-in support for storing app state in the browser that has been protected from tampering using ASP.NET Core data protection. Data can be stored in either local browser storage or session storage. For more information, see and . ### Blazor WebAssembly prerendering diff --git a/aspnetcore/release-notes/aspnetcore-8.0.md b/aspnetcore/release-notes/aspnetcore-8.0.md index d222d04bf2ce..9bfabb0b3331 100644 --- a/aspnetcore/release-notes/aspnetcore-8.0.md +++ b/aspnetcore/release-notes/aspnetcore-8.0.md @@ -78,7 +78,7 @@ For prior releases of .NET, we covered prerendering and integration in a single ### Persist component state in a Blazor Web App -You can persist and read component state in a Blazor Web App using the existing service. This is useful for [persisting component state during prerendering](xref:blazor/components/prerender?view=aspnetcore-8.0&preserve-view=true#persist-prerendered-state). +You can persist and read component state in a Blazor Web App using the existing service. This is useful for [persisting component state during prerendering](xref:blazor/state-management/prerendered-state-persistence?view=aspnetcore-8.0&preserve-view=true#persist-prerendered-state). Blazor Web Apps automatically persist any registered app-level state created during prerendering, removing the need for the [Persist Component State Tag Helper](xref:mvc/views/tag-helpers/builtin-th/persist-component-state-tag-helper). diff --git a/aspnetcore/release-notes/aspnetcore-9/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-9/includes/blazor.md index 411a7ae3d04f..338e685cea8c 100644 --- a/aspnetcore/release-notes/aspnetcore-9/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-9/includes/blazor.md @@ -69,7 +69,7 @@ New APIs make it easier to add authentication to an existing Blazor Web App. Whe These providers flow the user's authentication state to the browser. Authenticating on the server rather than the client allows the app to access authentication state during prerendering and before the .NET WebAssembly runtime is initialized. -The custom implementations use the [Persistent Component State service](xref:blazor/components/prerender#persist-prerendered-state) () to serialize the authentication state into HTML comments and read it back from WebAssembly to create a new instance. +The custom implementations use the [Persistent Component State service](xref:blazor/state-management/prerendered-state-persistence?view=aspnetcore-9.0) () to serialize the authentication state into HTML comments and read it back from WebAssembly to create a new instance. This works well if you've started from the Blazor Web App project template and selected the **Individual Accounts** option, but it's a lot of code to implement yourself or copy if you're trying to add authentication to an existing project. There are now APIs, which are now part of the Blazor Web App project template, that can be called in the server and client projects to add this functionality: diff --git a/aspnetcore/security/authentication/2fa.md b/aspnetcore/security/authentication/2fa.md index 351bd0183f57..e84d717009a8 100644 --- a/aspnetcore/security/authentication/2fa.md +++ b/aspnetcore/security/authentication/2fa.md @@ -1,9 +1,9 @@ --- title: Two-factor authentication with SMS in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to set up two-factor authentication (2FA) with an ASP.NET Core app. monikerRange: '< aspnetcore-2.0' -ms.author: riande +ms.author: wpickett ms.custom: mvc, sfi-image-nochange ms.date: 09/22/2018 uid: security/authentication/2fa diff --git a/aspnetcore/security/authentication/accconfirm.md b/aspnetcore/security/authentication/accconfirm.md index 7fc064ffe42e..e51c0b4c3b3b 100644 --- a/aspnetcore/security/authentication/accconfirm.md +++ b/aspnetcore/security/authentication/accconfirm.md @@ -1,8 +1,8 @@ --- title: Account confirmation and password recovery in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to build an ASP.NET Core app with email confirmation and password reset. -ms.author: riande +ms.author: wpickett ms.custom: sfi-image-nochange monikerRange: '>= aspnetcore-3.1' ms.date: 2/9/2022 diff --git a/aspnetcore/security/authentication/add-user-data.md b/aspnetcore/security/authentication/add-user-data.md index 359868c5e3c9..ef1fe1de43e9 100644 --- a/aspnetcore/security/authentication/add-user-data.md +++ b/aspnetcore/security/authentication/add-user-data.md @@ -1,8 +1,8 @@ --- title: Add, download, and delete user data to Identity in an ASP.NET Core project -author: rick-anderson +author: wadepickett description: Learn how to add custom user data to Identity in an ASP.NET Core project. Delete data per GDPR. -ms.author: riande +ms.author: wpickett ms.date: 03/15/2022 ms.custom: mvc uid: security/authentication/add-user-data diff --git a/aspnetcore/security/authentication/azure-active-directory/index.md b/aspnetcore/security/authentication/azure-active-directory/index.md index 411d2febb3ce..d88b16b802d1 100644 --- a/aspnetcore/security/authentication/azure-active-directory/index.md +++ b/aspnetcore/security/authentication/azure-active-directory/index.md @@ -1,8 +1,8 @@ --- title: Microsoft identity platform and Microsoft Entra ID with ASP.NET Core -author: rick-anderson +author: wpickett description: Discover topics related to authentication with Microsoft identity platform Microsoft Entra ID for web apps and APIs in ASP.NET Core. -ms.author: riande +ms.author: wpickett ms.date: 01/21/2020 ms.custom: mvc uid: security/authentication/azure-active-directory/index diff --git a/aspnetcore/security/authentication/claims.md b/aspnetcore/security/authentication/claims.md index b34ded7f3bff..02d9d05517ab 100644 --- a/aspnetcore/security/authentication/claims.md +++ b/aspnetcore/security/authentication/claims.md @@ -3,7 +3,7 @@ title: Mapping, customizing, and transforming claims in ASP.NET Core author: damienbod description: Learn how to map claims, do claims transformations, customize claims. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 2/16/2022 uid: security/authentication/claims diff --git a/aspnetcore/security/authentication/community.md b/aspnetcore/security/authentication/community.md index cd1cd1d25bac..e12776294b1b 100644 --- a/aspnetcore/security/authentication/community.md +++ b/aspnetcore/security/authentication/community.md @@ -1,8 +1,8 @@ --- title: Community OSS authentication options for ASP.NET Core -author: rick-anderson +author: tdykstra description: Discover open-source authentication options for ASP.NET Core. -ms.author: riande +ms.author: tdykstra ms.date: 05/01/2024 uid: security/authentication/community --- diff --git a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md index 53bc748830e6..a3943ce10859 100644 --- a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md +++ b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md @@ -3,7 +3,7 @@ title: Configure JWT bearer authentication in ASP.NET Core author: damienbod description: Learn how to set up JWT bearer authentication in an ASP.NET Core app. monikerRange: '>= aspnetcore-8.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 12/7/2024 uid: security/authentication/configure-jwt-bearer-authentication diff --git a/aspnetcore/security/authentication/configure-oidc-web-authentication.md b/aspnetcore/security/authentication/configure-oidc-web-authentication.md index 1f5551fe4a56..b76264915d2c 100644 --- a/aspnetcore/security/authentication/configure-oidc-web-authentication.md +++ b/aspnetcore/security/authentication/configure-oidc-web-authentication.md @@ -3,7 +3,7 @@ title: Configure OpenID Connect Web (UI) authentication in ASP.NET Core author: damienbod description: Learn how to set up OpenID Connect authentication in an ASP.NET Core app. monikerRange: '>= aspnetcore-8.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 12/2/2024 uid: security/authentication/configure-oidc-web-authentication diff --git a/aspnetcore/security/authentication/cookie.md b/aspnetcore/security/authentication/cookie.md index 8fdbe323226b..4914470d6af2 100644 --- a/aspnetcore/security/authentication/cookie.md +++ b/aspnetcore/security/authentication/cookie.md @@ -1,9 +1,9 @@ --- title: Use cookie authentication without ASP.NET Core Identity -author: rick-anderson +author: wadepickett description: Learn how to use cookie authentication without ASP.NET Core Identity. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.date: 1/1/2022 uid: security/authentication/cookie --- diff --git a/aspnetcore/security/authentication/customize-identity-model.md b/aspnetcore/security/authentication/customize-identity-model.md index e8c4c7204e20..baa4cda7108e 100644 --- a/aspnetcore/security/authentication/customize-identity-model.md +++ b/aspnetcore/security/authentication/customize-identity-model.md @@ -2,7 +2,7 @@ title: Identity model customization in ASP.NET Core author: ajcvickers description: This article describes how to customize the underlying Entity Framework Core data model for ASP.NET Core Identity. -ms.author: riande +ms.author: tdykstra ms.date: 10/29/2024 uid: security/authentication/customize_identity_model --- diff --git a/aspnetcore/security/authentication/identity-configuration.md b/aspnetcore/security/authentication/identity-configuration.md index 5410c4cd6516..f2381333ab46 100644 --- a/aspnetcore/security/authentication/identity-configuration.md +++ b/aspnetcore/security/authentication/identity-configuration.md @@ -2,7 +2,7 @@ title: Configure ASP.NET Core Identity author: AdrienTorris description: Understand ASP.NET Core Identity default values and learn how to configure Identity properties to use custom values. -ms.author: riande +ms.author: tdykstra monikerRange: '>= aspnetcore-3.1' ms.custom: mvc ms.date: 3/09/2024 diff --git a/aspnetcore/security/authentication/identity-custom-storage-providers.md b/aspnetcore/security/authentication/identity-custom-storage-providers.md index d07d2600278f..9f1de15f1d7e 100644 --- a/aspnetcore/security/authentication/identity-custom-storage-providers.md +++ b/aspnetcore/security/authentication/identity-custom-storage-providers.md @@ -2,7 +2,7 @@ title: Custom storage providers for ASP.NET Core Identity author: ardalis description: Learn how to configure custom storage providers for ASP.NET Core Identity. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 10/29/2024 uid: security/authentication/identity-custom-storage-providers diff --git a/aspnetcore/security/authentication/identity-enable-qrcodes.md b/aspnetcore/security/authentication/identity-enable-qrcodes.md index 53dedc553a3b..9bdb88a7a8cc 100644 --- a/aspnetcore/security/authentication/identity-enable-qrcodes.md +++ b/aspnetcore/security/authentication/identity-enable-qrcodes.md @@ -1,9 +1,9 @@ --- title: Enable QR code generation for TOTP authenticator apps in ASP.NET Core -author: rick-anderson +author: wadepickett description: Discover how to enable QR code generation for TOTP authenticator apps that work with ASP.NET Core two-factor authentication. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: wpickett ms.date: 08/14/2018 uid: security/authentication/identity-enable-qrcodes --- diff --git a/aspnetcore/security/authentication/identity.md b/aspnetcore/security/authentication/identity.md index f67c82ae0c7c..23aadff6983a 100644 --- a/aspnetcore/security/authentication/identity.md +++ b/aspnetcore/security/authentication/identity.md @@ -1,9 +1,9 @@ --- title: Introduction to Identity on ASP.NET Core -author: rick-anderson +author: wadepickett description: Use Identity with an ASP.NET Core app. Learn how to set password requirements (RequireDigit, RequiredLength, RequiredUniqueChars, and more). monikerRange: '>= aspnetcore-3.0' -ms.author: riande +ms.author: wpickett ms.date: 04/26/2024 uid: security/authentication/identity --- diff --git a/aspnetcore/security/authentication/index.md b/aspnetcore/security/authentication/index.md index 98d34e68b4c4..86d89fa929fd 100644 --- a/aspnetcore/security/authentication/index.md +++ b/aspnetcore/security/authentication/index.md @@ -2,7 +2,7 @@ title: Overview of ASP.NET Core Authentication author: mjrousos description: Learn about authentication in ASP.NET Core. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 10/18/2022 uid: security/authentication/index diff --git a/aspnetcore/security/authentication/individual.md b/aspnetcore/security/authentication/individual.md index 6c0d71ef9185..6466f8cd5b27 100644 --- a/aspnetcore/security/authentication/individual.md +++ b/aspnetcore/security/authentication/individual.md @@ -1,8 +1,8 @@ --- title: Articles based on ASP.NET Core projects created with individual accounts -author: rick-anderson +author: tdykstra description: Discover articles based on ASP.NET Core projects created with individual accounts. -ms.author: riande +ms.author: tdykstra ms.date: 12/11/2019 uid: security/authentication/individual --- diff --git a/aspnetcore/security/authentication/jwt-authn.md b/aspnetcore/security/authentication/jwt-authn.md index 7f18082d0621..71dcca3ca9c1 100644 --- a/aspnetcore/security/authentication/jwt-authn.md +++ b/aspnetcore/security/authentication/jwt-authn.md @@ -1,9 +1,9 @@ --- title: Generate tokens with dotnet user-jwts -author: rick-anderson +author: tdykstra description: Learn how to set up manage JSON Web Tokens in development with dotnet user-jwts monikerRange: '>= aspnetcore-7.0' -ms.author: riande +ms.author: tdykstra ms.date: 09/22/2018 ms.custom: mvc uid: security/authentication/jwt diff --git a/aspnetcore/security/authentication/mfa.md b/aspnetcore/security/authentication/mfa.md index 104296a88767..5e7700d4287f 100644 --- a/aspnetcore/security/authentication/mfa.md +++ b/aspnetcore/security/authentication/mfa.md @@ -3,7 +3,7 @@ title: Multi-factor authentication in ASP.NET Core author: damienbod description: Learn how to set up multi-factor authentication (MFA) in an ASP.NET Core app. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 10/29/2024 uid: security/authentication/mfa diff --git a/aspnetcore/security/authentication/policyschemes.md b/aspnetcore/security/authentication/policyschemes.md index 6690441ead6a..bfe3707755d3 100644 --- a/aspnetcore/security/authentication/policyschemes.md +++ b/aspnetcore/security/authentication/policyschemes.md @@ -1,8 +1,8 @@ --- title: Policy schemes in ASP.NET Core -author: rick-anderson +author: wadepickett description: Authentication policy schemes make it easier to have a single logical authentication scheme -ms.author: riande +ms.author: wpickett ms.date: 12/05/2019 uid: security/authentication/policyschemes --- diff --git a/aspnetcore/security/authentication/scaffold-identity.md b/aspnetcore/security/authentication/scaffold-identity.md index c3cd0bc0cb2b..9d5b587716b2 100644 --- a/aspnetcore/security/authentication/scaffold-identity.md +++ b/aspnetcore/security/authentication/scaffold-identity.md @@ -1,9 +1,9 @@ --- title: Scaffold Identity in ASP.NET Core projects -author: rick-anderson +author: wadepickett description: Learn how to scaffold Identity in an ASP.NET Core project. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 07/22/2024 uid: security/authentication/scaffold-identity diff --git a/aspnetcore/security/authentication/social/additional-claims.md b/aspnetcore/security/authentication/social/additional-claims.md index 5b31ededf23c..2d3ce52737c1 100644 --- a/aspnetcore/security/authentication/social/additional-claims.md +++ b/aspnetcore/security/authentication/social/additional-claims.md @@ -1,9 +1,9 @@ --- title: Persist additional claims and tokens from external providers in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn how to establish additional claims and tokens from external providers. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 02/18/2021 uid: security/authentication/social/additional-claims diff --git a/aspnetcore/security/authentication/social/facebook-logins.md b/aspnetcore/security/authentication/social/facebook-logins.md index 1fcca0fdc9ed..761950536c81 100644 --- a/aspnetcore/security/authentication/social/facebook-logins.md +++ b/aspnetcore/security/authentication/social/facebook-logins.md @@ -1,8 +1,8 @@ --- title: Facebook external login setup in ASP.NET Core -author: rick-anderson +author: wadepickett description: Tutorial with code examples demonstrating the integration of Facebook account user authentication into an existing ASP.NET Core app. -ms.author: riande +ms.author: wpickett ms.custom: mvc, sfi-image-nochange ms.date: 12/08/2021 monikerRange: '>= aspnetcore-3.0' diff --git a/aspnetcore/security/authentication/social/google-logins.md b/aspnetcore/security/authentication/social/google-logins.md index 9b70f68913bc..f6cf3cc2ad8e 100644 --- a/aspnetcore/security/authentication/social/google-logins.md +++ b/aspnetcore/security/authentication/social/google-logins.md @@ -1,8 +1,8 @@ --- title: Google external login setup in ASP.NET Core -author: rick-anderson +author: wadepickett description: This tutorial demonstrates the integration of Google account user authentication into an existing ASP.NET Core app. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 06/18/2025 uid: security/authentication/google-logins diff --git a/aspnetcore/security/authentication/social/index.md b/aspnetcore/security/authentication/social/index.md index b4be6d3c0b55..af96bb979b26 100644 --- a/aspnetcore/security/authentication/social/index.md +++ b/aspnetcore/security/authentication/social/index.md @@ -1,8 +1,8 @@ --- title: Using external login providers with Identity in ASP.NET Core -author: rick-anderson +author: wadepickett description: Create an ASP.NET Core app using Identity with external authentication providers such as Facebook, Twitter, Google, and Microsoft. -ms.author: riande +ms.author: wpickett ms.custom: mvc, sfi-image-nochange ms.date: 07/09/2025 uid: security/authentication/social/index diff --git a/aspnetcore/security/authentication/social/microsoft-logins.md b/aspnetcore/security/authentication/social/microsoft-logins.md index 60c8c0938073..91da43ca70a5 100644 --- a/aspnetcore/security/authentication/social/microsoft-logins.md +++ b/aspnetcore/security/authentication/social/microsoft-logins.md @@ -1,8 +1,8 @@ --- title: Microsoft Account external login setup with ASP.NET Core -author: rick-anderson +author: tdykstra description: This sample demonstrates the integration of Microsoft account user authentication into an existing ASP.NET Core app. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 03/01/2025 monikerRange: '>= aspnetcore-3.1' diff --git a/aspnetcore/security/authentication/social/other-logins.md b/aspnetcore/security/authentication/social/other-logins.md index 1b68b9f5a8cc..f5c03b9c6091 100644 --- a/aspnetcore/security/authentication/social/other-logins.md +++ b/aspnetcore/security/authentication/social/other-logins.md @@ -1,8 +1,8 @@ --- title: External OAuth authentication providers -author: rick-anderson +author: tdykstra description: Discover External OAuth authentication providers that work with ASP.NET Core apps. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 11/11/2018 uid: security/authentication/otherlogins diff --git a/aspnetcore/security/authentication/social/social-without-identity.md b/aspnetcore/security/authentication/social/social-without-identity.md index cf5a8c4b6afc..633bf31c75d0 100644 --- a/aspnetcore/security/authentication/social/social-without-identity.md +++ b/aspnetcore/security/authentication/social/social-without-identity.md @@ -3,7 +3,7 @@ title: Facebook, Google, and external provider authentication without ASP.NET Co author: serpent5 description: Use Facebook, Google, Twitter, etc. account user authentication without ASP.NET Core Identity. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.date: 04/05/2022 uid: security/authentication/social/social-without-identity --- diff --git a/aspnetcore/security/authentication/social/twitter-logins.md b/aspnetcore/security/authentication/social/twitter-logins.md index 6148363ca866..04c9a568e655 100644 --- a/aspnetcore/security/authentication/social/twitter-logins.md +++ b/aspnetcore/security/authentication/social/twitter-logins.md @@ -1,8 +1,8 @@ --- title: Twitter external sign-in setup with ASP.NET Core -author: rick-anderson +author: wadepickett description: This tutorial demonstrates the integration of Twitter account user authentication into an existing ASP.NET Core app. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 12/08/2021 monikerRange: '>= aspnetcore-3.0' diff --git a/aspnetcore/security/authorization/claims.md b/aspnetcore/security/authorization/claims.md index 0c3179f8dbf1..6362f7fe942a 100644 --- a/aspnetcore/security/authorization/claims.md +++ b/aspnetcore/security/authorization/claims.md @@ -1,8 +1,8 @@ --- title: Claims-based authorization in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to add claims checks for authorization in an ASP.NET Core app. -ms.author: riande +ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 11/26/2021 uid: security/authorization/claims diff --git a/aspnetcore/security/authorization/customizingauthorizationmiddlewareresponse.md b/aspnetcore/security/authorization/customizingauthorizationmiddlewareresponse.md index 1c9461747077..da43f591c5ad 100644 --- a/aspnetcore/security/authorization/customizingauthorizationmiddlewareresponse.md +++ b/aspnetcore/security/authorization/customizingauthorizationmiddlewareresponse.md @@ -1,8 +1,8 @@ --- title: Customize the behavior of AuthorizationMiddleware -author: rick-anderson +author: tdykstra description: This article explains how to customize the result handling of AuthorizationMiddleware. -ms.author: riande +ms.author: tdykstra monikerRange: '>= aspnetcore-5.0' ms.date: 03/24/2022 uid: security/authorization/authorizationmiddlewareresulthandler diff --git a/aspnetcore/security/authorization/dependencyinjection.md b/aspnetcore/security/authorization/dependencyinjection.md index 96966c70df4b..fb52de15fb2e 100644 --- a/aspnetcore/security/authorization/dependencyinjection.md +++ b/aspnetcore/security/authorization/dependencyinjection.md @@ -1,9 +1,9 @@ --- title: Dependency injection in requirement handlers in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn how to inject authorization requirement handlers into an ASP.NET Core app using dependency injection. monikerRange: ">= aspnetcore-2.1" -ms.author: riande +ms.author: tdykstra ms.date: 03/25/2022 uid: security/authorization/dependencyinjection --- diff --git a/aspnetcore/security/authorization/iard.md b/aspnetcore/security/authorization/iard.md index bbfe547515f1..628ee7d9267a 100644 --- a/aspnetcore/security/authorization/iard.md +++ b/aspnetcore/security/authorization/iard.md @@ -1,8 +1,8 @@ --- title: Custom authorization policies with `IAuthorizationRequirementData` -author: rick-anderson +author: tdykstra description: Learn how to specify requirements associated with the authorization policy in attribute definitions with the IAuthorizationRequirementData interface. -ms.author: riande +ms.author: tdykstra monikerRange: '>= aspnetcore-8.0' ms.date: 5/16/2025 uid: security/authorization/iard diff --git a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md index aacfe774f3bf..81d4d1cfa4c7 100644 --- a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md +++ b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md @@ -2,7 +2,7 @@ title: Custom Authorization Policy Providers in ASP.NET Core author: mjrousos description: Learn how to use a custom IAuthorizationPolicyProvider in an ASP.NET Core app to dynamically generate authorization policies. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 11/14/2019 uid: security/authorization/iauthorizationpolicyprovider diff --git a/aspnetcore/security/authorization/introduction.md b/aspnetcore/security/authorization/introduction.md index c8839940c83b..9b03d680eced 100644 --- a/aspnetcore/security/authorization/introduction.md +++ b/aspnetcore/security/authorization/introduction.md @@ -1,8 +1,8 @@ --- title: Introduction to authorization in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn the basics of authorization and how authorization works in ASP.NET Core apps. -ms.author: riande +ms.author: wpickett ms.date: 10/14/2016 uid: security/authorization/introduction --- diff --git a/aspnetcore/security/authorization/limitingidentitybyscheme.md b/aspnetcore/security/authorization/limitingidentitybyscheme.md index 30d9ec4bea5c..960c2e605d1f 100644 --- a/aspnetcore/security/authorization/limitingidentitybyscheme.md +++ b/aspnetcore/security/authorization/limitingidentitybyscheme.md @@ -1,9 +1,9 @@ --- title: Authorize with a specific scheme in ASP.NET Core -author: rick-anderson +author: wadepickett description: This article explains how to limit identity to a specific scheme when working with multiple authentication methods. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.date: 1/11/2022 uid: security/authorization/limitingidentitybyscheme --- diff --git a/aspnetcore/security/authorization/policies.md b/aspnetcore/security/authorization/policies.md index c164c2bbc3e6..ea3bdb74c917 100644 --- a/aspnetcore/security/authorization/policies.md +++ b/aspnetcore/security/authorization/policies.md @@ -1,9 +1,9 @@ --- title: Policy-based authorization in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to create and use authorization policy handlers for enforcing authorization requirements in an ASP.NET Core app. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 1/5/2023 uid: security/authorization/policies diff --git a/aspnetcore/security/authorization/razor-pages-authorization.md b/aspnetcore/security/authorization/razor-pages-authorization.md index b01ce8a56321..312e0aef181b 100644 --- a/aspnetcore/security/authorization/razor-pages-authorization.md +++ b/aspnetcore/security/authorization/razor-pages-authorization.md @@ -1,9 +1,9 @@ --- title: Razor Pages authorization conventions in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to control access to pages with conventions that authorize users and allow anonymous users to access pages or folders of pages. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 08/12/2019 uid: security/authorization/razor-pages-authorization diff --git a/aspnetcore/security/authorization/roles.md b/aspnetcore/security/authorization/roles.md index 877ecb2a55b6..e69d4b2ad8f3 100644 --- a/aspnetcore/security/authorization/roles.md +++ b/aspnetcore/security/authorization/roles.md @@ -1,8 +1,8 @@ --- title: Role-based authorization in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to restrict ASP.NET Core controller and action access by passing roles to the Authorize attribute. -ms.author: riande +ms.author: wpickett monikerRange: '>= aspnetcore-3.1' ms.date: 10/14/2024 uid: security/authorization/roles diff --git a/aspnetcore/security/authorization/secure-data.md b/aspnetcore/security/authorization/secure-data.md index fbea052a9315..3aedd3557c9b 100644 --- a/aspnetcore/security/authorization/secure-data.md +++ b/aspnetcore/security/authorization/secure-data.md @@ -1,8 +1,8 @@ --- title: Create an ASP.NET Core app with user data protected by authorization -author: rick-anderson +author: tdykstra description: Learn how to create an ASP.NET Core web app with user data protected by authorization. Includes HTTPS, authentication, security, ASP.NET Core Identity. -ms.author: riande +ms.author: tdykstra ms.custom: mvc, sfi-image-nochange ms.date: 12/5/2021 ms.sfi.ropc: t diff --git a/aspnetcore/security/authorization/simple.md b/aspnetcore/security/authorization/simple.md index 7e07de52b436..c6f36bb00575 100644 --- a/aspnetcore/security/authorization/simple.md +++ b/aspnetcore/security/authorization/simple.md @@ -1,8 +1,8 @@ --- title: Simple authorization in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn how to use the Authorize attribute to restrict access to ASP.NET Core controllers and actions. -ms.author: riande +ms.author: tdykstra ms.date: 05/01/2024 uid: security/authorization/simple --- diff --git a/aspnetcore/security/authorization/views.md b/aspnetcore/security/authorization/views.md index 5e14ba8bd563..10c8331fc0fd 100644 --- a/aspnetcore/security/authorization/views.md +++ b/aspnetcore/security/authorization/views.md @@ -1,9 +1,9 @@ --- title: View-based authorization in ASP.NET Core MVC -author: rick-anderson +author: wadepickett description: This document demonstrates how to inject and utilize the authorization service inside of an ASP.NET Core Razor view. -monikerRange: '>= aspnetcore-2.1' -ms.author: riande +monikerRange: '>= aspnetcore-3.1' +ms.author: wpickett ms.date: 11/08/2019 uid: security/authorization/views --- diff --git a/aspnetcore/security/cookie-sharing.md b/aspnetcore/security/cookie-sharing.md index 892489eb1169..1b75a0642562 100644 --- a/aspnetcore/security/cookie-sharing.md +++ b/aspnetcore/security/cookie-sharing.md @@ -1,9 +1,9 @@ --- title: Share authentication cookies among ASP.NET apps -author: rick-anderson +author: wadepickett description: Learn how to share authentication cookies among ASP.NET 4.x and ASP.NET Core apps. monikerRange: '>= aspnetcore-2.1' -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 6/6/2022 uid: security/cookie-sharing diff --git a/aspnetcore/security/data-protection/compatibility/index.md b/aspnetcore/security/data-protection/compatibility/index.md index 9475dfa6a4aa..fa932a31bc64 100644 --- a/aspnetcore/security/data-protection/compatibility/index.md +++ b/aspnetcore/security/data-protection/compatibility/index.md @@ -1,8 +1,8 @@ --- title: Compatibility in ASP.NET Core -author: rick-anderson +author: tdykstra description: This document serves as a table of contents for various ASP.NET Core data protection compatibility topics. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/compatibility/index --- diff --git a/aspnetcore/security/data-protection/compatibility/replacing-machinekey.md b/aspnetcore/security/data-protection/compatibility/replacing-machinekey.md index bb967ec43d41..16eae7c143a3 100644 --- a/aspnetcore/security/data-protection/compatibility/replacing-machinekey.md +++ b/aspnetcore/security/data-protection/compatibility/replacing-machinekey.md @@ -1,8 +1,8 @@ --- title: Replace the ASP.NET machineKey in ASP.NET Core -author: rick-anderson +author: tdykstra description: Discover how to replace machineKey in ASP.NET to allow the use of a new and more secure data protection system. -ms.author: riande +ms.author: tdykstra ms.date: 04/06/2019 uid: security/data-protection/compatibility/replacing-machinekey --- diff --git a/aspnetcore/security/data-protection/consumer-apis/dangerous-unprotect.md b/aspnetcore/security/data-protection/consumer-apis/dangerous-unprotect.md index afd412fb2065..def75e4f067c 100644 --- a/aspnetcore/security/data-protection/consumer-apis/dangerous-unprotect.md +++ b/aspnetcore/security/data-protection/consumer-apis/dangerous-unprotect.md @@ -1,8 +1,8 @@ --- title: Unprotect payloads whose keys have been revoked in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to unprotect data, protected with keys that have since been revoked, in an ASP.NET Core app. -ms.author: riande +ms.author: wpickett ms.custom: mvc ms.date: 10/24/2018 uid: security/data-protection/consumer-apis/dangerous-unprotect diff --git a/aspnetcore/security/data-protection/consumer-apis/limited-lifetime-payloads.md b/aspnetcore/security/data-protection/consumer-apis/limited-lifetime-payloads.md index 816b909f0b95..2732625f5805 100644 --- a/aspnetcore/security/data-protection/consumer-apis/limited-lifetime-payloads.md +++ b/aspnetcore/security/data-protection/consumer-apis/limited-lifetime-payloads.md @@ -1,8 +1,8 @@ --- title: Limit the lifetime of protected payloads in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to limit the lifetime of a protected payload using the ASP.NET Core Data Protection APIs. -ms.author: riande +ms.author: wpickett ms.date: 10/14/2016 uid: security/data-protection/consumer-apis/limited-lifetime-payloads --- diff --git a/aspnetcore/security/data-protection/consumer-apis/password-hashing.md b/aspnetcore/security/data-protection/consumer-apis/password-hashing.md index a1db188269f3..a4584018dbdd 100644 --- a/aspnetcore/security/data-protection/consumer-apis/password-hashing.md +++ b/aspnetcore/security/data-protection/consumer-apis/password-hashing.md @@ -1,8 +1,8 @@ --- title: Hash passwords in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn how to hash passwords using the ASP.NET Core Data Protection APIs. -ms.author: riande +ms.author: wpickett ms.date: 10/14/2016 uid: security/data-protection/consumer-apis/password-hashing --- diff --git a/aspnetcore/security/data-protection/consumer-apis/purpose-strings-multitenancy.md b/aspnetcore/security/data-protection/consumer-apis/purpose-strings-multitenancy.md index 92c3f62e7f7c..00783867aae6 100644 --- a/aspnetcore/security/data-protection/consumer-apis/purpose-strings-multitenancy.md +++ b/aspnetcore/security/data-protection/consumer-apis/purpose-strings-multitenancy.md @@ -1,8 +1,8 @@ --- title: Purpose hierarchy and multi-tenancy in ASP.NET Core -author: rick-anderson +author: wadepickett description: Learn about purpose string hierarchy and multi-tenancy as it relates to the ASP.NET Core Data Protection APIs. -ms.author: riande +ms.author: wpickett ms.date: 10/14/2016 uid: security/data-protection/consumer-apis/purpose-strings-multitenancy --- diff --git a/aspnetcore/security/data-protection/extensibility/core-crypto.md b/aspnetcore/security/data-protection/extensibility/core-crypto.md index 7cb685e6aa12..524f6f75b97b 100644 --- a/aspnetcore/security/data-protection/extensibility/core-crypto.md +++ b/aspnetcore/security/data-protection/extensibility/core-crypto.md @@ -1,8 +1,8 @@ --- title: Core cryptography extensibility in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn about IAuthenticatedEncryptor, IAuthenticatedEncryptorDescriptor, IAuthenticatedEncryptorDescriptorDeserializer, and the top-level factory. -ms.author: riande +ms.author: tdykstra ms.date: 08/11/2017 uid: security/data-protection/extensibility/core-crypto --- diff --git a/aspnetcore/security/data-protection/extensibility/index.md b/aspnetcore/security/data-protection/extensibility/index.md index 6ffce22ea86c..873becbd6912 100644 --- a/aspnetcore/security/data-protection/extensibility/index.md +++ b/aspnetcore/security/data-protection/extensibility/index.md @@ -1,8 +1,8 @@ --- title: ASP.NET Core Data Protection extensibility APIs -author: rick-anderson +author: tdykstra description: Discover the various ASP.NET Core Data Protection extensibility topics. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/extensibility/index --- diff --git a/aspnetcore/security/data-protection/extensibility/key-management.md b/aspnetcore/security/data-protection/extensibility/key-management.md index 728d83d328a3..e4236657b0ea 100644 --- a/aspnetcore/security/data-protection/extensibility/key-management.md +++ b/aspnetcore/security/data-protection/extensibility/key-management.md @@ -1,8 +1,8 @@ --- title: Key management extensibility in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn about ASP.NET Core Data Protection key management extensibility. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 10/24/2018 uid: security/data-protection/extensibility/key-management diff --git a/aspnetcore/security/data-protection/extensibility/misc-apis.md b/aspnetcore/security/data-protection/extensibility/misc-apis.md index 01ac93ea1b36..4ecf5964db7a 100644 --- a/aspnetcore/security/data-protection/extensibility/misc-apis.md +++ b/aspnetcore/security/data-protection/extensibility/misc-apis.md @@ -1,8 +1,8 @@ --- title: Miscellaneous ASP.NET Core Data Protection APIs -author: rick-anderson +author: wadepickett description: Learn about the ASP.NET Core Data Protection ISecret interface. -ms.author: riande +ms.author: wpickett ms.date: 10/14/2016 uid: security/data-protection/extensibility/misc-apis --- diff --git a/aspnetcore/security/data-protection/implementation/authenticated-encryption-details.md b/aspnetcore/security/data-protection/implementation/authenticated-encryption-details.md index c483e849ee6a..6f1e720650b3 100644 --- a/aspnetcore/security/data-protection/implementation/authenticated-encryption-details.md +++ b/aspnetcore/security/data-protection/implementation/authenticated-encryption-details.md @@ -1,8 +1,8 @@ --- title: Authenticated encryption details in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of ASP.NET Core Data Protection authenticated encryption. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/authenticated-encryption-details --- diff --git a/aspnetcore/security/data-protection/implementation/context-headers.md b/aspnetcore/security/data-protection/implementation/context-headers.md index 758c44790b12..087b71e88d53 100644 --- a/aspnetcore/security/data-protection/implementation/context-headers.md +++ b/aspnetcore/security/data-protection/implementation/context-headers.md @@ -1,8 +1,8 @@ --- title: Context headers in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of ASP.NET Core Data Protection context headers. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/context-headers --- diff --git a/aspnetcore/security/data-protection/implementation/index.md b/aspnetcore/security/data-protection/implementation/index.md index 0e493a54c8a6..af6d41eb43e0 100644 --- a/aspnetcore/security/data-protection/implementation/index.md +++ b/aspnetcore/security/data-protection/implementation/index.md @@ -1,8 +1,8 @@ --- title: ASP.NET Core Data Protection implementation -author: rick-anderson +author: tdykstra description: Discover the various ASP.NET Core Data Protection implementation topics. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/index --- diff --git a/aspnetcore/security/data-protection/implementation/key-encryption-at-rest.md b/aspnetcore/security/data-protection/implementation/key-encryption-at-rest.md index 20928373e47f..50acb223ec92 100644 --- a/aspnetcore/security/data-protection/implementation/key-encryption-at-rest.md +++ b/aspnetcore/security/data-protection/implementation/key-encryption-at-rest.md @@ -1,8 +1,8 @@ --- title: Key encryption at rest in Windows and Azure using ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of ASP.NET Core Data Protection key encryption at rest. -ms.author: riande +ms.author: tdykstra ms.date: 06/06/2025 uid: security/data-protection/implementation/key-encryption-at-rest --- diff --git a/aspnetcore/security/data-protection/implementation/key-immutability.md b/aspnetcore/security/data-protection/implementation/key-immutability.md index 4c3b59ca43ec..a9fb76b6785f 100644 --- a/aspnetcore/security/data-protection/implementation/key-immutability.md +++ b/aspnetcore/security/data-protection/implementation/key-immutability.md @@ -1,8 +1,8 @@ --- title: Key immutability and key settings in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn the implementation details of the ASP.NET Core Data Protection key immutability APIs. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/key-immutability --- diff --git a/aspnetcore/security/data-protection/implementation/key-management.md b/aspnetcore/security/data-protection/implementation/key-management.md index 4383876d8740..c399296bac5b 100644 --- a/aspnetcore/security/data-protection/implementation/key-management.md +++ b/aspnetcore/security/data-protection/implementation/key-management.md @@ -1,8 +1,8 @@ --- title: Key management in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of the ASP.NET Core Data Protection key management APIs. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/key-management --- diff --git a/aspnetcore/security/data-protection/implementation/key-storage-ephemeral.md b/aspnetcore/security/data-protection/implementation/key-storage-ephemeral.md index 39ec227b89b1..09d8badb7c66 100644 --- a/aspnetcore/security/data-protection/implementation/key-storage-ephemeral.md +++ b/aspnetcore/security/data-protection/implementation/key-storage-ephemeral.md @@ -1,8 +1,8 @@ --- title: Ephemeral data protection providers in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of the ASP.NET Core ephemeral data protection providers. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/key-storage-ephemeral --- diff --git a/aspnetcore/security/data-protection/implementation/key-storage-format.md b/aspnetcore/security/data-protection/implementation/key-storage-format.md index ebaeb8159ab5..52f78390c763 100644 --- a/aspnetcore/security/data-protection/implementation/key-storage-format.md +++ b/aspnetcore/security/data-protection/implementation/key-storage-format.md @@ -1,8 +1,8 @@ --- title: Key storage format in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of the ASP.NET Core Data Protection key storage format. -ms.author: riande +ms.author: tdykstra ms.date: 04/08/2020 uid: security/data-protection/implementation/key-storage-format --- diff --git a/aspnetcore/security/data-protection/implementation/key-storage-providers.md b/aspnetcore/security/data-protection/implementation/key-storage-providers.md index b13a4750fa97..1b81c5535747 100644 --- a/aspnetcore/security/data-protection/implementation/key-storage-providers.md +++ b/aspnetcore/security/data-protection/implementation/key-storage-providers.md @@ -1,8 +1,8 @@ --- title: Key storage providers in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn about key storage providers in ASP.NET Core and how to configure key storage locations. -ms.author: riande +ms.author: tdykstra ms.date: 06/11/2025 uid: security/data-protection/implementation/key-storage-providers --- diff --git a/aspnetcore/security/data-protection/implementation/subkeyderivation.md b/aspnetcore/security/data-protection/implementation/subkeyderivation.md index 217fe1001a71..0b2cd21c3475 100644 --- a/aspnetcore/security/data-protection/implementation/subkeyderivation.md +++ b/aspnetcore/security/data-protection/implementation/subkeyderivation.md @@ -1,8 +1,8 @@ --- title: Subkey derivation and authenticated encryption in ASP.NET Core -author: rick-anderson +author: tdykstra description: Learn implementation details of ASP.NET Core Data Protection subkey derivation and authenticated encryption. -ms.author: riande +ms.author: tdykstra ms.date: 10/14/2016 uid: security/data-protection/implementation/subkeyderivation --- diff --git a/aspnetcore/security/preventing-open-redirects.md b/aspnetcore/security/preventing-open-redirects.md index 0cd967b36fb1..86a9afa7a0a3 100644 --- a/aspnetcore/security/preventing-open-redirects.md +++ b/aspnetcore/security/preventing-open-redirects.md @@ -2,7 +2,7 @@ title: Prevent open redirect attacks in ASP.NET Core author: ardalis description: Shows how to prevent open redirect attacks against an ASP.NET Core app -ms.author: riande +ms.author: tdykstra ms.date: 07/07/2017 uid: security/preventing-open-redirects --- diff --git a/aspnetcore/security/samesite/mvc21.md b/aspnetcore/security/samesite/mvc21.md index b9165200cf27..9fac0c03c8a3 100644 --- a/aspnetcore/security/samesite/mvc21.md +++ b/aspnetcore/security/samesite/mvc21.md @@ -1,9 +1,9 @@ --- title: ASP.NET Core 2.1 MVC SameSite cookie sample -author: rick-anderson +author: tdykstra description: ASP.NET Core 2.1 MVC SameSite cookie sample monikerRange: '>= aspnetcore-2.1 < aspnetcore-3.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 12/03/2019 uid: security/samesite/mvc21 diff --git a/aspnetcore/security/samesite/rp21.md b/aspnetcore/security/samesite/rp21.md index 56c98460d628..9e237aa126e1 100644 --- a/aspnetcore/security/samesite/rp21.md +++ b/aspnetcore/security/samesite/rp21.md @@ -1,9 +1,9 @@ --- title: ASP.NET Core 2.1 Razor Pages SameSite cookie sample -author: rick-anderson +author: tdykstra description: ASP.NET Core 2.1 Razor Pages SameSite cookie sample monikerRange: '>= aspnetcore-2.1 < aspnetcore-3.0' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 12/03/2019 uid: security/samesite/rp21 diff --git a/aspnetcore/security/samesite/rp31.md b/aspnetcore/security/samesite/rp31.md index e24f7633e368..a3131b83d988 100644 --- a/aspnetcore/security/samesite/rp31.md +++ b/aspnetcore/security/samesite/rp31.md @@ -1,9 +1,9 @@ --- title: ASP.NET Core 3.1 Razor Pages SameSite cookie sample -author: rick-anderson +author: tdykstra description: ASP.NET Core 3.1 Razor Pages SameSite cookie sample monikerRange: '= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 12/03/2019 uid: security/samesite/rp31 diff --git a/aspnetcore/test/load-tests.md b/aspnetcore/test/load-tests.md index 1cacb660d621..0a975027285e 100644 --- a/aspnetcore/test/load-tests.md +++ b/aspnetcore/test/load-tests.md @@ -2,7 +2,7 @@ title: ASP.NET Core load/stress testing author: Jeremy-Meng description: Learn about several tools and approaches for load testing and stress testing ASP.NET Core apps. -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 4/05/2019 uid: test/loadtests diff --git a/aspnetcore/test/middleware.md b/aspnetcore/test/middleware.md index bddc05974767..d98dbc0195b6 100644 --- a/aspnetcore/test/middleware.md +++ b/aspnetcore/test/middleware.md @@ -3,7 +3,7 @@ title: Test ASP.NET Core middleware author: tratcher description: Learn how to test ASP.NET Core middleware with TestServer. monikerRange: '>= aspnetcore-3.1' -ms.author: riande +ms.author: tdykstra ms.custom: mvc ms.date: 05/18/2022 uid: test/middleware diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 6e1f7e1c92f3..b52599b6b67b 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -31,8 +31,6 @@ items: uid: aspnetcore-2.0 - name: What's new in 1.1 uid: aspnetcore-1.1 - - name: What's new in docs - href: whats-new/index.yml - name: Tutorials displayName: tutorial items: @@ -637,7 +635,17 @@ items: - name: Server-side and Blazor Web App additional scenarios uid: blazor/security/additional-scenarios - name: State management - uid: blazor/state-management + items: + - name: Overview + uid: blazor/state-management/index + - name: Prerendered state persistence + uid: blazor/state-management/prerendered-state-persistence + - name: Server + uid: blazor/state-management/server + - name: WebAssembly + uid: blazor/state-management/webassembly + - name: Protected browser storage + uid: blazor/state-management/protected-browser-storage - name: Debug uid: blazor/debug - name: Lazy load assemblies with WebAssembly diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod0.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod0.md deleted file mode 100644 index efd0f5c46460..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod0.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for June 2024" -description: "What's new in the ASP.NET Core docs for June 2024." -ms.custom: June-2024 -ms.date: 07/01/2024 ---- - -# ASP.NET Core docs: What's new for June 2024 - -Welcome to what's new in the ASP.NET Core docs for June 2024. This article lists some of the major changes to docs during this period. - -## Blazor - -### Updated articles - -* - * QuickGrid display name support - * Scaffolding tool doc overhaul with added generators -* - * Document reserved event names - * Clarify interactive requirement for event handlers in BWAs -* - Downloading files with static SSR -* - * Mitigate overposting attacks - * BWA client-side validation requires a circuit -* - BWA client-side validation requires a circuit -* - * Prerendering behavior updates - * Interactive SSR RCs in global WASM/Auto projects - * Detect the current render mode at runtime -* - Blazor Server reconnection coverage -* - Map Static Assets Blazor-specific coverage -* - Update RemoteAuthenticatorView param value -* - * Place code for sample cross-link in MAUI project - * Article updates - * .NET MAUI BH BWA tutorial updates - * Update .NET MAUI BH BWA tutorial - * Clarify per-page/component scenario - * Patch the Pre5 .NET MAUI Blazor Hybrid BWA coverage (PR 2) - * Patch the Pre5 .NET MAUI Blazor Hybrid BWA coverage (PR 1) - * New .NET MAUI Blazor Hybrid template -* - Clarify Blazor trim mode -* - Blazor CLI commands moving to `dotnet watch` -* - Blazor CLI commands moving to `dotnet watch` -* - * Blazor CLI commands moving to `dotnet watch` - * Update Apache coverage (drop CentOS mentions) - * Fix spacing in Apache configuration example -* - Import-Export interop: collocated JS with RCL -* - Use 'reconnection UI' for all references -* - Interactive SSR RCs in global WASM/Auto projects -* - Simplified auth state serialization for BWAs -* - Change Tooling article content layout -* - * Blazor CLI commands moving to `dotnet watch` - * Blazor SignalR tutorial updates - * Blazor SignalR tutorial refactor - -## Client-side development - -### Updated articles - -* - Package installation no longer needed -* - .NET JS interop article updates - -## Fundamentals - -### Updated articles - -* - Scaffolding tool doc overhaul with added generators -* - May Content Health - freshness review -* - Inline code --> snippet references -* - May Content Health - freshness review -* - moniker prep: - -## Getting started - -### Updated articles - -* - May Content Health - freshness review - -## gRPC - -### Updated articles - -* - Dispose gRPC streaming calls -* - Add gRPC perf docs around gracefully completing and disposing streaming calls - -## Hosting and deployment - -### New articles - -* - -### Updated articles - -* - * Revert "refactor azure troubleshooting/1" - * Update index.md -* - Revert "refactor azure troubleshooting/1" - -## Migration - -### Updated articles - -* - Follow-up .NET 8 updates - -## Mobile development - -### Updated articles - -* - Lowercase the code name - -## Performance - -### Updated articles - -* - Add serialization sample app -* - Note about code sample - -## Release notes - -### Updated articles - -* - * Render mode detection, static web asset delivery, dynamic compression - * Add three Blazor What's New sections - -## Security - -### Updated articles - -* - Fix broken links -* - May Content Health - freshness review -* - Scaffolding tool doc overhaul with added generators - -## Testing - -### Updated articles - -* - * refactor azure troubleshooting/1 - -## Tutorials - -### Updated articles - -* - mon split -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - .NET 9 update: Prep RP tutorial series -* - First MVC: Validation: Clear old null values -* - * v9 Update: Min Web API Tutorial - * Prework-Min Web API .NET 9 update -* - .NET 9 update: Prep RP tutorial series - -## Web API - -### Updated articles - -* - May Content Health - freshness review - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [hakenr](https://github.com/hakenr) - Robert Haken ![5 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-5-green) -* [aidmsu](https://github.com/aidmsu) - Andrey Dorokhov ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [DickBaker](https://github.com/DickBaker) - Dick Baker ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [Marjani](https://github.com/Marjani) - AmirHossein ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [saborrie](https://github.com/saborrie) - Steven Borrie ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [waedi](https://github.com/waedi) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod1.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod1.md deleted file mode 100644 index 83c0897d304e..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod1.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for January 2024" -description: "What's new in the ASP.NET Core docs for January 2024." -ms.custom: January-2024 -ms.date: 02/01/2024 ---- - -# ASP.NET Core docs: What's new for January 2024 - -Welcome to what's new in the ASP.NET Core docs for January 2024. This article lists some of the major changes to docs during this period. - -## Blazor - -### New articles - -* - -### Updated articles - -* - - Blazor 8.0 content updates - - Cascading values updates - - Move example code to sample apps -* - - Blazor 8.0 content updates - - Add component example -* - - Blazor 8.0 content updates - - Prerendering and interactive/enhanced routing - - Move example code to sample apps -* - - Blazor 8.0 content updates - - Clarification on prerendering and root components - - Fine control of static SSR - - Clarify Auto render mode behavior - - Apply a render mode programmatically section - - Client services during prerendering -* - - Blazor 8.0 content updates - - Content follow-up updates (8.0) - - "Base address" clarifications for `HttpClient` -* - - Blazor 8.0 content updates - - Custom Blazor WASM loading progress indicator -* - - Blazor 8.0 content updates - - Improve auth state provider guidance - - Add Identity BWA template cross-links -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - - Content follow-up updates (8.0) - - Groups/roles article and Graph article updates -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Content follow-up updates (8.0) -* - Add troubleshooting guidance -* - - Groups/roles article and Graph article updates - - "Base address" clarifications for `HttpClient` -* - - "Base address" clarifications for `HttpClient` - - Client services during prerendering -* - "Base address" clarifications for `HttpClient` -* - "Base address" clarifications for `HttpClient` -* - - "Base address" clarifications for `HttpClient` - - Update save app state example -* - Terminology updates -* - Update PWA guidance -* - Clarify 'content items' (placeholder content) -* - Cascading values updates -* - - Calling base class methods - - Account conf and PW recovery article -* - - Calling base class methods - - Move example code to sample apps -* - - Integration article updates - - RazorComponentResult rendering behavior -* - - Manage InputSelect form options for SSR - - Move example code to sample apps -* - - Blazor CRUD/Quickgrid scaffolder - - Move example code to sample apps -* - Trimming complex framework types (JS interop) -* - Clarify lazy loading is only for dev assemblies -* - App base path enhancements -* - Client services during prerendering -* - Move example code to sample apps -* - Move example code to sample apps -* - Move example code to sample apps -* - Prerendering and interactive/enhanced routing -* - Update JS collocation guidance -* - Custom Blazor WASM loading progress indicator - -## Client-side development - -### Updated articles - -* - libMan limitations /8 - -## Fundamentals - -### Updated articles - -* - - Update env var name - - Fix default value of PreferHostingUrls -* - Fix default value of PreferHostingUrls -* - CreateSimBuilder is missing /7 - -## gRPC - -### New articles - -* - -### Updated articles - -* - Add note to IPC docs that it can't be combined with some channel features -* - Add note to IPC docs that it can't be combined with some channel features - -## Hosting and deployment - -### Updated articles - -* - Update doc author note -* - - DelegateHealthCheck /8 - - sample prep /8 - -## Migration - -### Updated articles - -* - Drop `[Parameter]` for query string params - -## Performance - -### Updated articles - -* - Add Azure Cosmos DB - -## Release notes - -### Updated articles - -* - - Add a note about certificate file watching - - Drop `[Parameter]` for query string params - -## Security - -### Updated articles - -* - - Duplicate new section in the >6.0 moniker block - - Updated app-secrets.md to show how to use user secrets in a console app -* - Update env var name -* - Account conf and PW recovery article -* - Move prior version include to end - -## SignalR - -### Updated articles - -* - GH27996 - SignalR/hubs.md versioning to includes prework - -## Testing - -### Updated articles - -* - Add secret handling and special variables to .http files doc -* - Add example with endpoints to middleware testing doc - -## Tutorials - -### Updated articles - -* - Update getting-started-with-swashbuckle.md - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [ericmutta](https://github.com/ericmutta) - Eric Mutta ![7 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-7-green) -* [PSCourtney](https://github.com/PSCourtney) - Piers Courtney ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [Elanis](https://github.com/Elanis) - Axel ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [harry1911](https://github.com/harry1911) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [jposert](https://github.com/jposert) - Jakub ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [mahdikshk](https://github.com/mahdikshk) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [martincostello](https://github.com/martincostello) - Martin Costello ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [mganss](https://github.com/mganss) - Michael Ganss ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [Nitzantomer1998](https://github.com/Nitzantomer1998) - Nitzan Tomer ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [ptakpiotr](https://github.com/ptakpiotr) - Piotr Ptak ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [richstokoe](https://github.com/richstokoe) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [roxas0zero](https://github.com/roxas0zero) - Abdullah Hashim ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [serpent5](https://github.com/serpent5) - Kirk Larkin ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [steenbokdev](https://github.com/steenbokdev) - Lars ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [Ususucsus](https://github.com/Ususucsus) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [yogyogi](https://github.com/yogyogi) - Yogi ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod2.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod2.md deleted file mode 100644 index 3d5d4bd1e9e3..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod2.md +++ /dev/null @@ -1,217 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for February 2024" -description: "What's new in the ASP.NET Core docs for February 2024." -ms.custom: February-2024 -ms.date: 03/01/2024 ---- - -# ASP.NET Core docs: What's new for February 2024 - -Welcome to what's new in the ASP.NET Core docs for February 2024. This article lists some of the major changes to docs during this period. - -## Miscellaneous - - -## Blazor - -### New articles - -* - -### Updated articles - -* - - Blazor troubleshooting guidance updates - - Redirect to the home page - - Blazor Web App with OIDC article -* - Add QuickGrid API cross-links -* - - Ctor service injection - - Services via the top-level imports file - - Clarify "subset" of .NET API remark - - Transient "disposable" service language updates - - Cross-link (don't show) example code - - Update transient services guidance -* - - Move handle errors section - - Lifecycle methods call ordering -* - - Move handle errors section - - Blazor Synchronization contxt - draw sample code -* - - Move handle errors section - - Update DispatchExceptionAsync example - - Update render mode guidance for error boundaries -* - Update deep linking guidance -* - Inline form updates for conventions -* - Inline form updates for conventions -* - - Inline form updates for conventions - - Routing - use @key in NavLink loop warning (instead of NavLink href) - - Avoid referring to components or RenderFragment parameters as "tags" -* - Inline form updates for conventions -* - Services via the top-level imports file -* - - Update component ref text and examples - - Update Route params section -* - Update Todo component -* - - Add WebAssembly (runtime) startup callbacks - - Blazor Startup - sample environment variable name - - Startup - manually start Standalone Blazor WebAssembly -* - Add roles and test user guidance -* - [Blazor] SignalR - remove "using System" reminder -* - Update 'Blazor Server' references -* - - Update "ASP.NET Core" references - - Clarify "subset" of .NET API remark -* - Clarify "subset" of .NET API remark -* - Improve Blazor Environments article -* - Include a VSC path for resource files -* - Offline discussion updates for 8.0 -* - Offline discussion updates for 8.0 -* - Offline discussion updates for 8.0 -* - Offline discussion updates for 8.0 -* - Offline discussion updates for 8.0 -* - Revise built-in components list -* - Revise built-in components list -* - - Add a remarks on ClaimsPrincipal use - - Avoid referring to components or RenderFragment parameters as "tags" -* - - Debugging article updates - - Final round of debugging updates - - Debug article follow-up 8.0 -* - Document Static Web Asset Project Mode - -## Client-side development - -### Updated articles - -* - Moniker prep - -## Fundamentals - -### Updated articles - -* - Middleware in Minimal API: Add links -* - Update to Native capitalization -* - Update to Native capitalization -* - Update to Native capitalization -* - filters -* - Remove generic host -* - RouteDataRequestCultureProvider /8 - -## gRPC - -### Updated articles - -* - Update to Native capitalization - -## Migration - -### New articles - -* - -### Updated articles - -* - - Add step to hosted Blazor WASM migration guidance - - Update hosted WASM-to-BWA guidance -* - - migration to 9 - - Blazor What's New guidance - -## Performance - -### Updated articles - -* - Update rate-limit.md - -## Razor Pages - -### Updated articles - -* - RCL, adding static web assets - -## Release notes - -### New articles - -* - -### Updated articles - -* - - .NET 9 Preview 1 - - Blazor What's New guidance - - What's new in ASP.NET Core in .NET 9 -* - Update to Native capitalization - -## Security - -### Updated articles - -* - Manually set assembly info attribute -* - Note that Entra External ID tenants also use SingleOrg for --auth option -* - Blazor Web App with OIDC article -* - Add ChainTrustValidationMode and CustomTrustStore properties to certauth.md - -## SignalR - -### Updated articles - -* - SignaR Security: Point to customizing CORS middleware -* - - SignalR Redis Backplane update and fix - - SignalR: Redis Backplane: Change to include versioning - -## Testing - -### Updated articles - -* - - remove deprecated ISystemClock - - Explain integration test WebHostBuilderSection - -## Tutorials - -### Updated articles - -* - Min Web API tutorial: Remove prerelease for packages -* - VSC improvements for Razor Pages and MVC Tutorials -* - VSC improvements for Razor Pages and MVC Tutorials -* - VSC improvements for Razor Pages and MVC Tutorials -* - VSC improvements for Razor Pages and MVC Tutorials -* - VSC improvements for Razor Pages and MVC Tutorials -* - VSC improvements for Razor Pages and MVC Tutorials -* - Update getting-started-with-swashbuckle.md -* - - Improve description of the UseSwaggerUI method - - Update getting-started-with-swashbuckle.md -* - - Razor Pages Get Started: Fix VS Code and MacOS explanation for Up - - edit validation.md: use `dotnet ef database update` in Visual Studio Code section. Use `Update-Database` in Visual Studio section -* - edit search.md: in Note that describes LINQ Contains and SQLite case (in)sensitivity, include links in the Note instead of outside - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [hakenr](https://github.com/hakenr) - Robert Haken ![17 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-17-green) -* [stanimirovv](https://github.com/stanimirovv) - Zlatin Stanimirov ![6 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-6-green) -* [yogyogi](https://github.com/yogyogi) - Yogi ![4 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-4-green) -* [zipperer](https://github.com/zipperer) - Andrew Zipperer ![3 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-3-green) -* [timdeschryver](https://github.com/timdeschryver) - Tim Deschryver ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [0xced](https://github.com/0xced) - Cédric Luthi ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [andrerom](https://github.com/andrerom) - André R. ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [aterbo](https://github.com/aterbo) - aterbo ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [Burke-Chris](https://github.com/Burke-Chris) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [CadeMH](https://github.com/CadeMH) - Cade ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [damienbod](https://github.com/damienbod) - damienbod ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [edwardneal](https://github.com/edwardneal) - Edward Neal ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [ilmalte](https://github.com/ilmalte) - Daniele Maltese ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [jufa2401](https://github.com/jufa2401) - Justin Fabricius ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [StormPooper](https://github.com/StormPooper) - Daniel Smith ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [thabaum](https://github.com/thabaum) - Cody ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod3.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod3.md deleted file mode 100644 index 9b63bcca017c..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod3.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for March 2024" -description: "What's new in the ASP.NET Core docs for March 2024." -ms.custom: March-2024 -ms.date: 04/01/2024 ---- - -# ASP.NET Core docs: What's new for March 2024 - -Welcome to what's new in the ASP.NET Core docs for March 2024. This article lists some of the major changes to docs during this period. - -## Blazor - -### Updated articles - -* - Update Azure SignalR Service remarks -* - * Improve authorization opening remarks - * Add coverage on antiforgery services and middleware - * Server-side behaviors during static SSR - * WebSocket compression/CSP and security guidance - * WASM+Identity same-site & antiforgery updates -* - * Updates to compression warning content - * Surface warning on compression for interactive SSR -* - * Add remark on ME-ID authority in server API config - * Update scope/authority guidance in BWA+OIDC article - * Add VS prerequisite version - * Nonce update for token refresh -* - Add coverage on antiforgery services and middleware -* - Control content and migration updates -* - * Clarify app settings file locations - * Remove article front matter -* - Improved Project Structure article WASM headings -* - * [Blazor] Lifecycle - AfterRender.razor sample update + console output added - * Graph scopes clarification and addl updates - * [Blazor] Lifecycle - clear formulation for conditions when rendering is avoided -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Graph scopes clarification and addl updates -* - Add sample app cross-links to JS/SPA article -* - * [Blazor] Event handling - ParentChild2.razor without Task.Yield() - * [Blazor] Event handling - first InvokeAsync example with args -* - Dependency on DBContext for Blazor Identity UI -* - * Updates to 'click'-based remarks - * Server-side behaviors during static SSR - * WebSocket compression/CSP and security guidance -* - Static files article updates -* - * Harden API options - * Improve SignalR idle timeout example - * Update Blazor release notes for Preview 2 - * WebSocket compression/CSP and security guidance -* - Server-side behaviors during static SSR -* - Server-side behaviors during static SSR -* - Temporarily surface PU issue for access tokens -* - * Blazor WASM cookie security for web APIs - * PATCH section and other updates - * Drop prop and field in examples - * Call (web) API security updates - * Additional Call web API article updates - * Call web API article updates - * Drop pivots and sample code -* - Add Bootstrap to Blazor Hybrid tutorials -* - [Blazor] OverridingParameters - ShowMoreExpander, ToggleExpander -* - * Blazor-specific 'how to download' guidance - * Clarify sample location - * Remove article front matter -* - Blazor-specific 'how to download' guidance -* - Blazor-specific 'how to download' guidance -* - Blazor - data-binding - event fix -* - WebSocket compression/CSP and security guidance -* - Add BWA global Auto approach -* - WASM+Identity same-site & antiforgery updates - -## Fundamentals - -### Updated articles - -* - Fix typo -* - Update index.md - -## Migration - -### New articles - -* - -### Updated articles - -* - * Add coverage on antiforgery services and middleware - * Control content and migration updates - * Blazor Server script fallback policy authorization -* - * move snippets to code sample - * Add doc for incrementally migration IHttpModule implementations - -## Performance - -### Updated articles - -* - Update API Testing tool references - -## Release notes - -### Updated articles - -* - Add preview 2 features - -## Security - -### Updated articles - -* - Convert inline code to snippet references - -## Tutorials - -### Updated articles - -* - Min API tutorial: rewrite to Swagger - -## Web API - -### Updated articles - -* - Update API Testing tool references - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [hakenr](https://github.com/hakenr) - Robert Haken ![21 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-21-green) -* [BusHero](https://github.com/BusHero) - Cervac Petru ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [danespinosa](https://github.com/danespinosa) - Dan Espinosa ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [drewnoakes](https://github.com/drewnoakes) - Drew Noakes ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [fbaptista](https://github.com/fbaptista) - Fabian ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [fredrikcarlbom](https://github.com/fredrikcarlbom) - Fredrik C ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [Jessuhh](https://github.com/Jessuhh) - Jesse Brand ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [markharwood101](https://github.com/markharwood101) - Mark Harwood ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [reyang](https://github.com/reyang) - Reiley Yang ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [StefanOssendorf](https://github.com/StefanOssendorf) - Stefan Ossendorf ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [timdeschryver](https://github.com/timdeschryver) - Tim Deschryver ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod4.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod4.md deleted file mode 100644 index b3a3fdf75ef9..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod4.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for April 2024" -description: "What's new in the ASP.NET Core docs for April 2024." -ms.custom: April-2024 -ms.date: 05/01/2024 ---- - -# ASP.NET Core docs: What's new for April 2024 - -Welcome to what's new in the ASP.NET Core docs for April 2024. This article lists some of the major changes to docs during this period. - -## Blazor - -### New articles - -* -* -* -* - -### Updated articles - -* - Update QuickGrid guidance -* - Improve guidance on security config with app settings files -* - - Clear forms and fields - - Improve @formname coverage -* - [Blazor] Globalization & localization - correct async JS interop -* - Blazor WASM build tools + AOT article -* - QR code generation article for BWAs -* - [Blazor] Logging - comments for "magic numbers" -* - Guidance on dynamic NavLink generation -* - - Revise content on the reconnection UI delay - - Improve SignalR connection guidance -* - [Blazor] Templated components - TemplatedNavBar + keyed TableTemplate -* - Blazor WASM build tools + AOT article -* - Generic type article improvements -* - - Improve lifecycle method remarks - - Revise setting parameters lifecycle remarks - - Improve `SetParametersAsync` base method coverage -* - [Blazor] Virtualization - data slicing clarification -* - - Clarify conditional HTML element attributes - - Distinguish Razor components -* - Dedicated article on JS location -* - Dedicated article on JS location -* - Add Debugger support section -* - [Blazor] DynamicComponents - fixes samples vulnerability + related adjustments -* - - Blazor WASM build tools + AOT article - - WASM runtime max heap size -* - - Improve IIS crosslinking and additional deployment updates - - Blazor WASM build tools + AOT article - - Memory management updates - - Improve SignalR connection guidance -* - Add additional scope guidance -* - - OIDC Blazor authentication text improvements - - Clarify use of IHttpContextAccessor/HttpContext -* - Shorten class name - -## Fundamentals - -### Updated articles - -* - .NET 9 endpoint metadata on error handling page -* - - .NET 9 moniker prep for 500 status code TypedResults - - Update not-latest and not-current include files - - .NET 9 new feature - Internal Server Error TypedResults on Responses page -* - Update not-latest and not-current include files -* - - No swag - - Mon prep -* - fix RDG highlights after code samples update -* - Refresh my top 10 topics: WebSockets - -## gRPC - -### Updated articles - -* - Add docs for WinHttpHandler and multiple connections -* - Test gRPC: Update API test Tooling - -## Hosting and deployment - -### Updated articles - -* - Fix documentation about how X-Original-* headers are populated - -## Mobile development - -### Updated articles - -* - Native Mobile Backend. - -## MVC - -### Updated articles - -* - Update API test tool: Custom Model Binding -* - Improve @formname coverage -* - fix highlight and style in snippets - -## Release notes - -### Updated articles - -* - .NET 9 - endpoint metadata on what's new - -## Security - -### Updated articles - -* - QR code generation article for BWAs -* - Moniker prep for .NET 9 content - -## SignalR - -### Updated articles - -* - SignalR: Clarify groups - -## Tutorials - -### Updated articles - -* - WebAPI MongoDB: Clarify steps -* - - Swagger Update: web-api-help-pages: Sample fix - - fix Swag - - Doc With Swagger: Enable only in dev env - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [hakenr](https://github.com/hakenr) - Robert Haken ![10 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-10-green) -* [timdeschryver](https://github.com/timdeschryver) - Tim Deschryver ![5 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-5-green) -* [damienbod](https://github.com/damienbod) - damienbod ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [sousadiego11](https://github.com/sousadiego11) - Diego Sousa ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [andriibratanin](https://github.com/andriibratanin) - Andrii Bratanin ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [ceddy4395](https://github.com/ceddy4395) - Cedric ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [joegoldman2](https://github.com/joegoldman2) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [ndc](https://github.com/ndc) - Endy Tjahjono ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [PawelAdamczuk](https://github.com/PawelAdamczuk) - Paweł Adamczuk ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [plasmarocker](https://github.com/plasmarocker) - Jonathan Carter ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod5.md b/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod5.md deleted file mode 100644 index c70294445517..000000000000 --- a/aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod5.md +++ /dev/null @@ -1,180 +0,0 @@ ---- -title: "ASP.NET Core docs: What's new for May 2024" -description: "What's new in the ASP.NET Core docs for May 2024." -ms.custom: May-2024 -ms.date: 06/01/2024 ---- - -# ASP.NET Core docs: What's new for May 2024 - -Welcome to what's new in the ASP.NET Core docs for May 2024. This article lists some of the major changes to docs during this period. - -## Blazor - -### New articles - -* - -### Updated articles - -* - Add OverscanCount to ref article -* - Update cascading auth state service requirements -* - Bound field or property expression convention -* - Maximum parallel invocations per client remark -* - - More hints on interactivity for doc components - - New .NET MAUI BWA with shared UI article -* - Location override using the "Sensors" pane -* - Surface new tutorial in tutorial list -* - - More hints on interactivity for doc components - - Static SSR pages in a globally-interactive app -* - - Maximum parallel invocations per client remark - - Inform readers on support status of stateful reconnect -* - More hints on interactivity for doc components -* - RCLs for Blazor apps that support pages+views -* - - Azure Container Apps updates - - Inform readers on support status of stateful reconnect -* - - Add OverscanCount to ref article - - Add cross-link to new guidance -* - Remark on ownership of service API registration -* - - BlazorWebAppOidcBff Aspire article updates - - Add product unit issue cross-link -* - Update ref source links to Blazor security API -* - Add OverscanCount to ref article -* - More hints on interactivity for doc components -* - Update "CLI" tab controls - -## Data access - -### Updated articles - -* - Update "CLI" tab controls - -## Fundamentals - -### New articles - -* - -### Updated articles - -* - - Update install package instructions. - - Bring back OpenAPI package installation instructions - - Move up ## Customize OpenAPI endpoints with endpoint metadata - - Edit OpenAPI doc - - Update docs on OpenAPI-related metadata - - Bump Swashbuckle versions - - Update Scalar docs to use Scalar.AspNetCore package - - Update Swashbuckle documentation - - Add content on endpoint customization and Scalar docs - - Post-PR review. - - Add docs on Microsoft.AspNetCore.OpenApi -* - Document the Preview 4 developer exception page -* - Location override using the "Sensors" pane -* - Add publishtrimmed note -* - Update "CLI" tab controls - -## gRPC - -### Updated articles - -* - gRPC Health Checks: Add client factory example - -## Hosting and deployment - -### Updated articles - -* - Document ShutdownDelay -* - Add doc about X-Forwarded-Prefix/X-Original-Prefix -* - Update "CLI" tab controls -* - Update building-net-docker-images.md -* - Update "CLI" tab controls - -## Migration - -### Updated articles - -* - Hosted WASM to BWA migration updates - -## Performance - -### New articles - -* - -### Updated articles - -* - - Document .NET 9 new feature - HybridCache - - Moniker prep for 9.0 content - -## Release notes - -### Updated articles - -* - SignalR:H ubConnectionBuild: Update to withServerTimeout and withKeepAlive -* - - What's new OpenAPI - - HybridCache in What's new doc - -## Security - -### Updated articles - -* - Update "CLI" tab controls -* - Update "CLI" tab controls -* - - Mon prep - - content health -* - Update key-vault-configuration.md -* - DataProtection Blob warning -* - Update "CLI" tab controls -* - - move up linux-dev-certs - - linux-dev-certs easy -* - Implement IEmailSender to customize emails -* - Update "CLI" tab controls -* - Update "CLI" tab controls -* - Add a Prerequisites section - -## SignalR - -### Updated articles - -* - SignalR:H ubConnectionBuild: Update to withServerTimeout and withKeepAlive - -## Tutorials - -### Updated articles - -* - Update "CLI" tab controls -* - First MVC: Clarify project location has no restriction -* - Update "CLI" tab controls -* - - Update "CLI" tab controls - - Bump Swashbuckle versions - - Update Swashbuckle documentation -* - - First Web API: Linux: Add tools path - - First Web API: no loc correction for New Scaffolded Item menu - -## Community contributors - -The following people contributed to the ASP.NET Core docs during this period. Thank you! Learn how to contribute by following the links under "Get involved" in the [what's new landing page](index.yml). - -* [martincostello](https://github.com/martincostello) - Martin Costello ![3 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-3-green) -* [hakenr](https://github.com/hakenr) - Robert Haken ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [joegoldman2](https://github.com/joegoldman2) - ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [kevinchalet](https://github.com/kevinchalet) - Kévin Chalet ![2 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-2-green) -* [azarboon](https://github.com/azarboon) - Mahdi Azarboon ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [capdiem](https://github.com/capdiem) - capdiem ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [JonathanBout](https://github.com/JonathanBout) - Jonathan Bout ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [jpbulman](https://github.com/jpbulman) - JP Bulman ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [MrXhh](https://github.com/MrXhh) - 小辉辉 ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) -* [tuhlaajapoika](https://github.com/tuhlaajapoika) - ![1 pull requests.](https://img.shields.io/badge/Merged%20Pull%20Requests-1-green) diff --git a/aspnetcore/whats-new/index.yml b/aspnetcore/whats-new/index.yml deleted file mode 100644 index 814b2e305c54..000000000000 --- a/aspnetcore/whats-new/index.yml +++ /dev/null @@ -1,67 +0,0 @@ -### YamlMime:Landing - -title: ASP.NET Core documentation - what's new? -summary: Welcome to what's new in ASP.NET Core docs. Use this page to quickly find the latest changes. -metadata: - title: ASP.NET Core documentation - What's new? - description: Learn about new and updated content in ASP.NET Core docs. - ms.author: wpickett - ms.date: 07/01/2024 - ms.topic: landing-page -landingContent: -- title: Find ASP.NET Core docs updates - linkLists: - - linkListType: whats-new - links: - - text: June 2024 - url: dotnet-AspNetCore.Docs-mod0.md - - text: May 2024 - url: dotnet-AspNetCore.Docs-mod5.md - - text: April 2024 - url: dotnet-AspNetCore.Docs-mod4.md - - text: March 2024 - url: dotnet-AspNetCore.Docs-mod3.md - - text: February 2024 - url: dotnet-AspNetCore.Docs-mod2.md - - text: January 2024 - url: dotnet-AspNetCore.Docs-mod1.md -- title: Get involved - contribute to ASP.NET Core docs - linkLists: - - linkListType: overview - links: - - text: ASP.NET Core docs repository - url: https://github.com/dotnet/AspNetCore.Docs/blob/main/README.md - - text: Project structure and labels for issues and pull requests - url: https://github.com/dotnet/docs/blob/main/styleguide/labels-projects.md - - linkListType: concept - links: - - text: Contributor guide - url: /contribute - - text: ASP.NET Core docs contributor guide - url: https://github.com/dotnet/AspNetCore.Docs/blob/main/CONTRIBUTING.md - - text: ASP.NET Core API reference docs contributor guide - url: https://github.com/dotnet/AspNetApiDocs/blob/main/CONTRIBUTING.md -- title: Community - linkLists: - - linkListType: whats-new - links: - - text: Community - url: https://dotnet.microsoft.com/platform/community -- title: Related what's new pages - linkLists: - - linkListType: whats-new - links: - - text: .NET Multi-platform App UI (.NET MAUI) docs updates - url: /dotnet/maui/whats-new/ - - text: .NET Core release notes - url: https://github.com/dotnet/core/blob/main/release-notes/README.md - - text: ASP.NET Core release notes - url: ../release-notes/aspnetcore-3.1.md - - text: C# compiler (Roslyn) release notes - url: https://github.com/dotnet/roslyn/tree/main/docs/ide - - text: Visual Studio release notes - url: /visualstudio/releases/2019/release-notes - - text: Visual Studio for Mac release notes - url: /visualstudio/releasenotes/vs2019-mac-relnotes - - text: Visual Studio Code release notes - url: https://code.visualstudio.com/updates diff --git a/aspnetcore/whats-new/toc.yml b/aspnetcore/whats-new/toc.yml deleted file mode 100644 index 132e90eafa23..000000000000 --- a/aspnetcore/whats-new/toc.yml +++ /dev/null @@ -1,17 +0,0 @@ -items: -- name: What's new - href: index.yml - expanded: true - items: - - name: June 2024 - href: dotnet-AspNetCore.Docs-mod0.md - - name: May 2024 - href: dotnet-AspNetCore.Docs-mod5.md - - name: April 2024 - href: dotnet-AspNetCore.Docs-mod4.md - - name: March 2024 - href: dotnet-AspNetCore.Docs-mod3.md - - name: February 2024 - href: dotnet-AspNetCore.Docs-mod2.md - - name: January 2024 - href: dotnet-AspNetCore.Docs-mod1.md