zoukankan      html  css  js  c++  java
  • 在asp.net core中使用托管服务实现后台任务

    在业务场景中经常需要后台服务不停的或定时处理一些任务,这些任务是不需要及时响应请求的。
    在 asp.net中会使用windows服务来处理。
    在 asp.net core中,可以使用托管服务来实现,托管服务是一个类,具有实现IHostService接口的后台任务逻辑。

    导入包

    使用NUGET添加Microsoft.Extensions.Hosting包到项目中
     Microsoft.Extensions.Hosting包地址

    IHostedService接口

    • 托管服务必须实现IHostedService接口,该接口为主机管理的对象定义了两种方法。
      StartAsync(CancellationToken) - StartAsync包含启动后台任务的逻辑。使用Web主机时,StartAsync在服务器启动并且触发IApplicationLifetime.ApplicationStarted后调用。使用Generic Host时,StartAsync会在ApplicationStarted触发之前调用。

    • StopAsync(CancellationToken) - 在主机执行正常关闭时触发。StopAsync包含结束后台任务的逻辑。实现IDisposable和终结器(析构函数)来处理任何非托管资源。

    取消令牌具有默认的五秒超时,以指示关闭过程不再是正常的。在令牌上请求取消时:

    应该中止应用正在执行的任何剩余后台操作。
    任何调用的方法都StopAsync应该立即返回。
    但是,在请求取消后,任务不会被放弃 - 调用者等待所有任务完成。

    如果应用程序被意外关闭(例如,应用程序的进程失败),则StopAsync可能无法调用。因此,StopAsync是有可能不会被调用的。

    托管服务在应用启动时激活一次,并在应用关闭时正常关闭。为防止异常,最好继承IDispose接口,释放资源

    定时后台任务用例

    可以写一个托管服务类直接继承IHostedService,和IDisposable接口

     public class MyTimerHostedService : IHostedService, IDisposable
        {
            private Timer _timer;
    
            public Task StartAsync(CancellationToken cancellationToken)
            {
                Console.WriteLine("启动定时任务托管服务");
    
                _timer = new Timer(DoWork, null, TimeSpan.Zero,
                    TimeSpan.FromSeconds(0.5));
    
                return Task.CompletedTask;
            }
    
            private void DoWork(object state)
            {
                Console.WriteLine("定时任务处理中");
            }
    
            public Task StopAsync(CancellationToken cancellationToken)
            {
                _timer?.Change(Timeout.Infinite, 0);
                Console.WriteLine("停止定时任务");
                return Task.CompletedTask;
            }
    
            public void Dispose()
            {
                // 手动释放定时器
                _timer?.Dispose();
            }
        }
    

    该服务Startup.ConfigureServices使用AddHostedService扩展方法注册:

    services.AddHostedService<MyTimerHostedService>();
    

    使用通用主机启动 托管服务

      class Program
        {
            static void Main(string[] args)
            {
                var host = new HostBuilder().ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<MyTimerHostedService>();
                }).Build();
    
                host.Run();
    
                Console.WriteLine("Hello World!");
                Console.ReadLine();
            }
        }
    

    输出效果

    使用后台服务BackgroundService 实现

    .NET Core中实现的抽象BackgroundService基类。

    // Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
    /// <summary>
    /// Base class for implementing a long running <see cref="IHostedService"/>.
    /// </summary>
    public abstract class BackgroundService : IHostedService, IDisposable
    {
        private Task _executingTask;
        private readonly CancellationTokenSource _stoppingCts =
                                                       new CancellationTokenSource();
    
        protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    
        public virtual Task StartAsync(CancellationToken cancellationToken)
        {
            // Store the task we're executing
            _executingTask = ExecuteAsync(_stoppingCts.Token);
    
            // If the task is completed then return it,
            // this will bubble cancellation and failure to the caller
            if (_executingTask.IsCompleted)
            {
                return _executingTask;
            }
    
            // Otherwise it's running
            return Task.CompletedTask;
        }
    
        public virtual async Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop called without start
            if (_executingTask == null)
            {
                return;
            }
    
            try
            {
                // Signal cancellation to the executing method
                _stoppingCts.Cancel();
            }
            finally
            {
                // Wait until the task completes or the stop token triggers
                await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
                                                              cancellationToken));
            }
    
        }
    
        public virtual void Dispose()
        {
            _stoppingCts.Cancel();
        }
    }
    

    由于抽象类已经实现了IHostService接口定义的方法,只需要写子类去继承BackgroundService, 在自己的自定义托管服务类中实现ExecuteAsync()方法

     public class MyBackGroundService : BackgroundService
        {
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    Console.WriteLine("MyBackGroundService doing");
    
                    //延迟500毫秒执行 相当于使用了定时器
                    await Task.Delay(500, stoppingToken);
                }
            }
        }
    

    在主机中托管服务

    class Program
        {
            static void Main(string[] args)
            {
                var host = new HostBuilder().ConfigureServices((hostContext, services) =>
                {
                    //services.AddHostedService<MyTimerHostedService>();
                    services.AddHostedService<MyBackGroundService>();
                }).Build();
    
                host.Run();
    
                Console.WriteLine("Hello World!");
                Console.ReadLine();
            }
        }
    

    使用了HostService后极大的方便了后台任务的管理

    github源码地址

  • 相关阅读:
    多线程
    集合与文件操作
    Net基础复习
    form表单
    html的常用标签和属性
    C#泛型与linq
    2020 年度总结 & OI 生涯感想——当年酒狂自负
    TODO-List
    Attention Points
    THUWC2020 游记
  • 原文地址:https://www.cnblogs.com/sands/p/11460137.html
Copyright © 2011-2022 走看看