简体   繁体   English

ASP.NET 核心 IHostedService 手动启动/停止/暂停(?)

[英]ASP.NET Core IHostedService manual start/stop/pause(?)

I would like to implement a recurring (timed) IHostedService instance in AS.NET Core that can be stopped and started on demand.我想在 AS.NET Core 中实现一个可以按需停止和启动的循环(定时)IHostedService 实例。 My understanding is that IHostedService(s) are started by the framework on application startup.我的理解是 IHostedService(s) 是在应用程序启动时由框架启动的。

However, I would like to be able to start/stop the service 'manually', perhaps using an on/off toggle via a UI.但是,我希望能够“手动”启动/停止服务,或许可以通过 UI 使用开/关切换。 Ideally the "off" state would dispose of currently running service, and the "on" state would then create a new instance.理想情况下,“关闭”state 将处理当前正在运行的服务,然后“打开”state 将创建一个新实例。

I've read the MS docs here: https://learn.microsoft.com/en-us/as.net/core/fundamentals/host/hosted-services?view=as.netcore-2.1 .我在这里阅读了 MS 文档: https://learn.microsoft.com/en-us/as.net/core/fundamentals/host/hosted-services?view=as.netcore-2.1

My initial thought was to get an instance of the running service and then call the public StopAsync(CancellationToken token) method.我最初的想法是获取正在运行的服务的实例,然后调用 public StopAsync(CancellationToken token)方法。 However I'm a little stuck when it comes to which token I should pass in, and the same could be said for the StartAsync(CancellationToken cancellationToken) method.但是,当谈到我应该传入哪个令牌时,我有点卡住了,对于StartAsync(CancellationToken cancellationToken)方法也是如此。

Any ideas on how this should be done, or if it's even advisable?关于应该如何完成的任何想法,或者它是否可取? Is my approach somehow going against the intended design of hosted services in AS.NET Core?我的方法是否以某种方式违背了 AS.NET Core 中托管服务的预期设计?

EDIT 7.27.2018编辑 2018 年 7 月 27 日

So it appears after some more research (aka actually reading the documentation:D) that hosted services StartAsync/StopAsync methods are indeed meant to coincide with the lifetime of the application.因此,经过更多研究(又名实际阅读文档:D)后,托管服务 StartAsync/StopAsync 方法似乎确实与应用程序的生命周期一致。 Registered IHostedServices seem to not be added to the DI container for injection into other classes.注册的 IHostedServices 似乎没有添加到 DI 容器中以注入其他类。

Therefore I do not think my initial idea will work.因此,我认为我最初的想法不会奏效。 For now I registered my services with configuration dependencies ( IOptions<T> ) that can be updated at runtime.现在,我使用可以在运行时更新的配置依赖项 ( IOptions<T> ) 注册了我的服务。 As the hosted services is processing, it will check the configuration to see if it should continue, otherwise it will just wait (instead of stopping or disposing of the hosted service).当托管服务正在处理时,它将检查配置以查看它是否应该继续,否则它将只是等待(而不是停止或处置托管服务)。

I'll probably mark this as my answer soon, unless I hear of some other ideas.除非我听到其他想法,否则我可能很快会将其标记为我的答案。

For StopAsync(CancellationToken token) , you could pass new System.Threading.CancellationToken() .对于StopAsync(CancellationToken token) ,您可以传递new System.Threading.CancellationToken() In the defination of public CancellationToken(bool canceled) , canceled indicates state for the token.在概念的探讨public CancellationToken(bool canceled)canceled指示令牌状态。 For your scenario, there is no need to specify the canceled since you want to Stop the service.对于您的场景,由于您要停止服务,因此无需指定canceled

You could follow below step by step:您可以按照以下步骤进行操作:

  1. Create IHostedService创建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."); } }
  2. Register IHostedService注册IHostedService

     services.AddSingleton<IHostedService, RecureHostedService>();
  3. Start and Stop Service启动和停止服务

     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(); } }

You should inherit your HostedService from your own Interface and register your service as Singleton, but in a difference way:您应该从您自己的接口继承您的 HostedService 并将您的服务注册为 Singleton,但以不同的方式:

First register your service with AddHostedService generic method.首先使用AddHostedService通用方法注册您的服务。

        services.AddHostedService<TimerHostedService>();

Then add a public static field to your class named Instance , that holds the instance reference of your class and set its value in the constructor!然后将公共 static 字段添加到名为Instance的 class 中,它保存 class 的实例引用并在构造函数中设置它的值!

Then put a factory in the ConfigureServices for registering your service as singleton that returns the static instance field !然后在 ConfigureServices 中放置一个工厂,用于将您的服务注册为 singleton,返回 static 实例字段!

Here is the sample code: (in your HostedService.cs: )这是示例代码:(在您的HostedService.cs中:)

public interface ITimerHostedService : IHostedService
{

}

public class TimerHostedService : ITimerHostedService
{
    private static TimerHostedService _instance;

    public static TimerHostedService Instance => _instance;

    public TimerHostedService(ILogger<TimerHostedService> logger)
    {
        if(_instance == null)
        {
            _instance = this;
        }
    }
}

And here is the code for registering your service as singleton ( in Startup.cs ):这是将您的服务注册为 singleton 的代码(在Startup.cs中):

        services.AddHostedService<TimerHostedService>();

        services.AddSingleton<ITimerHostedService, TimerHostedService>(serviceProvider =>
        {
            return TimerHostedService.Instance;
        });

And here is the code in your Controller to manually start / stop your HostedService:这是Controller中用于手动启动/停止 HostedService 的代码:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ITimerHostedService _hostedService;

    public HomeController(ILogger<HomeController> logger, ITimerHostedService hostedService)
    {
        _logger = logger;
        _hostedService = hostedService;
    }

    public async Task<IActionResult> Start()
    {
        await _hostedService.StartAsync(default);
        
        return Ok();
    }

    public async Task<IActionResult> Stop()
    {
        await _hostedService.StopAsync(default);
        
        return Ok();
    }
}

Happy Coding!快乐编码!

Enjoy Your Lovely Moments:X享受你的美好时光:X

Using Blazor Server, you can start and stop background services in the following ways.使用 Blazor 服务器,您可以通过以下方式启动和停止后台服务。 Asp.net Core MVC or Razor is the same principle Asp.net Core MVC 或者 Razor 原理是一样的

First, implement an IHostService首先,实现一个 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;

        }
    }
}

Registration Service In Startup.cs Startup.cs 中的注册服务

public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<BackService>();
        services.AddHostedService(sp => sp.GetRequiredService<BackService>());
    }

Inject background services into Blazor components将后台服务注入 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>

reference参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 ASP.Net Core 中使用 IHostedService? - How to use IHostedService in ASP.Net Core? 使用ASP.NET Core 2.0将简单的Injector组件注入IHostedService - Injecting Simple Injector components into IHostedService with ASP.NET Core 2.0 ASP.NET Core 中的手动内容协商 - Manual content negotiation in ASP.NET Core Asp.Net - 使用 IHostedService 的计划任务 - Asp.Net - Scheduled Task using IHostedService 在 asp.net 核心应用程序中实现了 IHostedService,如何在没有 IIS 的第一个请求的情况下运行它? - Implemented IHostedService in an asp.net core app, How to run it without the first request on IIS? Asp.net 内核如何注册也包含自定义接口的 IHostedService - Asp.net core How to Register IHostedService which also Contains a Custom Interface 如何通过 ASP.NET Core 中的依赖注入获取对 IHostedService 的引用? - How do I get a reference to an IHostedService via Dependency Injection in ASP.NET Core? 在 ASP.NET Core 依赖注入中手动注册控制器 - Manual controller registration in ASP.NET Core dependency injection 在哪里可以记录 ASP.NET Core 应用程序的启动/停止/错误事件? - Where can I log an ASP.NET Core app's start/stop/error events? asp .net 核心中 IHostedService.StartAsync 中的 CancellationToken 有什么意义? - What is the point of the CancellationToken in IHostedService.StartAsync in asp .net core?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM