ASP.NET Core中,实体框架核心服务的默认生命周期是怎样的?

更新于
2026-09-18 23:08:08
39阅读来源:SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计706个文字,预计阅读时间需要3分钟。

ASP.NET Core中,实体框架核心服务的默认生命周期是怎样的?

在ASP.NET Core应用中,通过DI注入DbContext的示例如下:

csharpservices.AddDbContext(options=> options.UseNpgsql(connection));

关于DbContext的生命周期,它是依赖于ASP.NET Core应用的请求生命周期。具体来说:

- 实例化:当应用启动并首次请求依赖注入服务时,会创建DbContext的实例。- 请求作用域:在每次请求中,都会重用同一个DbContext实例。这意味着在同一个请求内,DbContext的实例是持续存在的。- 请求结束后:请求结束后,DbContext的实例不会被销毁,而是会等待后续请求重用。如果在配置中设置了`UseApplicationLifetime`,则可以在应用关闭时执行清理操作。- 应用关闭:当应用关闭时,DbContext实例会进行清理,释放资源,如关闭数据库连接等。

在ASP.NET Core应用程序中,我可以像这样通过DI注册DbContext

services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection));

而知道它的生命周期是什么呢?

从这里github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140看起来它被配置为Scoped意味着在每个请求上创建DbContext实例.

所以问题的第一部分是:
这是真的,如果是的话,它的成本是多少?

第二部分是:
如果我创建一个消耗DbContext并且打算由控制器使用的服务,并且将有一个API来管理DB中的某些实体,那么它是否应该注册为Scoped?

是的,DbContext的默认生命周期是作用域.这是这样的.

实例化DbContext非常便宜,它确保您不会使用许多资源.如果你有一个单身生命周期的DbContext,那么你读过的所有记录都会被DbContext跟踪,除非你专门禁用了跟踪.这将需要更多的内存使用,并将继续增长.

ASP.NET Core中,实体框架核心服务的默认生命周期是怎样的?

DbContext跟踪的越多,性能就越低.这就是为什么你经常看到DbContext只在using(var context = new AppDbContext())块中使用.

但是,在Web应用程序中,使用using块是不好的,因为生命周期由framework管理,如果您将其处置为早期,则之后的调用将因异常而失败.

如果您在另一侧使用瞬态生命周期,则将失去“事务”功能.使用作用域,DbContext的事务范围与请求一样长.

如果你需要更细粒度的控制,你必须使用工作单元模式(DbContext已经使用了它).

对于你的第二个问题:

如果您创建服务,则其生命周期必须等于范围或更短的范围(读取:Scoped或瞬态).

如果您明确需要更长的服务生命周期,则应将DbContext工厂服务或工厂方法注入服务.

你可以用类似的东西来完成这个

services.AddTransient<Func<AppDbContext>>( (provider) => new Func<MyDbContext>( () => new AppDbContext())); services.AddSingleton<IMySingletonService, MySingletonService>();

您的服务可能如下所示:

public class MySingletonService : IMySingletonService, IDisposable { private readonly AppDbContext context; public MySingletonService(Func<AppDbContext> contextFactory) { if(contextFactory == null) throw new ArgumentNullException(nameof(contextFactory)); // it creates an transient factory, make sure to dispose it in `Dispose()` method. // Since it's member of the MySingletonService, it's lifetime // is effectively bound to it. context = contextFactory(); } }

本文共计706个文字,预计阅读时间需要3分钟。

ASP.NET Core中,实体框架核心服务的默认生命周期是怎样的?

在ASP.NET Core应用中,通过DI注入DbContext的示例如下:

csharpservices.AddDbContext(options=> options.UseNpgsql(connection));

关于DbContext的生命周期,它是依赖于ASP.NET Core应用的请求生命周期。具体来说:

- 实例化:当应用启动并首次请求依赖注入服务时,会创建DbContext的实例。- 请求作用域:在每次请求中,都会重用同一个DbContext实例。这意味着在同一个请求内,DbContext的实例是持续存在的。- 请求结束后:请求结束后,DbContext的实例不会被销毁,而是会等待后续请求重用。如果在配置中设置了`UseApplicationLifetime`,则可以在应用关闭时执行清理操作。- 应用关闭:当应用关闭时,DbContext实例会进行清理,释放资源,如关闭数据库连接等。

在ASP.NET Core应用程序中,我可以像这样通过DI注册DbContext

services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection));

而知道它的生命周期是什么呢?

从这里github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140看起来它被配置为Scoped意味着在每个请求上创建DbContext实例.

所以问题的第一部分是:
这是真的,如果是的话,它的成本是多少?

第二部分是:
如果我创建一个消耗DbContext并且打算由控制器使用的服务,并且将有一个API来管理DB中的某些实体,那么它是否应该注册为Scoped?

是的,DbContext的默认生命周期是作用域.这是这样的.

实例化DbContext非常便宜,它确保您不会使用许多资源.如果你有一个单身生命周期的DbContext,那么你读过的所有记录都会被DbContext跟踪,除非你专门禁用了跟踪.这将需要更多的内存使用,并将继续增长.

ASP.NET Core中,实体框架核心服务的默认生命周期是怎样的?

DbContext跟踪的越多,性能就越低.这就是为什么你经常看到DbContext只在using(var context = new AppDbContext())块中使用.

但是,在Web应用程序中,使用using块是不好的,因为生命周期由framework管理,如果您将其处置为早期,则之后的调用将因异常而失败.

如果您在另一侧使用瞬态生命周期,则将失去“事务”功能.使用作用域,DbContext的事务范围与请求一样长.

如果你需要更细粒度的控制,你必须使用工作单元模式(DbContext已经使用了它).

对于你的第二个问题:

如果您创建服务,则其生命周期必须等于范围或更短的范围(读取:Scoped或瞬态).

如果您明确需要更长的服务生命周期,则应将DbContext工厂服务或工厂方法注入服务.

你可以用类似的东西来完成这个

services.AddTransient<Func<AppDbContext>>( (provider) => new Func<MyDbContext>( () => new AppDbContext())); services.AddSingleton<IMySingletonService, MySingletonService>();

您的服务可能如下所示:

public class MySingletonService : IMySingletonService, IDisposable { private readonly AppDbContext context; public MySingletonService(Func<AppDbContext> contextFactory) { if(contextFactory == null) throw new ArgumentNullException(nameof(contextFactory)); // it creates an transient factory, make sure to dispose it in `Dispose()` method. // Since it's member of the MySingletonService, it's lifetime // is effectively bound to it. context = contextFactory(); } }