欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

aspnet core运行后台任务

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

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

aspnet core运行后台任务
// 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();
        }
    }
}
view code

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

aspnet core运行后台任务
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();
        }
    }
}
view code

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

aspnet core运行后台任务
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();
        }
    }
}
view code

最后我们将实现了backgroundservice的类注入到di即可:
services.addhostedservice<timedbackgroundservice>();

dotnet core的microsoft.extensions.hosting 组件中,充斥着类似ihostedservice接口中定义的方法:startasync、stopasync方法。我们注入的hostedservice服务会在webhost类中通过getrequiredservice获取到注入的定时服务。随后执行startasync方法开始执行。建议看看hosting组件源码,会有很多的收获。