我应该在哪里开始ASP.NET Core中的持久后台任务?

时间:2018-01-10 00:48:38

标签: c# asp.net-core .net-core hangfire

在我的Web应用程序(ASP.NET Core)中,我想在后台运行一个正在侦听远程服务器的作业,计算一些结果并将其推送到Pusher上的客户端(websocket)。

我不确定我应该在哪里开始这个任务。目前我在

结尾处开始
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
Startup.cs

但是我觉得这有点不对,在一个名为" Configure"的方法中启动后台作业没有意义。我期待在某处找到一个Start方法

此外,当我尝试将EF Core用于generate initial database migration file时,它实际上会执行该方法并启动我的任务......这显然没有任何意义:

dotnet ef migrations add InitialCreate

从控制台运行该代码会创建迁移代码,该代码将用于根据我的数据模型在SQL Server上创建数据库。

为什么我没有办法开始一项任务?我不希望这是一个单独的进程,它实际上不需要自己的进程,它本质上是Web服务器的一部分,因为它确实通过websocket与客户端(浏览器)进行通信,所以将它作为Web服务器的一部分运行是有意义的。

1 个答案:

答案 0 :(得分:6)

我相信你正在寻找这个

https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/

我做了一个2小时自我宣传获奖的黑客马拉松对我自己去学习。

https://github.com/nixxholas/nautilus

您可以在此处参考注射并从那里实施摘要。

许多MVC项目并不是真正需要运行持久性后台任务。这就是为什么你不能通过模板看到它们被烘焙到一个全新的项目中。为开发人员提供一个界面可以点击并继续使用它会更好。

另外,关于为这些后台任务打开套接字连接,我还没有为此建立解决方案。据我所知/做过,我只能将负载广播到连接到我自己的socketmanager的客户端,所以你必须在其他地方查找。如果IHostedService中有关于websockets的任何内容,我肯定会发出哔哔声。

好的,无论如何,这会发生什么。

将它放在项目的某个地方,它更多的是一个让你重载以创建自己的任务的界面

/// 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
    {
        protected readonly IServiceScopeFactory _scopeFactory;
        private Task _executingTask;
        private readonly CancellationTokenSource _stoppingCts =
                                                       new CancellationTokenSource();

        public BackgroundService(IServiceScopeFactory scopeFactory) {
            _scopeFactory = scopeFactory;
        }

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

以下是如何实际使用它

public class IncomingEthTxService : BackgroundService
    {
        public IncomingEthTxService(IServiceScopeFactory scopeFactory) : base(scopeFactory)
        {
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {

            while (!stoppingToken.IsCancellationRequested)
            {
                using (var scope = _scopeFactory.CreateScope())
                {
                    var dbContext = scope.ServiceProvider.GetRequiredService<NautilusDbContext>();

                    Console.WriteLine("[IncomingEthTxService] Service is Running");

                    // Run something

                    await Task.Delay(5, stoppingToken);
                }
            }
        }
    }

如果你注意到,那里有奖金。您必须使用服务范围才能访问数据库操作,因为它是单例。

中注入您的服务
// Background Service Dependencies
            services.AddSingleton<IHostedService, IncomingEthTxService>();