这个问题的范围相当大,但由于您似乎专门在寻找 AddScoped 信息,因此我将示例范围缩小到 Web 应用程序内的范围。
在 Web 应用程序中 AddScoped 几乎意味着请求的范围。 EntityFramework 在内部使用范围,但在大多数情况下它不会影响用户代码,所以我坚持使用用户代码,如下所示。
如果您将DbContext 注册为服务,并且还注册了范围服务,那么对于每个请求,您将获得一个范围服务的单个实例,您可以在其中解析DbContext。
下面的示例代码应该更清楚。一般来说,我建议按照我在下面展示的方式尝试一下,以通过调试器中的代码逐步熟悉行为。从一个空的 Web 应用程序开始。请注意,我显示的代码来自 Beta2(因为在 Beta2 中我们添加了[FromServices] 属性,这使得演示更容易,无论版本如何,基本行为都是相同的。
startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add EF services to the services container.
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<UserDbContext>();
services.AddScoped<UserService>();
// Add MVC services to the services container.
services.AddMvc();
}
UserDbContext.cs
public class UserDbContext : DbContext
{
public UserService UserService { get; }
public UserDbContext(UserService userService)
{
_userService = userService;
}
}
HomeController.cs
public class HomeController : Controller
{
private UserDbContext _dbContext;
public HomeController(UserDbContext dbContext)
{
_dbContext = dbContext;
}
public string Index([FromServices]UserDbContext dbContext, [FromServices]UserService userService)
{
// [FromServices] is available start with Beta2, and will resolve the service from DI
// dbContext == _ctrContext
// and of course dbContext.UserService == _ctrContext.UserService;
if (dbContext != _dbContext) throw new InvalidOperationException();
if (dbContext.UserService != _dbContext.UserService) throw new InvalidOperationException();
if (dbContext.UserService != userService) throw new InvalidOperationException();
return "Match";
}
}
或者,如果您从另一个服务解析用户服务,这一次注册为 transient 瞬态服务将在每次解析时都有一个新实例,但范围内的服务将在 请求范围。
创建新的服务
public class AnotherUserService
{
public UserService UserService { get; }
public AnotherUserService(UserService userService)
{
UserService = userService;
}
}
将以下行添加到 startup.cs
services.AddTransient<AnotherUserService>();
并重写HomeController.cs如下
公共类 HomeController : 控制器
{
私有AnotherUserService _anotherUserService;
public HomeController(AnotherUserService anotherUserService)
{
_anotherUserService = anotherUserService;
}
public string Index([FromServices]AnotherUserService anotherUserService,
[FromServices]UserService userService)
{
// Since another user service is tranient we expect a new instance
if (anotherUserService == _anotherUserService)
throw new InvalidOperationException();
// but the scoped service should remain the same instance
if (anotherUserService.UserService != _anotherUserService.UserService)
throw new InvalidOperationException();
if (anotherUserService.UserService != userService)
throw new InvalidOperationException();
return "Match";
}
}