标签: asp.net-core-hosted-services

定期托管服务是否需要保持活动状态?

我创建了一个在 .Net-Core 中执行重复任务的托管服务。(我使用共享主机,所以我无法控制 iis)

public class SchedulerService : IHostedService
{
    private readonly ILogger _logger;
    private Timer _timer;

    public SchedulerService(ILogger<SchedulerService> logger)
    {
        this._logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        this._timer = new Timer(ExecuteTask, null, TimeSpan.Zero,
            TimeSpan.FromMinutes(30));

        return Task.CompletedTask;
    }

    private void ExecuteTask(object state)
    {
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        this._timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想确保此任务始终运行。但是由于应用程序池回收等原因,不能 保证托管服务完成

我对这个概念有点困惑。我现在的印象是托管服务仅在发出请求后在后台运行,并且一旦应用程序池被回收,后台任务就会被终止(例如,旧版本的 90 秒限制)

编辑

我在我的 API 中对此进行了测试,它似乎在最后一次请求发出数小时后仍能持续运行。注意:我在 IIS Express 中对此进行了测试,因此仍然不能保证行为。

如果是这种情况,并且没有向我的站点发出请求,我是否仍能保证我的 SchedulerService 会运行?

或者我应该让我的调度程序服务每约 75 秒向自己发送一个请求,以确保新线程将重新启动调度程序?

c# task .net-core asp.net-core-hosted-services

5
推荐指数
1
解决办法
2056
查看次数

在 .NET Core 5 托管服务的 StartAsync 和 StopAsync 中返回什么?

尝试大致遵循MSDN,我在课堂上的范围服务之后添加了托管服务StartUp

public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddScoped<IUtilityService, UtilityService>();
  services.AddHostedService<StartupService>();
  ...
}
Run Code Online (Sandbox Code Playgroud)

我是StartAsync这样实现的。

public class StartupService : IHostedService
{
  private IServiceProvider Provider { get; }
  public StartupService(IServiceProvider provider)
  {
    Provider = provider;
  }

  public Task StartAsync(CancellationToken cancellationToken)
  {
    IServiceScope scope = Provider.CreateScope();
    IUtilityService service = scope.ServiceProvider
      .GetRequiredService<IUtilityService>();

    service.Seed();

    return Task.CompletedTask;
  }

  public Task StopAsync(CancellationToken cancellationToken)
  {
    throw new NotImplementedException();
  }
}
Run Code Online (Sandbox Code Playgroud)

我读过很多文章和博客,但我无法理解方法末尾应该返回什么。它现在似乎有效,但我可以清楚地看到,我通过不使用异步调用并返回一个虚拟值来违反这个想法(甚至在停止时也没有!),所以我可以安全地得出结论,我做错了(尽管不是)显然,但我确信它将来会咬我的屁股)。

我应该在实现中返回什么以确保我“使用”而不是反对框架?

c# .net-core asp.net-core-hosted-services asp.net-core-5.0

5
推荐指数
1
解决办法
2822
查看次数

HostedService 的多个实例

我想运行同一托管服务的多个实例。我尝试注册它们两次:

services.AddHostedService<MyService>();
services.AddHostedService<MyService>();
Run Code Online (Sandbox Code Playgroud)

但 ExecuteAsync 仅在一个实例上调用。

但是,如果我有两种不同的服务:

services.AddHostedService<MyServiceA>();
services.AddHostedService<MyServiceB>();
Run Code Online (Sandbox Code Playgroud)

每一个都会调用 ExecuteAsync。

无论如何,有没有办法运行同一个实例两次?我本质上想让两个工作服务做同样的事情。

c# .net-core asp.net-core asp.net-core-hosted-services

5
推荐指数
1
解决办法
8971
查看次数

通过计时器写入数据库的后台任务

如何在后台的计时器上写入数据库。例如,检查邮件并将新字母添加到数据库。在示例中,我在写入数据库之前简化了代码。

Microsoft示例中的类名称。录音课本身:

namespace EmailNews.Services
{

internal interface IScopedProcessingService
{
    void DoWork();
}

internal class ScopedProcessingService : IScopedProcessingService
{
    private readonly ApplicationDbContext _context;
    public ScopedProcessingService(ApplicationDbContext context)
    {
        _context = context;
    }

    public void DoWork()
    {
        Mail mail = new Mail();
        mail.Date = DateTime.Now;
        mail.Note = "lala";
        mail.Tema = "lala";
        mail.Email = "lala";
        _context.Add(mail);
        _context.SaveChangesAsync();
    }
}
}
Run Code Online (Sandbox Code Playgroud)

计时器类:

namespace EmailNews.Services
{
#region snippet1
internal class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    public TimedHostedService(IServiceProvider services, ILogger<TimedHostedService> …
Run Code Online (Sandbox Code Playgroud)

c# async-await asp.net-core asp.net-core-2.1 asp.net-core-hosted-services

4
推荐指数
1
解决办法
578
查看次数

.net 核心`IHostedService` 是否应该启动一个新线程

.net coreBackgroundServiceIHostedService的 start 方法是异步的:

//IHostedService
Task StartAsync(CancellationToken cancellationToken);
//BackgroundService
Task ExecuteAsync(CancellationToken stoppingToken);
Run Code Online (Sandbox Code Playgroud)

那么我应该在ExecuteAsync/StartAsync方法中编写所有逻辑,还是应该启动一个新线程并立即返回?

例如,以下哪两个是正确的实现?

1.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    new Thread(async () => await DoWork(stoppingToken)).Start();

    await Task.CompletedTask;
}

private async Task DoWork(CancellationToken stoppingToken) 
{
    while (!stoppingToken.IsCancellationRequested)
        //actual works
}
Run Code Online (Sandbox Code Playgroud)

2.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        //actual works
        await Task.Delay(1000);//e.g
    }
}
Run Code Online (Sandbox Code Playgroud)

从语义上讲,我认为第二个似乎是正确的,但是如果有几个IHostedServices,它们可以与第二种形式并行运行吗?

编辑 1

我还编写了一个示例程序,说明托管服务本身不是作为单独的线程运行的。

"Waiting for signal.."我键入 a 之前,不会将消息写入控制台 …

async-await .net-core asp.net-core-hosted-services

4
推荐指数
1
解决办法
4390
查看次数

asp .net core 中 IHostedService.StartAsync 中的 CancellationToken 有什么意义?

我正在尝试实现托管服务,我想知道我应该在通话中使用 CancellationToken 做什么IHostedService.StartAsync

Microsoft 文档中有很多关于取消令牌本质上StopAsync是超时(默认情况下 5 秒)的内容,这意味着应该在合理的时间范围内正常关闭。

但关于 中的 token StartAsync,信息并不多。如果有的话,文档指定实现不应等待长时间运行的初始化进程,而应仅返回长时间运行的任务。因此,如果我支持取消,我是否应该将取消令牌传递给创建该长时间运行任务的任何内容?如果是的话,取消这个令牌不是一个愚蠢的版本吗StopAsync?为什么框架会这样做?

事实上,在微软自己的抽象BackgroundService中,实现StartAsync实际上完全忽略了该令牌并创建了一个新的令牌,该令牌在调用时被取消StopAsync......

那么我是否认为框架传递的初始令牌的全部意义实际上是通过覆盖虚拟方法来用于阻止 初始化过程(尽管文档建议反对它)BackgroundService.StartAsync?例如

public class MyBackgroundService : BackgroundService
{
    public override Task StartAsync(CancellationToken cancellationToken)
    {
        // Block the thread for initialisation with cancellation (replace Task.Delay by actual initialisation)
        Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).GetAwaiter().GetResult();

        // Start the long running task proper
        return base.StartAsync(cancellationToken);
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // some long running …
Run Code Online (Sandbox Code Playgroud)

c# async-await asp.net-core-hosted-services

4
推荐指数
1
解决办法
7776
查看次数

asp.net core托管服务中的“timer + Task.Run”与“while循环+ Task.Delay”

我有一个要求,后台服务应该在Process每天凌晨 0:00 运行方法

因此,我的一位团队成员编写了以下代码:

public class MyBackgroundService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    public MyBackgroundService(ILogger<MyBackgroundService> logger)
    {
        _logger = logger;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        TimeSpan interval = TimeSpan.FromHours(24);
        TimeSpan firstCall = DateTime.Today.AddDays(1).AddTicks(-1).Subtract(DateTime.Now);

        Action action = () =>
        {
            Task.Delay(firstCall).Wait();

            Process();

            _timer = new Timer(
                ob => Process(),
                null,
                TimeSpan.Zero,
                interval
            );
        };

        Task.Run(action);
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Change(Timeout.Infinite, 0);

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

c# asynchronous timer task asp.net-core-hosted-services

4
推荐指数
1
解决办法
4798
查看次数

重写 IHostedService 以在所有任务完成后停止

我有一个应用程序,通常应该是一个简单的控制台应用程序,可以编程为 Windows 任务计划程序不时调用的计划任务。

\n

该程序应该在两个数据库上启动一些更新,每个数据库一项服务。说ContosoDatabase应该更新ContosoService

\n

最后,它被编写为一个 .NET Core 应用程序,使用s作为服务的基础,这也许不是最好的选择,如下所示:IHostedService

\n
public class ContosoService : IHostedService {\n    private readonly ILogger<ContosoService> _log;\n    private readonly IContosoRepository _repository;\n    \n    private Task executingTask;\n\n    public ContosoService(\n        ILogger<ContosoService> log,\n        IContosoRepository repository,\n        string mode) {\n        _log = log;\n        _repository = repository;\n    }\n\n    public Task StartAsync(CancellationToken cancellationToken) {\n        _log.LogInformation(">>> {serviceName} started <<<", nameof(ContosoService));\n        executingTask = ExcecuteAsync(cancellationToken);\n\n        // If the task is completed then return it, \n        // this should bubble cancellation and …
Run Code Online (Sandbox Code Playgroud)

background-process .net-core asp.net-core-hosted-services .net-5 ihostedservice

4
推荐指数
1
解决办法
4575
查看次数

后台服务/工作人员不进行垃圾收集

我需要一个 IHostedService 或“工作服务”,但我遇到了一个有趣的难题,那就是垃圾收集器没有在“适当”的时间运行。相反,它只是不收集任何资源,导致应用程序的内存使用量增加(在调试期间,根本没有发生 GC)。

我已经做了所有能想到的事情,包括让所有任务返回一些值,以及尽可能使用 using 语句。还使用依赖注入抽象了几个层(以确保有多个位置应该与运行时通信,表明它适合运行垃圾收集。

我唯一的“解决方案”(不是解决方案)是手动运行 GC.Collect();

namespace Worker
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation($"Worker running at: {DateTime.Now}");

                var files = Directory.EnumerateFiles(@"C:\\repos\");

                var date = files.Select(f => File.ReadAllBytesAsync(f));

                GC.Collect();
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

结果是,我的代码在不手动触发 GC 的情况下会膨胀到最大可用内存,但是,使用手动 GC 可以运行数小时,而资源使用情况不会发生明显变化


解决方案 使用本文中提到的设置:https://dotnet.github.io/orleans/1.5/Documentation/Deployment-and-Operations/Configuration-Guide/Configuring-.NET-Garbage-Collection.html(已弃用)

更新的链接:https://learn.microsoft.com/en-us/dotnet/core/run-time-config/garbage-collector

c# resources garbage-collection backgroundworker asp.net-core-hosted-services

3
推荐指数
1
解决办法
3483
查看次数

c# - DbContext 在BackgroundService 中释放

我有一个 WebAPI,它也应该从 RabbitMQ 接收消息。我使用了这个教程,因为我知道有时 IIS 喜欢终止长时间运行的任务(虽然还没有在服务器上测试它,也许它不起作用)。我有一个处理通过 RabbitMQ 接收的消息的服务。我遇到的第一个问题 - 我无法将它注入到BackgroundService类中,所以我使用了IServiceScopeFactory. 现在,我必须使用来自两个队列的消息,据我了解,最佳实践是为此使用两个通道。但处理是在一项服务中完成的。后台服务:

public class ConsumeRabbitMQHostedService : BackgroundService
{
    private IConnection _connection;
    private IModel _firstChannel;
    private IModel _secondChannel;
    private RabbitConfigSection _rabbitConfig;
    public IServiceScopeFactory _serviceScopeFactory;

    public ConsumeRabbitMQHostedService(IOptions<RabbitConfigSection> rabbitConfig, IServiceScopeFactory serviceScopeFactory)
    {
        _rabbitConfig = rabbitConfig.Value;
        _serviceScopeFactory = serviceScopeFactory;
        InitRabbitMQ();
    }

    private void InitRabbitMQ()
    {
        var factory = new ConnectionFactory { HostName = _rabbitConfig.HostName, UserName = _rabbitConfig.UserName, Password = _rabbitConfig.Password };

        
        _connection = factory.CreateConnection();

        
        _firstChannel = _connection.CreateModel();

        _firstChannel.ExchangeDeclare(_rabbitConfig.DefaultExchange, ExchangeType.Topic); …
Run Code Online (Sandbox Code Playgroud)

c# rabbitmq entity-framework-core asp.net-core asp.net-core-hosted-services

3
推荐指数
1
解决办法
3579
查看次数