ASP.NET Core在配置DI后初始化单例

pbz*_*pbz 29 singleton dependency-injection asp.net-core

所以,假设我有一个单例类实例,我在DI中注册如下:

services.AddSingleton<IFoo, Foo>();
Run Code Online (Sandbox Code Playgroud)

并且假设Foo该类具有许多其他依赖项(主要是允许其加载数据的存储库类).

根据我目前的理解,Foo实例在首次使用(询问)之前不会创建.有没有办法初始化除构造函数之外的这个类?就像ConfigureServices()完成后一样?或者初始化代码(从db加载数据)是否应该在Foo的构造函数中完成?

(如果这个类在第一次使用之前加载其数据以加速第一次访问,那将是很好的)

Tse*_*eng 46

在启动期间自己动手.

var foo = new Foo();
services.AddSingleton<IFoo>(foo);
Run Code Online (Sandbox Code Playgroud)

或者"热身"

public void Configure(IApplicationBuilder app) 
{
    app.ApplicationServices.GetService<IFoo>();
}
Run Code Online (Sandbox Code Playgroud)

或者

public void Configure(IApplicationBuilder app, IFoo foo) 
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是如果你做了一些你不应该在构造函数中做的事情,那么这感觉很脏并且对你的设计来说更成问题.类实例化必须快速,如果你在其中进行长时间运行的操作,你就要打破一堆最佳实践,需要重构代码库,而不是寻找破解它的方法

  • 如果您的单件服务需要从文件读取数据或从数据库加载数据并充当该数据的缓存,该怎么办?在第一次请求期间(当要求服务时)这样做似乎是不对的,但对我来说这似乎是一种常见的情况.此外,这些操作具有潜在的危险性,并且可以抛出您想要捕获的异常,记录等.如果自己实例化服务或"热身"感觉脏了,这样做的最佳做法是什么? (7认同)
  • 但后来我不得不担心Foo的所有依赖关系(所有存储库及其依赖关系).绝对可行,但寻找一种不与系统作斗争的方式. (3认同)
  • 对我来说是```public void Configure(IApplicationBuilder app) { app.ApplicationServices.GetService&lt;IFoo&gt;(); }```(IFoo 而不是 Foo) (3认同)

Moa*_*fan 8

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

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

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

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

services
    .AddHostedService<MyService>()
    .AddSingleton<MyService>(x => x
        .GetServices<IHostedService>()
        .OfType<MyService>()
        .First());
Run Code Online (Sandbox Code Playgroud)

简单服务的示例:

public class MyService : IHostedService
{
    // This function will be called automatically when the host `starts`
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // Do initialization logic
    }

    // This function will be called automatically when the host `stops`
    public Task StopAsync(CancellationToken cancellationToken)
    {
        // Do cleanup if needed

        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

我后来创建了一些扩展方法,因为我需要再次使用相同的模式

public static class HostedServiceExtensions
{
    public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services) where T : class, IHostedService
        => services.AddHostedService<T>().AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());

    public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class, IHostedService
        => services.AddHostedService(factory).AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());
}
Run Code Online (Sandbox Code Playgroud)

使用就像

services.AddHostedServiceAsService<MyService>();

// Or like this if you need a factory
services.AddHostedServiceAsService<MyService>(x => new MyService());
Run Code Online (Sandbox Code Playgroud)


小智 7

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

他解释了如何使用 asp .net core 3 执行此操作,但他还参考了有关如何使用早期版本执行此操作的页面。

  • 嗨,杰罗姆·弗拉门,欢迎光临。请考虑添加更多信息,因为如果链接变得过时,那么您的答案质量非常低。 (6认同)

Mmm*_*Mmm 5

添加详细信息到 J\xc3\xa9r\xc3\xb4me FLAMEN\ 的答案,因为它提供了我向单例调用异步初始化任务所需的密钥:

\n

创建一个实现 IHostedService 的类:

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

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

\n
services.AddHostedService<PostStartup>();\n
Run Code Online (Sandbox Code Playgroud)\n

来自链接

\n