Asp.net core ASP.NET Core 3.0在应用程序启动时执行逻辑

Asp.net core ASP.NET Core 3.0在应用程序启动时执行逻辑,asp.net-core,Asp.net Core,我有数据库记录,对于每一个记录,我应该在应用程序启动时有重复的作业。我想我可以使用IHostedService和定义一个作用域服务来做到这一点,但这是不可能的,因为我的作用域服务的生存期较短IHostedService需要单例服务,这会导致死路一条,因为ApplicationDbContext需要作用域服务 InvalidOperationException:无法使用singleton“Microsoft.Extensions.Hosting.IHostedService”中的作用域服务“Bin

我有数据库记录,对于每一个记录,我应该在应用程序启动时有重复的作业。我想我可以使用
IHostedService
和定义一个作用域服务来做到这一点,但这是不可能的,因为我的作用域服务的生存期较短
IHostedService
需要单例服务,这会导致死路一条,因为ApplicationDbContext需要作用域服务

InvalidOperationException:无法使用singleton“Microsoft.Extensions.Hosting.IHostedService”中的作用域服务“Binance.Services.IBotService”

我只需要在应用程序启动时执行该逻辑。在这种情况下,什么是最好的

namespace Binance.Services
{
    public class BotHostedService : IHostedService
    {
        private readonly ILogger _logger;
        private readonly IBotService _botService;

        private int _numberOfBots;

        public BotHostedService(ILogger<BotHostedService> logger, IBotService botService)
        {
            _logger = logger;
            _botService = botService;
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Bot service is starting.");

            var bots = await _botService.GetAllAsync();
            _numberOfBots = bots.Count;

            for (int i = 0; i < _numberOfBots; i++)
            {
                Bot bot = bots[i];
                _logger.LogDebug($"{bot.Name} is starting. Symbol: {bot.CryptoPair.Description}, Interval: {bot.TimeInterval.Description}");
                RecurringJob.AddOrUpdate($"bot{i}", () => DoWork(bot), $"0/5 * * * *", TimeZoneInfo.Local);
            }
        }

        public void DoWork(Bot bot)
        {
            _logger.LogError($"{bot.Name} is working. Current time: {DateTime.Now.ToLocalTime()}");
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Bot service is stopping.");

            for (int i = 0; i < _numberOfBots; i++)
            {
                RecurringJob.RemoveIfExists($"bot{i}");
            }

            return Task.CompletedTask;
        }
    }
}

namespace Binance.Services
{
公共类BotHostedService:IHostedService
{
专用只读ILogger\u记录器;
私有只读IBotService\u botService;
私人智能手机;
公共BotHostedService(ILogger记录器、IBotService botService)
{
_记录器=记录器;
_机器人服务=机器人服务;
}
公共异步任务StartAsync(CancellationToken CancellationToken)
{
_logger.LogInformation(“Bot服务正在启动”);
var bots=await_botService.GetAllAsync();
_numberOfBots=bots.Count;
对于(int i=0;i<\u机器人数量;i++)
{
机器人=机器人[i];
_LogDebug($“{bot.Name}正在启动。符号:{bot.CryptoPair.Description},间隔:{bot.TimeInterval.Description}”);
RecurringJob.AddOrUpdate($“bot{i}”,()=>DoWork(bot),$“0/5****”,TimeZoneInfo.Local);
}
}
公共无效工作(Bot)
{
_logger.LogError($“{bot.Name}正在工作。当前时间:{DateTime.Now.ToLocalTime()}”);
}
公共任务StopAsync(CancellationToken CancellationToken)
{
_logger.LogInformation(“Bot服务正在停止”);
对于(int i=0;i<\u机器人数量;i++)
{
RecurringJob.RemoveIfExists($“bot{i}”);
}
返回Task.CompletedTask;
}
}
}

您可以通过构造函数注入一个
IServiceProvider
,然后在必要时创建一个作用域,如下所示:

使用(var scope=this.serviceProvider.CreateScope())
{
IBotService-botService=scope.ServiceProvider.GetRequiredService();
//使用它
}

您可以通过构造函数注入一个
IServiceProvider
,然后在必要时创建一个作用域,如下所示:

使用(var scope=this.serviceProvider.CreateScope())
{
IBotService-botService=scope.ServiceProvider.GetRequiredService();
//使用它
}
本节对此进行了说明。答案是在需要时在服务内部创建一个作用域。为此,必须将IServiceProvider添加到服务的依赖项中,例如:

public class BotHostedService : IHostedService
{
    //...
    private readonly IServiceProvider  _services;

    public BotHostedService(IServiceProvider services, ILogger<BotHostedService> logger)
    {
        _logger = logger;
        _services=services;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Bot service is starting.");
        using (var scope = _services.CreateScope())
        {
            var botService = scope.ServiceProvider
                                  .GetRequiredService<IBotService>();
            var bots = await _botService.GetAllAsync();
            ...
        }
    }
公共类BotHostedService:IHostedService
{
//...
私人只读阅读器ViceProvider服务;
公共BotHostedService(IServiceProvider服务,ILogger记录器)
{
_记录器=记录器;
_服务=服务;
}
公共异步任务StartAsync(CancellationToken CancellationToken)
{
_logger.LogInformation(“Bot服务正在启动”);
使用(var scope=\u services.CreateScope())
{
var botService=scope.ServiceProvider
.GetRequiredService();
var bots=await_botService.GetAllAsync();
...
}
}
这在的一节中进行了描述。答案是在需要时在服务内部创建一个作用域。为此,必须将
IServiceProvider
添加到服务的依赖项中,例如:

public class BotHostedService : IHostedService
{
    //...
    private readonly IServiceProvider  _services;

    public BotHostedService(IServiceProvider services, ILogger<BotHostedService> logger)
    {
        _logger = logger;
        _services=services;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Bot service is starting.");
        using (var scope = _services.CreateScope())
        {
            var botService = scope.ServiceProvider
                                  .GetRequiredService<IBotService>();
            var bots = await _botService.GetAllAsync();
            ...
        }
    }
公共类BotHostedService:IHostedService
{
//...
私人只读阅读器ViceProvider服务;
公共BotHostedService(IServiceProvider服务,ILogger记录器)
{
_记录器=记录器;
_服务=服务;
}
公共异步任务StartAsync(CancellationToken CancellationToken)
{
_logger.LogInformation(“Bot服务正在启动”);
使用(var scope=\u services.CreateScope())
{
var botService=scope.ServiceProvider
.GetRequiredService();
var bots=await_botService.GetAllAsync();
...
}
}

谢谢!如果我的服务是singleton,我也可以使用这种方式吗?@不可以。调用服务的生命周期是什么并不重要。如果是singleton,你不需要手动创建作用域,因为托管服务已注册为singleton。你只需通过constructor@mcont如果是这样的话,就会有no需要创建一个作用域。后台服务的行为类似于单例。此外,在应用程序的生命周期内保持昂贵的类(如
DbContext
)处于活动状态会导致严重的并发问题谢谢!如果我的服务是单例的,我也可以使用这种方式吗?@不,是的。调用的生命周期是什么并不重要ing服务是。如果它是单例,则不需要手动创建作用域,因为托管服务已注册为单例。您只需通过constructor@mcont如果是这样的话,就不需要创建作用域。后台服务的行为类似于单例。此外,保留一个昂贵的类,如
DbContext
在应用程序的生命周期内保持活动状态会导致严重的并发问题谢谢!我接受了另一个答案,因为他更快。事实相反,但没有问题:)谢谢!我接受了另一个答案,因为他更快。事实相反,但没有问题:)