Skip to content

Commit 0d8c178

Browse files
authored
Merge pull request #36854 from dotnet/main
Merge to Live
2 parents 258ff94 + b295908 commit 0d8c178

217 files changed

Lines changed: 1140 additions & 163280 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

aspnetcore/blazor/state-management/server.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: ASP.NET Core Blazor server-side state management
3+
ai-usage: ai-assisted
34
author: guardrex
45
description: Learn how to persist user data (state) in server-side Blazor apps.
56
monikerRange: '>= aspnetcore-3.1'
@@ -195,6 +196,156 @@ An app can only persist *app state*. UIs can't be persisted, such as component i
195196

196197
## Server-side storage
197198

199+
:::moniker range=">= aspnetcore-11.0"
200+
201+
Data can be stored temporarily or permanently in server-side scenarios.
202+
203+
### Temporary data persistence
204+
205+
<!-- UPDATE 11.0 - API cross-links -->
206+
207+
To persist temporary data between HTTP requests during static server-side rendering (static SSR), Blazor supports `TempData`. `TempData` is ideal for scenarios such as flash messages after form submissions, passing data during redirects (POST-Redirect-GET pattern), and one-time notifications.
208+
209+
`TempData`:
210+
211+
* Is available when <xref:Microsoft.Extensions.DependencyInjection.RazorComponentsServiceCollectionExtensions.AddRazorComponents%2A> is called in the app's `Program` file.
212+
* Is provided as a cascading value with the [`[CascadingParameter]` attribute](xref:blazor/components/cascading-values-and-parameters#cascadingparameter-attribute).
213+
* Is accessed by key (string).
214+
* Supports primitives, <xref:System.DateTime>, <xref:System.Guid>, enums, and collections (arrays, <xref:System.Collections.Generic.List%601>, <xref:System.Collections.Generic.Dictionary%602>).
215+
* Stores `object?` values, requiring runtime casting (example: `var message = TempData["Message"] as string`). IntelliSense and type checking aren't supported.
216+
* Uses case-insensitive keys, so `TempData["message"]` and `TempData["Message"]` retrieve the same value.
217+
218+
```csharp
219+
[CascadingParameter]
220+
public ITempData? TempData { get; set; }
221+
```
222+
223+
The `ITempData` interface provides the following methods for controlling value lifecycle:
224+
225+
* `Get`: Gets the value associated with the specified key and schedules the data for deletion.
226+
* `Peek`: Returns the value associated with the specified key without marking the data for deletion.
227+
* `Keep`: Marks all keys in the dictionary for retention. Values are available on the next request.
228+
* `Keep(string)`: Marks a specified key (string) for retention. The value is available on the next request.
229+
230+
Data stored in `TempData` is automatically removed after the data is read unless `Keep`/`Keep(string)` is called or the data is accessed via `Peek`.
231+
232+
The default cookie-based provider uses [Data Protection](xref:security/data-protection/introduction) for encryption.
233+
234+
Call `AddCookieTempDataValueProvider` on the service collection in the app's `Program` file passing `CookieTempDataProviderOptions` to change the cookie's parameters in the following table.
235+
236+
Parameter | API | Default value
237+
--- | --- | ---
238+
Name | `Name` | `.AspNetCore.Components.TempData`
239+
[HTTP Only](https://developer.mozilla.org/docs/Web/Security/Practical_implementation_guides/Cookies#httponly) | `HttpOnly` | `true`
240+
[SameSite value](https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) | `SameSite` | <xref:Microsoft.AspNetCore.Http.SameSiteMode.Strict?displayProperty=nameWithType>
241+
Secure policy | `SecurePolicy` | [`CookieSecurePolicy.Always`](xref:Microsoft.AspNetCore.Http.CookieSecurePolicy)
242+
243+
Example (sets default values):
244+
245+
```csharp
246+
builder.Services.AddRazorComponents(options =>
247+
{
248+
options.TempDataCookie.Name = ".AspNetCore.Components.TempData";
249+
options.TempDataCookie.HttpOnly = true;
250+
options.TempDataCookie.SameSite = SameSiteMode.Strict;
251+
options.TempDataCookie.SecurePolicy = CookieSecurePolicy.Always;
252+
});
253+
```
254+
255+
Only JSON-serializable primitives and collections are supported. User-defined classes and custom object serialization aren't supported. Blazor WebAssembly and Blazor Server aren't supported.
256+
257+
A `SessionStorageTempDataProvider` is available as an alternative to the default `CookieTempDataProvider`. Using cookie and session storage simultaneously isn't supported.
258+
259+
Session storage:
260+
261+
* Requires explicit session state configuration.
262+
* Has no practical size limits (within session constraints).
263+
* Requires session affinity (sticky sessions) in load-balanced environments. Without it, users may lose data. For more information, see <xref:blazor/fundamentals/signalr#use-session-affinity-sticky-sessions-for-server-side-web-farm-hosting>.
264+
265+
Session storage configuration:
266+
267+
```csharp
268+
builder.Services.AddDistributedMemoryCache();
269+
builder.Services.AddSession();
270+
271+
builder.Services.Configure<RazorComponentsServiceOptions>(options =>
272+
{
273+
options.TempDataProviderType = TempDataProviderType.SessionStorage;
274+
});
275+
276+
...
277+
278+
app.UseSession();
279+
```
280+
281+
Browsers enforce a 4 KB cookie size limit. `TempData` automatically uses <xref:Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager> to split cookies across multiple cookie headers, but developers storing a large amount of data must switch to session storage, which introduces session affinity requirements.
282+
283+
In the following example, a form displays a message that's retained in `TempData` after the form is submitted (a new request).
284+
285+
`Pages/TempDataExample.razor`:
286+
287+
```razor
288+
@page "/tempdata-example"
289+
@inject NavigationManager NavigationManager
290+
291+
<p>@message</p>
292+
293+
<form @onsubmit="HandleSubmit">
294+
<button type="submit">Submit</button>
295+
</form>
296+
297+
@code {
298+
[CascadingParameter]
299+
public ITempData? TempData { get; set; }
300+
301+
private string? message;
302+
303+
protected override void OnInitialized()
304+
{
305+
// Get removes the value after reading (one-time use)
306+
message = TempData?.Get("Message") as string ?? "No message";
307+
}
308+
309+
private void HandleSubmit()
310+
{
311+
TempData!["Message"] = "Form submitted successfully!";
312+
NavigationManager.NavigateTo("/tempdata-example", forceLoad: true);
313+
}
314+
}
315+
```
316+
317+
Reading without deleting (`Peek`):
318+
319+
```csharp
320+
protected override void OnInitialized()
321+
{
322+
var notification = TempData?.Peek("Message") as string;
323+
}
324+
```
325+
326+
Keep a specific value for another request (`Keep(string)`):
327+
328+
```csharp
329+
protected override void OnInitialized()
330+
{
331+
var message = TempData?.Get("Message") as string;
332+
TempData?.Keep("Message");
333+
}
334+
```
335+
336+
Keep all values for another request (`Keep`):
337+
338+
```csharp
339+
protected override void OnInitialized()
340+
{
341+
TempData?.Keep();
342+
}
343+
```
344+
345+
### Permanent data persistence
346+
347+
:::moniker-end
348+
198349
For permanent data persistence that spans multiple users and devices, the app can use server-side storage. Options include:
199350

200351
* Blob storage

0 commit comments

Comments
 (0)