.net 为什么后台服务在C#中不停止?

nxagd54h  于 2023-01-10  发布在  .NET
关注(0)|答案(2)|浏览(193)

我正在尝试手动停止从BackgroundService继承的类。
ExampleService.cs

public class ExampleService : BackgroundService, IExampleService
{
    private readonly ILogger<ExampleService> _logger;
    private bool stopRequested { get; set; }

    public ExampleService(ILogger<ExampleService> logger)
    {
        _logger = logger;
    }
    public async Task Stoping(CancellationToken token)
    {
        _logger.LogInformation("Stoping");
        stopRequested = true;
        await StopAsync(token);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var count = 0;
        while (!stoppingToken.IsCancellationRequested && !stopRequested)
        {
            await Task.Delay(1000, stoppingToken);
            _logger.LogInformation("Service is working {0}", count++);
        }
    }
}
public interface IExampleService
{
    Task Stoping(CancellationToken token = default);

}

从API调用

[HttpGet("stoptask2")]
public async Task<IActionResult> Get()
{
    await exampleService.Stoping();
    return Ok();
}

但是服务没有停止。我知道IHostApplicationLifetime在工作,但是所有的应用程序都停止了。我不想这样。
我试过How to cancel manually a BackgroundService in ASP.net core,但它不工作。
我知道我应该在ExecuteAsync中使用stoppingToken停止服务,但如何停止呢?

bvjveswy

bvjveswy1#

在没有看到实际注册的情况下,我只能猜测,但我认为问题在于注册-AddHostedService创建了一个服务描述符,当您注册IExampleService时,它将创建另一个不相关的描述符,因此您有两个不同的服务示例。就我个人而言,我只会使用关注点分离原则,并引入像IStopper这样的独立服务,它将有两个方法StopIStopped(或者暴露一个取消令牌而不是第二个),但是如果你想保持你当前的类/接口结构-那么一定要提供注册,这将只产生一个示例:

builder.Services.AddSingleton<ExampleService>(); // singleton
builder.Services.AddSingleton<IExampleService>(s => s.GetRequiredService<ExampleService>()); // reabstract as interface
builder.Services.AddHostedService<ExampleService>(s => s.GetRequiredService<ExampleService>()); // reabstract as hosted service
1l5u6lss

1l5u6lss2#

我认为停止和执行方法中的CancellationToken不能处理,因为它们是不同的对象,所以使用这个图就可以解决问题。

public class ExampleService : BackgroundService, IExampleService
{
    private readonly ILogger<ExampleService> _logger;
    private CancellationToken cancellationToken = new CancellationToken();
    private static bool stopRequested = true;

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

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var count = 0;
        while (!stoppingToken.IsCancellationRequested)
        {
            if (!stopRequested)
            {
                await base.StopAsync(stoppingToken);
            }
            await Task.Delay(3000, stoppingToken);
            _logger.LogInformation("ExampleService is working {0}", count++);
           
           
        }
    }

    public void Stoping() => stopRequested = false;
}
}

public interface IExampleService
{
    void Stoping();
}

Program.cs

builder.Services.Configure<HostOptions>(hostOptions =>
{
    hostOptions.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore;
});
builder.Services.AddHostedService<ExampleService>();
builder.Services.AddSingleton<IExampleService,ExampleService>();

相关问题