gpt4 book ai didi

c# - .NET Core/EF 6 - 依赖注入(inject)范围

转载 作者:可可西里 更新时间:2023-11-01 08:48:14 25 4
gpt4 key购买 nike

我目前正在使用 EF 6 设置 .NET Core 应用程序,但在理解如何正确使用各种依赖项注册方法时遇到了一些困难。据我了解:

  • Transient:对象在需要时创建(即每次请求时创建一个新实例)
  • Singleton:在应用程序启动时创建的单个实例,可用于所有后续请求
  • Scoped:在请求期间可用

特别是在我的情况下,我设置了一对 DbContext(基于 CQRS 模式)来处理我注册为 Scoped 的数据库查询/命令:

services.AddScoped((_) => new TestCommandContext(Configuration["Data:TestConnection:ConnectionString"]));
services.AddScoped((_) => new TestQueryContext(Configuration["Data:TestConnection:ConnectionString"]));

这是根据 ASP.NET Getting Started with ASP.NET 5 and Entity Framework 6 文档:

Context should be resolved once per scope to ensure performance and ensure reliable operation of Entity Framework

然后我将注册相应的 UOW 类(class):

services.AddTransient<ITestCommandUnit, TestCommandUnit>();
services.AddTransient<ITestQueryUnit, TestQueryUnit>();

我在这里使用 Transient 基于 this文章,这表明:

Services registered with Transient scope are created whenever it is needed within the application. That means a new instance of the (registered service) class will be created by the dependency injection framework every time the (method in which the dependency is created) is executed.

基于这种理解,我也在 Scoped 下注册我的存储库和服务类:

services.AddScoped<ITestCommandRepository, TestCommandRepository>();
services.AddScoped<ITestQueryRepository, TestQueryRepository>();

services.AddScoped<ITestCommandService, TestCommandService>();
services.AddScoped<ITestQueryService, TestQueryService>();

然后根据需要在我的 Controller 中调用我各自的服务层方法:

public class TestController : BaseController
{
private ITestQueryService testQueryService;

// Get new object of type TestQueryService via DI
public TestController(ITestQueryService testQueryService)
{
this.testQueryService = testQueryService;
}

[HttpGet]
public IActionResult Edit(int id)
{
if (id > 0)
{
EditViewModel viewModel = new EditViewModel();
viewModel.TestObject = testQueryService.GetById(id);
return View(viewModel);
}
else
{
return RedirectToAction("Error", new { errorMessage = "No object with the specified Id could be found." });
}
}
}

在测试中,此配置似乎有效,将 DbContext 设置为 Scoped 很有意义 - 每次请求时都创建一个新的上下文对象似乎没有必要/效率低下。

但是,对于其他对象,在Transient/Singleton/Scoped 之间的选择是我迷失的地方。有人可以帮助我了解这种特定模式实现的最佳配置吗?

上述设置正在运行,但我正在寻求更多地了解为什么我应该使用我所做的范围。 (即 Transient 是我的 UOW 类(class)的最佳选择吗?为什么在这种情况下它比 Singleton 更好?等等)

最佳答案

通常我的经验法则是:

  1. Scoped - 是可行的方法,可以节省缓存和您的头发,因为状态是为整个请求共享的。没有并发问题(所有作用域服务共享一个线程)。如果类在单个请求中多次使用,则不会创建实例。如果我不知道应该如何注册类(class),我会选择 scoped。通常,您在单个请求中多次需要一些东西 - 您可以计算一次,并在字段中设置值,因此下一次对客户的 CreditLimit 的查询将不会访问数据存储。

  2. 单例适用于缓存(服务器范围)、配置类、设计时考虑了多线程(多个请求)的对象。请注意,单例不应依赖于作用域对象。还要注意在多个线程中调用单例。如果您需要单例对请求数据执行某些操作,请将其作为函数参数传递。

  3. 临时注册在我的应用程序中很少见。我将它用于具有内部状态的类,它们可以多次使用,并且不应共享该状态。通常是实用程序或框架类。

示例作用域类? SqlConnection - 您不想从单个请求打开到数据库的多个连接(因为它由连接池处理)。还使用该连接的服务(服务只做一件事,因此不需要多个实例)。 Asp Controller 。

示例单例?今天浏览最多的文章。邮政编码验证器(没有依赖关系,虽然可以是单例)。

transient 示例?想一想如果该请求中的所有列表共享状态会发生什么。列表不是服务请求,而是您的代码,并且可以在单个请求期间用于不同目的。

请记住,如果单例具有 transient 或作用域依赖性,它将不会被释放,直到单例被释放(应用程序回收)。因此,范围内的事物可以依赖于单例,但单例不能依赖于范围。

说到 CQRS 和 DbContext - 在我的应用程序中,我只有一个 DbContext,由命令和查询共享。一切都在每个生命周期范围内注册(命令或查询在完成后不会保留状态,因此可以重复使用。将其设置为 transient 也可以)。另一个例子是为 html 元素生成唯一 id 的类。它被注册为作用域,并在每次查询新 id 时递增内部计数器。如果类是 transient 的,当被下一个类调用时它会丢失它的状态。

请注意,有些人有其他观点。如果您使用多个生命周期范围,则最好转换为 transient 依赖项。如果我需要多次使用单个依赖项,我喜欢传递工厂,并且我尝试在我的应用程序中只有一个生命周期范围。

关于c# - .NET Core/EF 6 - 依赖注入(inject)范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37172161/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com