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

    复制代码
    // 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组件源码,会有很多的收获。

     
     
  • 相关阅读:
    HTML编写需要注意的事项
    Java中this、super用法
    多态性的表现形式
    面向对象
    用java实现冒泡排序法
    第一堂java web课
    mysql 复制中的 paxso 的两阶段和事务两阶段的区别
    github删除仓库
    git的介绍及使用
    github的介绍
  • 原文地址:https://www.cnblogs.com/webenh/p/12362955.html
Copyright © 2020-2023  润新知