在配置服务方法中使用服务实例

时间:2019-05-28 19:06:07

标签: c# asp.net-core dependency-injection

可以在configure services中调用services.buildserviceprovider方法以使其能够在configure services方法本身内使用服务的实例。

用例是我有一个加密服务,可以执行自定义加密/解密。我在appsettings.json文件中已加密连接字符串,并且需要将未加密的字符串传递给ef设置以创建SQL db上下文。因此,我需要在此配置服务方法中使用加密服务。它可以是单例或瞬态的,都没有关系。 除了这种方法,还有其他选择吗?

1 个答案:

答案 0 :(得分:3)

  

可以在services.BuildServiceProvider […]中调用ConfigureServices方法吗?

一般吗?不能。创建其他服务提供商只会导致您在不应有单独生命周期的情况下处理多个单独生命周期。尽管在简单的配置情况下它可能是可管理的,但肯定应该避免这种不好的做法。

  

我需要在此ConfigureServices方法中使用加密服务。

这实际上是一个非常常见的用例,它使用其他依赖项在ASP.NET Core中进行配置。这些东西几乎可以是任何东西,包括EF Core连接字符串。您可以为此使用任何类型的依赖项。最常见的用例是根据其他一些配置值进行配置。

通常,如果要配置某些依赖于服务的内容,则可以使用AddOptions<T>方法和OptionsBuilder<T>来配置依赖的配置操作。

对于EntityFramework Core,工作原理有所不同,但是用于注册和配置数据库上下文的默认AddDbContext<T>实际上具有useful overload,其中optionsAction属于输入Func<IServiceProvider, DbContextOptionsBuilder>。您可以使用它来注册配置操作,然后从服务提供商处解析您的服务以配置数据库上下文:

services.AddSingleton<ConnectionStringEncryptionService>();

services.AddDbContext<MyContext>((sp, options) =>
{
    var encryptionService = sp.GetService<ConnectionStringEncryptionService>();
    var connectionString = encryptionService.GetConnectionString();
    options.UseSqlServer(connectionString);
});

现在,当实例化MyContext并解决DbContextOptions<MyContext>时,将运行该操作,该操作将解析来自服务提供者的服务以首先解密连接字符串。

关于此的一个重要说明是,默认情况下,数据库上下文和上下文选项都被注册为作用域依赖性。这意味着每个请求将创建一次。这也意味着上述回调将对每个请求运行一次,从而导致解密过程对每个请求运行一次(除非服务进行缓存)。

您应该考虑更改数据库上下文选项的生存期(但不是数据库上下文本身!)以使其成为单例,以便仅运行一次:

services.AddDbContext<MyContext>((sp, options) =>
{
    // …
}, optionsLifetime: ServiceLifetime.Singleton);