【问题标题】:ASP.NET Core initialize singleton after configuring DI配置 DI 后 ASP.NET Core 初始化单例
【发布时间】:2016-08-17 20:37:18
【问题描述】:

假设我有一个像这样在 DI 中注册的单例类实例:

services.AddSingleton<IFoo, Foo>();

假设Foo 类有许多其他依赖项(主要是允许它加载数据的存储库类)。

根据我目前的理解,Foo 实例在第一次使用(询问)之前不会创建。除了构造函数之外,还有其他方法可以初始化这个类吗?就像在ConfigureServices() 完成之后一样?还是应该在 Foo 的构造函数中完成初始化代码(从 db 加载数据)?

(如果这个类可以在第一次使用之前加载它的数据以加速第一次访问,那就太好了)

【问题讨论】:

  • 您可以创建new Foo()并在ConfigureServices方法中注册。
  • @ademcaglin 那行不通;由于Foo 有依赖关系,它不会有默认构造函数。

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


【解决方案1】:

在启动时自己做。

var foo = new Foo();
services.AddSingleton<IFoo>(foo);

或者“热身”

public void Configure(IApplicationBuilder app) 
{
    app.ApplicationServices.GetService<IFoo>();
}

或者

public void Configure(IApplicationBuilder app, IFoo foo) 
{
    ...
}

但是如果你在构造函数中做了一些你不应该做的事情,这感觉很脏,而且更多的是你的设计问题。类实例化必须快速,如果你在其中执行长时间运行的操作,你会违反一堆最佳实践,需要重构你的代码库,而不是寻找绕过它的方法

【讨论】:

  • 但是我不得不担心 Foo 的所有依赖项(所有存储库及其依赖项)。绝对可行,但要寻找一种不与系统对抗的方法。
  • 是的。您通常只初始化需要特殊处理的类,例如启动服务总线连接等,您不希望在启动期间发生这种情况。我们需要更多信息,尽管您到底尝试了什么。我怀疑你在构造函数中做了一些长时间运行的操作,这是绝对不行的。类实例化应该是快速且长时间运行的操作,永远不要在构造函数中完成。当然你也可以一次性解决Configure中的类,但这只是感觉“脏”
  • 是的,运行时间相对较长,因为它会去数据库检索数据(多个查询大约需要 50 毫秒)。由于这是一个单例,因此可能会争辩说它在哪里初始化并不重要。我认为这是迄今为止最好的选择(顺便说一句,您输入错误 Configure()。刚刚尝试将 IFoo 添加到 Configure() 的参数列表中,这样我就不必调用 GetService()。谢谢。
  • 对我来说是public void Configure(IApplicationBuilder app) { app.ApplicationServices.GetService&lt;IFoo&gt;(); }(IFoo 而不是 Foo)
  • 如果您的单例服务需要从文件中读取数据或从数据库中加载数据并充当该数据的缓存,该怎么办?在第一次请求期间(当请求服务时)这样做似乎不正确,但对我来说这似乎是一种常见情况。此外,这些操作具有潜在危险,可能会引发您想要捕获、记录等的异常。如果您自己实例化服务或“热身”感觉很脏,那么这样做的最佳做法是什么?
【解决方案2】:

我遇到了同样的问题,我找到了 Andrew Lock 博客: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/

他解释了如何使用 asp .net core 3 做到这一点,但他也参考了他的页面,了解如何使用以前的版本做到这一点。

【讨论】:

  • 您好 Jérôme FLAMEN,欢迎您。请考虑添加更多信息,因为如果链接过时,那么您的答案质量就会非常低。
  • 感谢文章参考,但在我的 Main 方法中,我的 WebHost 是这样初始化的:CreateWebHostBuilder(args).Build().Run()。所以,我调用的是 Run 方法而不是 StartAsync 方法。我不认为调用异步方法而不是同步方法是一个问题(因为我可以捕获生成的任务并等待它),但是调用 Run 和 Start 之间有区别吗?
【解决方案3】:

最近,如果需要初始化,我将其创建为 IHostedService,因为对我来说,让初始化由服务本身而不是在服务之外处理似乎更合乎逻辑。

您甚至可以使用BackgroundService 代替IHostedService,因为它非常相似,只需要实现ExecuteAsync

这是他们的文档
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services

如何添加服务以便您可以直接注入它的示例:

services
    .AddHostedService<MyService>()
    .AddSingleton<MyService>(x => x
        .GetServices<IHostedService>()
        .OfType<MyService>()
        .First());

【讨论】:

    【解决方案4】:

    我做了一些经理,我需要订阅其他服务的事件。 我不喜欢在

    webBuilder.Configure (applicationBuilder => ...
    

    我觉得应该在版块里

    webBuilder.ConfigureServices ((context, services) => ...
    

    所以,这是我的答案(在 net.core 3 上测试):

    public static IHostBuilder CreateHostBuilder (string [] args) =>
        Host.CreateDefaultBuilder (args)
            .ConfigureWebHostDefaults (webBuilder =>
            {
    
            ...
    
            services.AddSingleton<ISomeSingletonService,SomeSingletonService>();
    
            var buildServiceProvider = services.BuildServiceProvider();
            var someSingletonService = buildServiceProvider.GetRequiredService <ISomeSingletonService>();
    
            ...
            });
      
    

    【讨论】:

      【解决方案5】:

      为 Jérôme FLAMEN 的答案添加细节,因为它提供了我将异步初始化任务调用到单例所需的密钥:

      创建一个实现 IHostedService 的类:

      public class PostStartup : IHostedService
      {
         private readonly YourSingleton yourSingleton;
      
         public PostStartup(YourSingleton _yourSingleton)
         {
             yourSingleton = _yourSingleton;
         }
      
         // you may wish to make use of the cancellationToken
         public async Task StartAsync(CancellationToken cancellationToken)
         {
            await yourSingleton.Initialize();
         }
      
         // implement as you see fit
         public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
      }
      

      然后,在您的 ConfigureServices 中,添加 HostedService 引用:

      services.AddHostedService<PostStartup>();
      

      来自link

      【讨论】:

        猜你喜欢
        • 2012-06-20
        • 2018-02-10
        • 2019-02-15
        • 1970-01-01
        • 1970-01-01
        • 2016-08-21
        • 1970-01-01
        • 1970-01-01
        • 2020-10-27
        相关资源
        最近更新 更多