如何在单例类中使用DbContext?

Chr*_*ris 4 c# singleton dependency-injection single-responsibility-principle asp.net-core

我实现了一个类EUMemberChecker,负责检查一个国家是否是欧盟成员。为了完成其工作,该类包含一个方法public bool IsEUMember(string country)。用于检查一个国家是否是欧盟成员的数据存储在 PostgreSQL 数据库表中。

我想通过 DI 将此类添加为单例服务,从而使其可用AddSingleton。原因是它应该只在应用程序启动时从数据库加载一次欧盟成员。如果我通过添加此类AddScoped,则它的每个实例都需要从数据库加载自己的欧盟成员列表,在我看来,这将是相当大的开销。

我的问题是我无法将此类添加为单例,因为它使用我的DbContext类作为范围服务添加。无论如何这样做,都会导致运行时错误Dependency ...DatabaseContext {ReturnDefault} as parameter "context" reuse CurrentScopeReuse {Lifespan=100} lifespan shorter than its parent's: singleton ... {ReturnDefault} as parameter ...

因此,似乎我必须将我的类添加为范围服务,从而导致额外的数据库调用来为该类的每个实例加载欧盟成员国。

我在这里是否错误地应用了单一职责原则,或者如何解决这个问题?如何确保欧盟成员不会无故多次从数据库加载?

Ste*_*ven 6

有几种解决方案可以解决这个问题。以下是我能想到的选项:

  • 制定作用域EUMemberChecker,但将缓存部分从类中拉出,并将其作为单例服务注入。
  • 成为您的组合根EUMemberChecker的一部分,以允许将容器实例(例如)注入到该类中。这允许创建一个范围实例,您可以从中解析,例如. 如果类包含业务逻辑,最好从类中提取业务逻辑并将其注入到类中;您希望组合根中的代码量尽可能小。IServiceProviderDbContext
  • 忽略并抑制警告,因为您似乎确信这不会在您的特定情况下导致任何问题。请注意,对于 MS.DI,可能没有简单的方法来抑制此错误。
  • 在创建缓存时DbContext手动构建。EUMemberChecker这可能意味着您需要将配置值注入到 中EUMemberChecker,例如连接字符串,这DbContext显然是需要的。
  • 在进行容器注册之前从数据库加载数据,并在注册时手动提供此缓存。例如:services.AddSingleton(c => new EUMemberChecker(loadedMembers)).
  • EUMemberChecker通过调用某种方法在启动时直接初始化Initialize。可以将加载的成员提供给该方法,或者您可以传入DbContext以便Initialize可以在内部进行查询。这DbContext可以在启动时从容器中解决,可能是通过手动创建的范围来解决。

哪一个选项最好,取决于许多实施细节,因此您必须决定哪一个最适合您的需求。