Skip to content

Commit dc1cf03

Browse files
authored
Blazor with EF Core article updates 8.0 (#30405)
1 parent 4fa6aaa commit dc1cf03

File tree

5 files changed

+79
-24
lines changed

5 files changed

+79
-24
lines changed

.openpublishing.redirection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,11 @@
12521252
"source_path": "aspnetcore/blazor/tutorials/signalr-blazor-preview.md",
12531253
"redirect_url": "/aspnet/core/blazor/tutorials/signalr-blazor",
12541254
"redirect_document_id": false
1255+
},
1256+
{
1257+
"source_path": "aspnetcore/blazor/blazor-server-ef-core.md",
1258+
"redirect_url": "/aspnet/core/blazor/blazor-ef-core",
1259+
"redirect_document_id": false
12551260
}
12561261
]
12571262
}

aspnetcore/blazor/blazor-server-ef-core.md renamed to aspnetcore/blazor/blazor-ef-core.md

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
11
---
2-
title: ASP.NET Core Blazor Server with Entity Framework Core (EF Core)
2+
title: ASP.NET Core Blazor with Entity Framework Core (EF Core)
33
author: guardrex
4-
description: Learn how to use Entity Framework Core (EF Core) in Blazor Server apps.
4+
description: Learn how to use Entity Framework Core (EF Core) in Blazor apps.
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: jeliknes
77
ms.custom: mvc
88
ms.date: 03/27/2023
9-
uid: blazor/blazor-server-ef-core
9+
uid: blazor/blazor-ef-core
1010
---
11-
# ASP.NET Core Blazor Server with Entity Framework Core (EF Core)
11+
# ASP.NET Core Blazor with Entity Framework Core (EF Core)
1212

1313
[!INCLUDE[](~/includes/not-latest-version.md)]
1414

15-
This article explains how to use [Entity Framework Core (EF Core)](/ef/core/) in Blazor Server apps.
15+
This article explains how to use [Entity Framework Core (EF Core)](/ef/core/) in server-side Blazor apps.
1616

17-
Blazor Server is a stateful app framework. The app maintains an ongoing connection to the server, and the user's state is held in the server's memory in a *circuit*. One example of user state is data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances that are scoped to the circuit. The unique application model that Blazor Server provides requires a special approach to use Entity Framework Core.
17+
Server-side Blazor is a stateful app framework. The app maintains an ongoing connection to the server, and the user's state is held in the server's memory in a *circuit*. One example of user state is data held in [dependency injection (DI)](xref:fundamentals/dependency-injection) service instances that are scoped to the circuit. The unique application model that Blazor provides requires a special approach to use Entity Framework Core.
1818

1919
> [!NOTE]
20-
> This article addresses EF Core in Blazor Server apps. Blazor WebAssembly apps run in a WebAssembly sandbox that prevents most direct database connections. Running EF Core in Blazor WebAssembly is beyond the scope of this article.
20+
> This article addresses EF Core in server-side Blazor apps. Blazor WebAssembly apps run in a WebAssembly sandbox that prevents most direct database connections. Running EF Core in Blazor WebAssembly is beyond the scope of this article.
2121
2222
## Sample app
2323

24-
The sample app was built as a reference for Blazor Server apps that use EF Core. The sample app includes a grid with sorting and filtering, delete, add, and update operations. The sample demonstrates use of EF Core to handle optimistic concurrency.
24+
The sample app was built as a reference for server-side Blazor apps that use EF Core. The sample app includes a grid with sorting and filtering, delete, add, and update operations. The sample demonstrates use of EF Core to handle optimistic concurrency.
2525

2626
[View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:index#how-to-download-a-sample))
2727

2828
The sample uses a local [SQLite](https://www.sqlite.org/index.html) database so that it can be used on any platform. The sample also configures database logging to show the SQL queries that are generated. This is configured in `appsettings.Development.json`:
2929

30-
:::moniker range=">= aspnetcore-7.0"
30+
:::moniker range=">= aspnetcore-8.0"
31+
32+
:::code language="json" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/appsettings.Development.json" highlight="8":::
33+
34+
:::moniker-end
35+
36+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0"
3137

3238
:::code language="json" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/appsettings.Development.json" highlight="8":::
3339

@@ -58,13 +64,13 @@ The grid, add, and view components use the "context-per-operation" pattern, wher
5864
5965
## Database access
6066

61-
EF Core relies on a <xref:Microsoft.EntityFrameworkCore.DbContext> as the means to [configure database access](/ef/core/miscellaneous/configuring-dbcontext) and act as a [*unit of work*](https://martinfowler.com/eaaCatalog/unitOfWork.html). EF Core provides the <xref:Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.AddDbContext%2A> extension for ASP.NET Core apps that registers the context as a *scoped* service by default. In Blazor Server apps, scoped service registrations can be problematic because the instance is shared across components within the user's circuit. <xref:Microsoft.EntityFrameworkCore.DbContext> isn't thread safe and isn't designed for concurrent use. The existing lifetimes are inappropriate for these reasons:
67+
EF Core relies on a <xref:Microsoft.EntityFrameworkCore.DbContext> as the means to [configure database access](/ef/core/miscellaneous/configuring-dbcontext) and act as a [*unit of work*](https://martinfowler.com/eaaCatalog/unitOfWork.html). EF Core provides the <xref:Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.AddDbContext%2A> extension for ASP.NET Core apps that registers the context as a *scoped* service by default. In server-side Blazor apps, scoped service registrations can be problematic because the instance is shared across components within the user's circuit. <xref:Microsoft.EntityFrameworkCore.DbContext> isn't thread safe and isn't designed for concurrent use. The existing lifetimes are inappropriate for these reasons:
6268

6369
* **Singleton** shares state across all users of the app and leads to inappropriate concurrent use.
6470
* **Scoped** (the default) poses a similar issue between components for the same user.
6571
* **Transient** results in a new instance per request; but as components can be long-lived, this results in a longer-lived context than may be intended.
6672

67-
The following recommendations are designed to provide a consistent approach to using EF Core in Blazor Server apps.
73+
The following recommendations are designed to provide a consistent approach to using EF Core in server-side Blazor apps.
6874

6975
* By default, consider using one context per operation. The context is designed for fast, low overhead instantiation:
7076

@@ -124,7 +130,13 @@ In the preceding factory:
124130

125131
The following example configures [SQLite](https://www.sqlite.org/index.html) and enables data logging. The code uses an extension method (`AddDbContextFactory`) to configure the database factory for DI and provide default options:
126132

127-
:::moniker range=">= aspnetcore-7.0"
133+
:::moniker range=">= aspnetcore-8.0"
134+
135+
:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Program.cs" id="snippet1":::
136+
137+
:::moniker-end
138+
139+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0"
128140

129141
:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Program.cs" id="snippet1":::
130142

@@ -150,15 +162,21 @@ The following example configures [SQLite](https://www.sqlite.org/index.html) and
150162

151163
The factory is injected into components and used to create new `DbContext` instances.
152164

153-
In `Pages/Index.razor` of the [sample app](https://github.com/dotnet/blazor-samples/blob/main/7.0/BlazorServerEFCoreSample/Pages/Index.razor), `IDbContextFactory<ContactContext>` is injected into the component:
165+
In the home page of the sample app, `IDbContextFactory<ContactContext>` is injected into the component:
154166

155167
```razor
156168
@inject IDbContextFactory<ContactContext> DbFactory
157169
```
158170

159171
A `DbContext` is created using the factory (`DbFactory`) to delete a contact in the `DeleteContactAsync` method:
160172

161-
:::moniker range=">= aspnetcore-7.0"
173+
:::moniker range=">= aspnetcore-8.0"
174+
175+
:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/Home.razor" id="snippet1":::
176+
177+
:::moniker-end
178+
179+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0"
162180

163181
:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/Index.razor" id="snippet1":::
164182

@@ -182,13 +200,35 @@ A `DbContext` is created using the factory (`DbFactory`) to delete a contact in
182200

183201
:::moniker-end
184202

203+
:::moniker range=">= aspnetcore-8.0"
204+
205+
> [!NOTE]
206+
> `Filters` is an injected `IContactFilters`, and `Wrapper` is a [component reference](xref:blazor/components/index#capture-references-to-components) to the `GridWrapper` component. See the `Home` component (`Components/Pages/Home.razor`) in the sample app.
207+
208+
:::moniker-end
209+
210+
:::moniker range="< aspnetcore-8.0"
211+
185212
> [!NOTE]
186-
> `Filters` is an injected `IContactFilters`, and `Wrapper` is a [component reference](xref:blazor/components/index#capture-references-to-components) to the `GridWrapper` component. See the `Index` component (`Pages/Index.razor`) in the [sample app](https://github.com/dotnet/blazor-samples/blob/main/6.0/BlazorServerEFCoreSample/Pages/Index.razor).
213+
> `Filters` is an injected `IContactFilters`, and `Wrapper` is a [component reference](xref:blazor/components/index#capture-references-to-components) to the `GridWrapper` component. See the `Index` component (`Pages/Index.razor`) in the sample app.
214+
215+
:::moniker-end
187216

188217
## Scope to the component lifetime
189218

190219
You may wish to create a <xref:Microsoft.EntityFrameworkCore.DbContext> that exists for the lifetime of a component. This allows you to use it as a [unit of work](https://martinfowler.com/eaaCatalog/unitOfWork.html) and take advantage of built-in features, such as change tracking and concurrency resolution.
191-
You can use the factory to create a context and track it for the lifetime of the component. First, implement <xref:System.IDisposable> and inject the factory as shown in `Pages/EditContact.razor`:
220+
221+
:::moniker range=">= aspnetcore-8.0"
222+
223+
You can use the factory to create a context and track it for the lifetime of the component. First, implement <xref:System.IDisposable> and inject the factory as shown in the `EditContact` component (`Components/Pages/EditContact.razor`):
224+
225+
:::moniker-end
226+
227+
:::moniker range="< aspnetcore-8.0"
228+
229+
You can use the factory to create a context and track it for the lifetime of the component. First, implement <xref:System.IDisposable> and inject the factory as shown in the `EditContact` component (`Pages/EditContact.razor`):
230+
231+
:::moniker-end
192232

193233
```razor
194234
@implements IDisposable
@@ -197,7 +237,13 @@ You can use the factory to create a context and track it for the lifetime of the
197237

198238
The sample app ensures the context is disposed when the component is disposed:
199239

200-
:::moniker range=">= aspnetcore-7.0"
240+
:::moniker range=">= aspnetcore-8.0"
241+
242+
:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet1":::
243+
244+
:::moniker-end
245+
246+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0"
201247

202248
:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet1":::
203249

@@ -223,7 +269,13 @@ The sample app ensures the context is disposed when the component is disposed:
223269

224270
Finally, [`OnInitializedAsync`](xref:blazor/components/lifecycle) is overridden to create a new context. In the sample app, [`OnInitializedAsync`](xref:blazor/components/lifecycle) loads the contact in the same method:
225271

226-
:::moniker range=">= aspnetcore-7.0"
272+
:::moniker range=">= aspnetcore-8.0"
273+
274+
:::code language="csharp" source="~/../blazor-samples/8.0/BlazorWebAppEFCore/Components/Pages/EditContact.razor" id="snippet2":::
275+
276+
:::moniker-end
277+
278+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0"
227279

228280
:::code language="csharp" source="~/../blazor-samples/7.0/BlazorServerEFCoreSample/Pages/EditContact.razor" id="snippet2":::
229281

aspnetcore/blazor/fundamentals/dependency-injection.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,9 +405,7 @@ In spite of the scoped service registration in the `Program` file and the longev
405405

406406
## Use of an Entity Framework Core (EF Core) DbContext from DI
407407

408-
<!-- UPDATE 8.0 The UID will change -->
409-
410-
For more information, see <xref:blazor/blazor-server-ef-core>.
408+
For more information, see <xref:blazor/blazor-ef-core>.
411409

412410
## Detect client-side transient disposables
413411

aspnetcore/toc.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,8 @@ items:
583583
uid: blazor/host-and-deploy/webassembly-deployment-layout
584584
- name: Multiple hosted WebAssembly apps
585585
uid: blazor/host-and-deploy/multiple-hosted-webassembly
586-
- name: Blazor Server and EF Core
587-
uid: blazor/blazor-server-ef-core
586+
- name: Blazor with EF Core
587+
uid: blazor/blazor-ef-core
588588
- name: Advanced scenarios
589589
uid: blazor/advanced-scenarios
590590
- name: Client-side development

aspnetcore/whats-new/dotnet-AspNetCore.Docs-mod5.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Welcome to what's new in the ASP.NET Core docs for May 2023. This article lists
2929
- Components overview versioning
3030
- <xref:blazor/host-and-deploy/index> - Expand lead-in coverage on app base path
3131
- <xref:blazor/fundamentals/signalr> - Blazor SignalR fundamentals article versioning
32-
- <xref:blazor/blazor-server-ef-core> - Blazor Server EF Core article versioning
32+
- <xref:blazor/blazor-ef-core> - Blazor Server EF Core article versioning
3333
- <xref:blazor/components/templated-components> - Blazor article versioning
3434
- <xref:blazor/tutorials/build-a-blazor-app> - Blazor article versioning
3535
- <xref:blazor/host-and-deploy/multiple-hosted-webassembly> - Subpath scenario for multiple hosted WASM apps

0 commit comments

Comments
 (0)