我想在ASPNET Core中实现一个周期性的(定时的)IHostedService实例,该实例可以按需停止和启动。我的理解是IHostedService是在应用程序启动时由框架启动的。
但是,我希望能够“手动”启动/停止服务,也许可以通过UI使用开/关切换。理想情况下,“关闭”状态将处理当前正在运行的服务,然后“开启”状态将创建一个新实例。
我在这里阅读了MS文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1。
我最初的想法是获取正在运行的服务的实例,然后调用公共StopAsync(CancellationToken token)
方法。但是,对于应该传递的令牌,我有些困惑,对于StartAsync(CancellationToken cancellationToken)
方法也可以这样说。
关于应该如何进行甚至是建议的任何想法?我的方法在某种程度上与ASPNET Core中托管服务的预期设计背道而驰吗?
编辑7.27.2018
因此,在经过更多研究(又实际上是在阅读文档:D)之后,托管服务StartAsync / StopAsync方法的确与应用程序的生存时间一致。已注册的IHostedServices似乎没有添加到DI容器中以注入到其他类中。
因此,我认为我最初的想法不会奏效。目前,我已使用可在运行时更新的配置依赖项(IOptions<T>
)注册了我的服务。在托管服务正在处理时,它将检查配置以查看其是否应该继续,否则它将等待(而不是停止或处置托管服务)。
除非我听到其他想法,否则我可能会很快将其标记为我的答案。
答案 0 :(得分:6)
对于StopAsync(CancellationToken token)
,您可以传递new System.Threading.CancellationToken()
。在public CancellationToken(bool canceled)
的定义中,canceled
指示令牌的状态。对于您的方案,由于您要停止服务,因此无需指定canceled
。
您可以按照以下步骤操作:
创建IHostedService
public class RecureHostedService : IHostedService, IDisposable
{
private readonly ILogger _log;
private Timer _timer;
public RecureHostedService(ILogger<RecureHostedService> log)
{
_log = log;
}
public void Dispose()
{
_timer.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_log.LogInformation("RecureHostedService is Starting");
_timer = new Timer(DoWork,null,TimeSpan.Zero, TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_log.LogInformation("RecureHostedService is Stopping");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private void DoWork(object state)
{
_log.LogInformation("Timed Background Service is working.");
}
}
注册IHostedService
services.AddSingleton<IHostedService, RecureHostedService>();
启动和停止服务
public class HomeController : Controller {
private readonly RecureHostedService _recureHostedService;
public HomeController(IHostedService hostedService)
{
_recureHostedService = hostedService as RecureHostedService;
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
_recureHostedService.StopAsync(new System.Threading.CancellationToken());
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
_recureHostedService.StartAsync(new System.Threading.CancellationToken());
return View();
} }
答案 1 :(得分:0)
使用Blazor服务器,您可以通过以下方式启动和停止后台服务。 Asp.net Core MVC或Razor是相同的原理
首先,实现IHostService
public class BackService : IHostedService, IDisposable
{
private readonly ILogger _log;
private Timer _timer;
public bool isRunning { get; set; }
public BackService(ILogger<V2rayFlowBackService> log)
{
_log = log;
}
public void Dispose()
{
_timer.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_log.LogInformation($"begin {DateTime.Now}");
_timer = new Timer(DoWorkAsync, null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
isRunning = false;
_log.LogInformation($"{DateTime.Now} BackService is Stopping");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private void DoWorkAsync(object state)
{
_log.LogInformation($"Timed Background Service is working. {DateTime.Now}");
try
{
isRunning = true;
// dosometing you want
}
catch (Exception ex)
{
isRunning = false;
_log.LogInformation("Error {0}", ex.Message);
throw ex;
}
}
}
Startup.cs中的注册服务
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<BackService>();
services.AddHostedService(sp => sp.GetRequiredService<BackService>());
}
将后台服务注入Blazor组件
public class IndexBase:ComponentBase
{
[Inject]
BackService BackService { set; get; }
protected override void OnInitialized()
{
if (BackService.isRunning)
{
BackService.StopAsync(new System.Threading.CancellationToken());
}
base.OnInitialized();
}
public void on()
{
if (!BackService.isRunning)
{
BackService.StartAsync(new System.Threading.CancellationToken());
}
}
public void off()
{
if (BackService.isRunning)
{
BackService.StopAsync(new System.Threading.CancellationToken());
}
}
}
@page "/"
@inherits IndexBase
<h1>Hello, world!</h1>
Welcome to your new app.
<button @onclick="on">Start</button>
<button @onclick="off">Stop</button>