zoukankan      html  css  js  c++  java
  • aspnet core运行后台服务任务

    之前在公司的一个项目中需要用到定时程序,当时使用的是aspnet core提供的IHostedService接口来实现后台定时程序,具体的示例可去官网查看。现在的dotnet core中默认封装了实现IHostedService接口的基类BackgroundService,该类实现如下:

    复制代码
    // Copyright (c) .NET Foundation. All rights reserved.
    // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
    
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Microsoft.Extensions.Hosting
    {
        /// <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();
    
            /// <summary>
            /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
            /// the lifetime of the long running operation(s) being performed.
            /// </summary>
            /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
            /// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
            protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    
            /// <summary>
            /// Triggered when the application host is ready to start the service.
            /// </summary>
            /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
            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;
            }
    
            /// <summary>
            /// Triggered when the application host is performing a graceful shutdown.
            /// </summary>
            /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
            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();
            }
        }
    }
    复制代码

    根据BackgroundService源码,我们只要实现该类的抽象方法ExecuteAsync即可。
    可以有两种实现方式来做定时程序,第一种就是实现一个Timer:

    复制代码
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using System;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace DemoOne.Models
    {
        public class TimedBackgroundService : BackgroundService
        {
            private readonly ILogger _logger;
            private Timer _timer;
    
            public TimedBackgroundService(ILogger<TimedBackgroundService> logger)
            {
                _logger = logger;
            }
    
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
                _logger.LogInformation("周六!");
                return Task.CompletedTask;
    
                //Console.WriteLine("MyServiceA is starting.");
    
                //stoppingToken.Register(() => File.Create($"E:\dotnetCore\Practice\Practice\{DateTime.Now.Millisecond}.txt"));
    
                //while (!stoppingToken.IsCancellationRequested)
                //{
                //    Console.WriteLine("MyServiceA 开始执行");
    
                //    await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
    
                //    Console.WriteLine("继续执行");
                //}
    
                //Console.WriteLine("MyServiceA background task is stopping.");
            }
    
            private void DoWork(object state)
            {
                _logger.LogInformation($"Hello World! - {DateTime.Now}");
            }
    
            public override void Dispose()
            {
                base.Dispose();
                _timer?.Dispose();
            }
        }
    }
    复制代码

    我们看看StartAsync的源码。上面的实现方式会直接返回一个已完成的Task,这样就会直接运行StartAsync方法的if判断,那么如果我们不走if呢?那么就应该由StartAsync方法返回一个已完成的Task.
    第二个即是:

    复制代码
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using System;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace DemoOne.Models
    {
        public class TimedBackgroundService : BackgroundService
        {
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                Console.WriteLine("MyServiceA is starting.");
    
                stoppingToken.Register(() => File.Create($"E:\dotnetCore\Practice\Practice\{DateTime.Now.Millisecond}.txt"));
    
                while (!stoppingToken.IsCancellationRequested)
                {
                    Console.WriteLine("MyServiceA 开始执行");
    
                    await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
    
                    Console.WriteLine("继续执行");
                }
    
                Console.WriteLine("MyServiceA background task is stopping.");
            }
    
            public override void Dispose()
            {
                base.Dispose();
            }
        }
    }
    复制代码

    最后我们将实现了BackgroundService的类注入到DI即可:
    services.AddHostedService<TimedBackgroundService>();

    dotnet core的Microsoft.Extensions.Hosting 组件中,充斥着类似IHostedService接口中定义的方法:StartAsync、StopAsync方法。我们注入的HostedService服务会在WebHost类中通过GetRequiredService获取到注入的定时服务。随后执行StartAsync方法开始执行。建议看看Hosting组件源码,会有很多的收获。

  • 相关阅读:
    vue form dynamic validator All In one
    TypeScript api response interface All In One
    closable VS closeable All In One
    macOS 如何开启 WiFi 热点 All In One
    vue css inline style All In One
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (下)
    牛腩新闻 59 整合添加新闻页 FreeTextBox 富文本编辑器,检测到有潜在危险的 Request.Form 值,DropDownList 的使用
    牛腩新闻 61尾声: error.aspx的使用 防止报错
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (上)
    牛腩新闻 62:尾声续2 asp.net的编译和发布
  • 原文地址:https://www.cnblogs.com/webenh/p/12362963.html
Copyright © 2011-2022 走看看