You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: aspnetcore/blazor/blazor-ef-core.md
+70-18Lines changed: 70 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,33 +1,39 @@
1
1
---
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)
3
3
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.
5
5
monikerRange: '>= aspnetcore-3.1'
6
6
ms.author: jeliknes
7
7
ms.custom: mvc
8
8
ms.date: 03/27/2023
9
-
uid: blazor/blazor-server-ef-core
9
+
uid: blazor/blazor-ef-core
10
10
---
11
-
# ASP.NET Core Blazor Server with Entity Framework Core (EF Core)
11
+
# ASP.NET Core Blazor with Entity Framework Core (EF Core)
12
12
13
13
[!INCLUDE[](~/includes/not-latest-version.md)]
14
14
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.
16
16
17
-
Blazor Serveris 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.
18
18
19
19
> [!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.
21
21
22
22
## Sample app
23
23
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.
25
25
26
26
[View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:index#how-to-download-a-sample))
27
27
28
28
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`:
@@ -58,13 +64,13 @@ The grid, add, and view components use the "context-per-operation" pattern, wher
58
64
59
65
## Database access
60
66
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:
62
68
63
69
***Singleton** shares state across all users of the app and leads to inappropriate concurrent use.
64
70
***Scoped** (the default) poses a similar issue between components for the same user.
65
71
***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.
66
72
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.
68
74
69
75
* By default, consider using one context per operation. The context is designed for fast, low overhead instantiation:
70
76
@@ -124,7 +130,13 @@ In the preceding factory:
124
130
125
131
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:
@@ -150,15 +162,21 @@ The following example configures [SQLite](https://www.sqlite.org/index.html) and
150
162
151
163
The factory is injected into components and used to create new `DbContext` instances.
152
164
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:
@@ -182,13 +200,35 @@ A `DbContext` is created using the factory (`DbFactory`) to delete a contact in
182
200
183
201
:::moniker-end
184
202
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
+
185
212
> [!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
187
216
188
217
## Scope to the component lifetime
189
218
190
219
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
192
232
193
233
```razor
194
234
@implements IDisposable
@@ -197,7 +237,13 @@ You can use the factory to create a context and track it for the lifetime of the
197
237
198
238
The sample app ensures the context is disposed when the component is disposed:
@@ -223,7 +269,13 @@ The sample app ensures the context is disposed when the component is disposed:
223
269
224
270
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:
0 commit comments