ASP.NET Core içinde barındırılan hizmetlerle arka plan görevleriBackground tasks with hosted services in ASP.NET Core

, Jeow li Hua tarafındanBy Jeow Li Huan

ASP.NET Core, arka plan görevleri barındırılan hizmetlerolarak uygulanabilir.In ASP.NET Core, background tasks can be implemented as hosted services. Barındırılan hizmet, arabirimi uygulayan bir arka plan görevi mantığı olan bir sınıftır IHostedService .A hosted service is a class with background task logic that implements the IHostedService interface. Bu konuda üç barındırılan hizmet örneği sunulmaktadır:This topic provides three hosted service examples:

Örnek kodu görüntüleme veya indirme (nasıl indirileceği)View or download sample code (how to download)

Çalışan hizmeti şablonuWorker Service template

ASP.NET Core Worker hizmeti şablonu, uzun süre çalışan hizmet uygulamalarını yazmak için bir başlangıç noktası sağlar.The ASP.NET Core Worker Service template provides a starting point for writing long running service apps. Çalışan hizmeti şablonundan oluşturulan bir uygulama, çalışan SDK 'sını proje dosyasında belirtir:An app created from the Worker Service template specifies the Worker SDK in its project file:

<Project Sdk="Microsoft.NET.Sdk.Worker">

Şablonu bir barındırılan hizmetler uygulamasının temeli olarak kullanmak için:To use the template as a basis for a hosted services app:

  1. Yeni bir proje oluşturma.Create a new project.
  2. Çalışan hizmetiseçin.Select Worker Service. İleri’yi seçin.Select Next.
  3. Proje adı alanında bir proje adı girin veya varsayılan proje adını kabul edin.Provide a project name in the Project name field or accept the default project name. Oluştur’u seçin.Select Create.
  4. Yeni çalışan hizmeti oluştur Iletişim kutusunda Oluştur' u seçin.In the Create a new Worker service dialog, select Create.

PaketPackage

Çalışan hizmeti şablonunu temel alan bir uygulama Microsoft.NET.Sdk.Worker SDK kullanır ve Microsoft. Extensions. Hosting paketine açık bir paket başvurusu içerir.An app based on the Worker Service template uses the Microsoft.NET.Sdk.Worker SDK and has an explicit package reference to the Microsoft.Extensions.Hosting package. Örneğin, örnek uygulamanın proje dosyasına (Backgroundtaskssample. csproj) bakın.For example, see the sample app's project file (BackgroundTasksSample.csproj).

SDK kullanan Web uygulamaları için Microsoft.NET.Sdk.Web , Microsoft. Extensions. Hosting paketine, paylaşılan çerçeveden dolaylı olarak başvurulur.For web apps that use the Microsoft.NET.Sdk.Web SDK, the Microsoft.Extensions.Hosting package is referenced implicitly from the shared framework. Uygulamanın proje dosyasındaki açık bir paket başvurusu gerekli değildir.An explicit package reference in the app's project file isn't required.

Ihostedservice arabirimiIHostedService interface

IHostedServiceArabirim, konak tarafından yönetilen nesneler için iki yöntem tanımlar:The IHostedService interface defines two methods for objects that are managed by the host:

  • Startasync (CancellationToken): StartAsync arka plan görevinin başlatılacağı mantığı içerir.StartAsync(CancellationToken): StartAsync contains the logic to start the background task. StartAsyncŞu kadar çağrılır:StartAsync is called before:

    Varsayılan davranış, barındırılan hizmetin StartAsync , uygulamanın işlem hattı yapılandırıldıktan ve çağrıldıktan sonra çalışması için değiştirilebilir ApplicationStarted .The default behavior can be changed so that the hosted service's StartAsync runs after the app's pipeline has been configured and ApplicationStarted is called. Varsayılan davranışı değiştirmek için, öğesini çağırdıktan sonra barındırılan hizmeti ( VideosWatcher Aşağıdaki örnekte) ekleyin ConfigureWebHostDefaults :To change the default behavior, add the hosted service (VideosWatcher in the following example) after calling ConfigureWebHostDefaults:

    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
                .ConfigureServices(services =>
                {
                    services.AddHostedService<VideosWatcher>();
                });
    }
    
  • StopAsync (CancellationToken): konak düzgün kapanma yaparken tetiklenir.StopAsync(CancellationToken): Triggered when the host is performing a graceful shutdown. StopAsyncarka plan görevinin bitiş mantığını içerir.StopAsync contains the logic to end the background task. IDisposableYönetilmeyen kaynakların atılmaya yönelik uygulama ve sonlandırıcılar (Yıkıcılar) .Implement IDisposable and finalizers (destructors) to dispose of any unmanaged resources.

    İptal belirtecinin, kapanma işleminin artık düzgün şekilde olmaması gerektiğini göstermek için varsayılan beş saniyelik bir zaman aşımı vardır.The cancellation token has a default five second timeout to indicate that the shutdown process should no longer be graceful. Belirteç üzerinde iptal istendiğinde:When cancellation is requested on the token:

    • Uygulamanın gerçekleştirdiği diğer arka plan işlemleri iptal edilmelidir.Any remaining background operations that the app is performing should be aborted.
    • İçinde çağrılan tüm yöntemler StopAsync hemen döndürmelidir.Any methods called in StopAsync should return promptly.

    Ancak, bir iptal işlemi istendikten sonra görevler terk edilmez — ve bu, çağıran tüm görevlerin tamamlanmasını bekler.However, tasks aren't abandoned after cancellation is requested—the caller awaits all tasks to complete.

    Uygulama beklenmedik bir şekilde kapanırsa (örneğin, uygulamanın işlemi başarısız olur), StopAsync çağrılmayabilir.If the app shuts down unexpectedly (for example, the app's process fails), StopAsync might not be called. Bu nedenle, veya üzerinde gerçekleştirilen işlemleri çağıran Yöntemler StopAsync gerçekleşmeyebilir.Therefore, any methods called or operations conducted in StopAsync might not occur.

    Varsayılan beş saniyelik kapatılma zaman aşımını uzatmak için, şunu ayarlayın:To extend the default five second shutdown timeout, set:

Barındırılan hizmet, uygulama başlangıcında bir kez etkinleştirilir ve uygulama kapatılırken düzgün şekilde kapanır.The hosted service is activated once at app startup and gracefully shut down at app shutdown. Arka plan görevinin yürütülmesi sırasında bir hata oluşursa, Dispose StopAsync çağrılmadıysa bile çağrılmalıdır.If an error is thrown during background task execution, Dispose should be called even if StopAsync isn't called.

BackgroundService temel sınıfıBackgroundService base class

BackgroundService, uzun süre çalışan uygulamaya yönelik bir temel sınıftır IHostedService .BackgroundService is a base class for implementing a long running IHostedService.

Arka plan hizmetini çalıştırmak için ExecuteAsync (CancellationToken) çağırılır.ExecuteAsync(CancellationToken) is called to run the background service. Uygulama, Task arka plan hizmetinin tüm ömrünü temsil eden bir döndürür.The implementation returns a Task that represents the entire lifetime of the background service. ExecuteAsync, çağırarak gibi zaman uyumsuz halegelene kadar başka bir hizmet başlatılamaz await .No further services are started until ExecuteAsync becomes asynchronous, such as by calling await. İçinde başlatma işini uzun süre gerçekleştirmekten kaçının ExecuteAsync .Avoid performing long, blocking initialization work in ExecuteAsync. StopAsync (CancellationToken) içindeki konak blokları tamamlanmasını bekliyor ExecuteAsync .The host blocks in StopAsync(CancellationToken) waiting for ExecuteAsync to complete.

Ihostedservice. StopAsync çağrıldığında iptal belirteci tetiklenir.The cancellation token is triggered when IHostedService.StopAsync is called. ExecuteAsyncHizmeti sorunsuz bir şekilde kapatmak için iptal belirteci tetiklendiğinde uygulamanızın uygulamanız hemen sona ermesini sağlar.Your implementation of ExecuteAsync should finish promptly when the cancellation token is fired in order to gracefully shut down the service. Aksi takdirde, hizmet, kapanmanın zaman aşımından sonra kapanmadığını kaldırır.Otherwise, the service ungracefully shuts down at the shutdown timeout. Daha fazla bilgi için ıhostedservice arabirimi bölümüne bakın.For more information, see the IHostedService interface section.

Zamanlanmış arka plan görevleriTimed background tasks

Zamanlanmış bir arka plan görevi, System. Threading. Timer sınıfından kullanımını sağlar.A timed background task makes use of the System.Threading.Timer class. Zamanlayıcı, görevin DoWork metodunu tetikler.The timer triggers the task's DoWork method. Zamanlayıcı devre dışı bırakılır StopAsync ve hizmet kapsayıcısı bırakıldığında bırakıldı Dispose :The timer is disabled on StopAsync and disposed when the service container is disposed on Dispose:

public class TimedHostedService : IHostedService, IDisposable
{
    private int executionCount = 0;
    private readonly ILogger<TimedHostedService> _logger;
    private Timer _timer;

    public TimedHostedService(ILogger<TimedHostedService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service running.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        var count = Interlocked.Increment(ref executionCount);

        _logger.LogInformation(
            "Timed Hosted Service is working. Count: {Count}", count);
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

, Timer Önceki yürütmelerin bitmesini beklemez, bu DoWork nedenle gösterilen yaklaşım her senaryo için uygun olmayabilir.The Timer doesn't wait for previous executions of DoWork to finish, so the approach shown might not be suitable for every scenario. Interkilitlendi. Increment , yürütme sayacını bir atomik işlem olarak artırmak için kullanılır, bu da birden çok iş parçacığının eşzamanlı olarak güncelleştirilmesini sağlar executionCount .Interlocked.Increment is used to increment the execution counter as an atomic operation, which ensures that multiple threads don't update executionCount concurrently.

Hizmet, IHostBuilder.ConfigureServices (program.cs) AddHostedService öğesine uzantı yöntemiyle kaydedilir:The service is registered in IHostBuilder.ConfigureServices (Program.cs) with the AddHostedService extension method:

services.AddHostedService<TimedHostedService>();

Bir arka plan görevinde kapsamlı bir hizmeti kullanmaConsuming a scoped service in a background task

Bir backgroundserviceiçinde kapsamlı hizmetler kullanmak için bir kapsam oluşturun.To use scoped services within a BackgroundService, create a scope. Barındırılan hizmet için varsayılan olarak kapsam oluşturulmaz.No scope is created for a hosted service by default.

Kapsamlı arka plan görev hizmeti, arka plan görevinin mantığını içerir.The scoped background task service contains the background task's logic. Aşağıdaki örnekte:In the following example:

  • Hizmet zaman uyumsuz.The service is asynchronous. DoWorkYöntemi bir döndürür Task .The DoWork method returns a Task. Tanıtım amacıyla, yöntemde on saniyelik bir gecikme beklenir DoWork .For demonstration purposes, a delay of ten seconds is awaited in the DoWork method.
  • ILoggerHizmete eklenen bir.An ILogger is injected into the service.
internal interface IScopedProcessingService
{
    Task DoWork(CancellationToken stoppingToken);
}

internal class ScopedProcessingService : IScopedProcessingService
{
    private int executionCount = 0;
    private readonly ILogger _logger;
    
    public ScopedProcessingService(ILogger<ScopedProcessingService> logger)
    {
        _logger = logger;
    }

    public async Task DoWork(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            executionCount++;

            _logger.LogInformation(
                "Scoped Processing Service is working. Count: {Count}", executionCount);

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

Barındırılan hizmet, yöntemini çağırmak için kapsamlı arka plan görev hizmetini çözümlemek üzere bir kapsam oluşturur DoWork .The hosted service creates a scope to resolve the scoped background task service to call its DoWork method. DoWorkşunu döndürür Task ExecuteAsync :DoWork returns a Task, which is awaited in ExecuteAsync:

public class ConsumeScopedServiceHostedService : BackgroundService
{
    private readonly ILogger<ConsumeScopedServiceHostedService> _logger;

    public ConsumeScopedServiceHostedService(IServiceProvider services, 
        ILogger<ConsumeScopedServiceHostedService> logger)
    {
        Services = services;
        _logger = logger;
    }

    public IServiceProvider Services { get; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service running.");

        await DoWork(stoppingToken);
    }

    private async Task DoWork(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is working.");

        using (var scope = Services.CreateScope())
        {
            var scopedProcessingService = 
                scope.ServiceProvider
                    .GetRequiredService<IScopedProcessingService>();

            await scopedProcessingService.DoWork(stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is stopping.");

        await Task.CompletedTask;
    }
}

Hizmetler ' de kaydedilir IHostBuilder.ConfigureServices (program.cs).The services are registered in IHostBuilder.ConfigureServices (Program.cs). Barındırılan hizmet, AddHostedService uzantı yöntemiyle kaydedilir:The hosted service is registered with the AddHostedService extension method:

services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();

Sıraya alınan arka plan görevleriQueued background tasks

Arka plan görev kuyruğu, .NET 4. x 'i temel alır QueueBackgroundWorkItem :A background task queue is based on the .NET 4.x QueueBackgroundWorkItem:

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);

    Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private ConcurrentQueue<Func<CancellationToken, Task>> _workItems = 
        new ConcurrentQueue<Func<CancellationToken, Task>>();
    private SemaphoreSlim _signal = new SemaphoreSlim(0);

    public void QueueBackgroundWorkItem(
        Func<CancellationToken, Task> workItem)
    {
        if (workItem == null)
        {
            throw new ArgumentNullException(nameof(workItem));
        }

        _workItems.Enqueue(workItem);
        _signal.Release();
    }

    public async Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken)
    {
        await _signal.WaitAsync(cancellationToken);
        _workItems.TryDequeue(out var workItem);

        return workItem;
    }
}

Aşağıdaki QueueHostedService örnekte:In the following QueueHostedService example:

  • BackgroundProcessingYöntemi Task , ' de beklemiş bir döndürür ExecuteAsync .The BackgroundProcessing method returns a Task, which is awaited in ExecuteAsync.
  • Kuyruktaki arka plan görevleri, içinde kuyruklanmış ve yürütülür BackgroundProcessing .Background tasks in the queue are dequeued and executed in BackgroundProcessing.
  • İş öğeleri, hizmetin durdurulmadan önce bekletildi StopAsync .Work items are awaited before the service stops in StopAsync.
public class QueuedHostedService : BackgroundService
{
    private readonly ILogger<QueuedHostedService> _logger;

    public QueuedHostedService(IBackgroundTaskQueue taskQueue, 
        ILogger<QueuedHostedService> logger)
    {
        TaskQueue = taskQueue;
        _logger = logger;
    }

    public IBackgroundTaskQueue TaskQueue { get; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            $"Queued Hosted Service is running.{Environment.NewLine}" +
            $"{Environment.NewLine}Tap W to add a work item to the " +
            $"background queue.{Environment.NewLine}");

        await BackgroundProcessing(stoppingToken);
    }

    private async Task BackgroundProcessing(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var workItem = 
                await TaskQueue.DequeueAsync(stoppingToken);

            try
            {
                await workItem(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, 
                    "Error occurred executing {WorkItem}.", nameof(workItem));
            }
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Queued Hosted Service is stopping.");

        await base.StopAsync(stoppingToken);
    }
}

Bir MonitorLoop hizmet, giriş cihazında anahtar her seçildiğinde barındırılan hizmet için görevleri sıraya alır w :A MonitorLoop service handles enqueuing tasks for the hosted service whenever the w key is selected on an input device:

  • , IBackgroundTaskQueue MonitorLoop Hizmete eklenir.The IBackgroundTaskQueue is injected into the MonitorLoop service.
  • IBackgroundTaskQueue.QueueBackgroundWorkItembir iş öğesini kuyruğa almak için çağrılır.IBackgroundTaskQueue.QueueBackgroundWorkItem is called to enqueue a work item.
  • Çalışma öğesi uzun süre çalışan bir arka plan görevinin benzetimini yapar:The work item simulates a long-running background task:
    • Üç 5-ikinci gecikme () yürütülür Task.Delay .Three 5-second delays are executed (Task.Delay).
    • try-catch OperationCanceledException Görev iptal edildiğinde bir ifade yakalar.A try-catch statement traps OperationCanceledException if the task is cancelled.
public class MonitorLoop
{
    private readonly IBackgroundTaskQueue _taskQueue;
    private readonly ILogger _logger;
    private readonly CancellationToken _cancellationToken;

    public MonitorLoop(IBackgroundTaskQueue taskQueue, 
        ILogger<MonitorLoop> logger, 
        IHostApplicationLifetime applicationLifetime)
    {
        _taskQueue = taskQueue;
        _logger = logger;
        _cancellationToken = applicationLifetime.ApplicationStopping;
    }

    public void StartMonitorLoop()
    {
        _logger.LogInformation("Monitor Loop is starting.");

        // Run a console user input loop in a background thread
        Task.Run(() => Monitor());
    }

    public void Monitor()
    {
        while (!_cancellationToken.IsCancellationRequested)
        {
            var keyStroke = Console.ReadKey();

            if (keyStroke.Key == ConsoleKey.W)
            {
                // Enqueue a background work item
                _taskQueue.QueueBackgroundWorkItem(async token =>
                {
                    // Simulate three 5-second tasks to complete
                    // for each enqueued work item

                    int delayLoop = 0;
                    var guid = Guid.NewGuid().ToString();

                    _logger.LogInformation(
                        "Queued Background Task {Guid} is starting.", guid);

                    while (!token.IsCancellationRequested && delayLoop < 3)
                    {
                        try
                        {
                            await Task.Delay(TimeSpan.FromSeconds(5), token);
                        }
                        catch (OperationCanceledException)
                        {
                            // Prevent throwing if the Delay is cancelled
                        }

                        delayLoop++;

                        _logger.LogInformation(
                            "Queued Background Task {Guid} is running. " +
                            "{DelayLoop}/3", guid, delayLoop);
                    }

                    if (delayLoop == 3)
                    {
                        _logger.LogInformation(
                            "Queued Background Task {Guid} is complete.", guid);
                    }
                    else
                    {
                        _logger.LogInformation(
                            "Queued Background Task {Guid} was cancelled.", guid);
                    }
                });
            }
        }
    }
}

Hizmetler ' de kaydedilir IHostBuilder.ConfigureServices (program.cs).The services are registered in IHostBuilder.ConfigureServices (Program.cs). Barındırılan hizmet, AddHostedService uzantı yöntemiyle kaydedilir:The hosted service is registered with the AddHostedService extension method:

services.AddSingleton<MonitorLoop>();
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();

MonitorLoopBaşlangıç Program.Main :MonitorLoop is started in Program.Main:

var monitorLoop = host.Services.GetRequiredService<MonitorLoop>();
monitorLoop.StartMonitorLoop();

ASP.NET Core, arka plan görevleri barındırılan hizmetlerolarak uygulanabilir.In ASP.NET Core, background tasks can be implemented as hosted services. Barındırılan hizmet, arabirimi uygulayan bir arka plan görevi mantığı olan bir sınıftır IHostedService .A hosted service is a class with background task logic that implements the IHostedService interface. Bu konuda üç barındırılan hizmet örneği sunulmaktadır:This topic provides three hosted service examples:

Örnek kodu görüntüleme veya indirme (nasıl indirileceği)View or download sample code (how to download)

PaketPackage

Microsoft. AspNetCore. app metapackage 'e başvurun veya Microsoft. Extensions. Hosting paketine bir paket başvurusu ekleyin.Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Hosting package.

Ihostedservice arabirimiIHostedService interface

Barındırılan hizmetler, IHostedService arabirimini uygular.Hosted services implement the IHostedService interface. Arabirim, konak tarafından yönetilen nesneler için iki yöntem tanımlar:The interface defines two methods for objects that are managed by the host:

  • Startasync (CancellationToken): StartAsync arka plan görevinin başlatılacağı mantığı içerir.StartAsync(CancellationToken): StartAsync contains the logic to start the background task. Web konağınıkullanırken StartAsync sunucu başlatıldıktan ve ıapplicationlifetime değerinden sonra çağrılır. applicationstarted tetiklenir.When using the Web Host, StartAsync is called after the server has started and IApplicationLifetime.ApplicationStarted is triggered. Genel ana bilgisayarkullanılırken, StartAsync tetiklendikten önce çağrılır ApplicationStarted .When using the Generic Host, StartAsync is called before ApplicationStarted is triggered.

  • StopAsync (CancellationToken): konak düzgün kapanma yaparken tetiklenir.StopAsync(CancellationToken): Triggered when the host is performing a graceful shutdown. StopAsyncarka plan görevinin bitiş mantığını içerir.StopAsync contains the logic to end the background task. IDisposableYönetilmeyen kaynakların atılmaya yönelik uygulama ve sonlandırıcılar (Yıkıcılar) .Implement IDisposable and finalizers (destructors) to dispose of any unmanaged resources.

    İptal belirtecinin, kapanma işleminin artık düzgün şekilde olmaması gerektiğini göstermek için varsayılan beş saniyelik bir zaman aşımı vardır.The cancellation token has a default five second timeout to indicate that the shutdown process should no longer be graceful. Belirteç üzerinde iptal istendiğinde:When cancellation is requested on the token:

    • Uygulamanın gerçekleştirdiği diğer arka plan işlemleri iptal edilmelidir.Any remaining background operations that the app is performing should be aborted.
    • İçinde çağrılan tüm yöntemler StopAsync hemen döndürmelidir.Any methods called in StopAsync should return promptly.

    Ancak, bir iptal işlemi istendikten sonra görevler terk edilmez — ve bu, çağıran tüm görevlerin tamamlanmasını bekler.However, tasks aren't abandoned after cancellation is requested—the caller awaits all tasks to complete.

    Uygulama beklenmedik bir şekilde kapanırsa (örneğin, uygulamanın işlemi başarısız olur), StopAsync çağrılmayabilir.If the app shuts down unexpectedly (for example, the app's process fails), StopAsync might not be called. Bu nedenle, veya üzerinde gerçekleştirilen işlemleri çağıran Yöntemler StopAsync gerçekleşmeyebilir.Therefore, any methods called or operations conducted in StopAsync might not occur.

    Varsayılan beş saniyelik kapatılma zaman aşımını uzatmak için, şunu ayarlayın:To extend the default five second shutdown timeout, set:

Barındırılan hizmet, uygulama başlangıcında bir kez etkinleştirilir ve uygulama kapatılırken düzgün şekilde kapanır.The hosted service is activated once at app startup and gracefully shut down at app shutdown. Arka plan görevinin yürütülmesi sırasında bir hata oluşursa, Dispose StopAsync çağrılmadıysa bile çağrılmalıdır.If an error is thrown during background task execution, Dispose should be called even if StopAsync isn't called.

Zamanlanmış arka plan görevleriTimed background tasks

Zamanlanmış bir arka plan görevi, System. Threading. Timer sınıfından kullanımını sağlar.A timed background task makes use of the System.Threading.Timer class. Zamanlayıcı, görevin DoWork metodunu tetikler.The timer triggers the task's DoWork method. Zamanlayıcı devre dışı bırakılır StopAsync ve hizmet kapsayıcısı bırakıldığında bırakıldı Dispose :The timer is disabled on StopAsync and disposed when the service container is disposed on Dispose:

internal class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    public TimedHostedService(ILogger<TimedHostedService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Background Service is working.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

, Timer Önceki yürütmelerin bitmesini beklemez, bu DoWork nedenle gösterilen yaklaşım her senaryo için uygun olmayabilir.The Timer doesn't wait for previous executions of DoWork to finish, so the approach shown might not be suitable for every scenario.

Hizmet, Startup.ConfigureServices AddHostedService uzantı yöntemiyle kaydedilir:The service is registered in Startup.ConfigureServices with the AddHostedService extension method:

services.AddHostedService<TimedHostedService>();

Bir arka plan görevinde kapsamlı bir hizmeti kullanmaConsuming a scoped service in a background task

Kapsamlı hizmetleri bir içinde kullanmak için IHostedService bir kapsam oluşturun.To use scoped services within an IHostedService, create a scope. Barındırılan hizmet için varsayılan olarak kapsam oluşturulmaz.No scope is created for a hosted service by default.

Kapsamlı arka plan görev hizmeti, arka plan görevinin mantığını içerir.The scoped background task service contains the background task's logic. Aşağıdaki örnekte, ILogger hizmetine bir hizmet eklenmiş olur:In the following example, an ILogger is injected into the service:

internal interface IScopedProcessingService
{
    void DoWork();
}

internal class ScopedProcessingService : IScopedProcessingService
{
    private readonly ILogger _logger;
    
    public ScopedProcessingService(ILogger<ScopedProcessingService> logger)
    {
        _logger = logger;
    }

    public void DoWork()
    {
        _logger.LogInformation("Scoped Processing Service is working.");
    }
}

Barındırılan hizmet, kendi metodunu çağırmak için kapsamlı arka plan görev hizmetini çözümlemek üzere bir kapsam oluşturur DoWork :The hosted service creates a scope to resolve the scoped background task service to call its DoWork method:

internal class ConsumeScopedServiceHostedService : IHostedService
{
    private readonly ILogger _logger;

    public ConsumeScopedServiceHostedService(IServiceProvider services, 
        ILogger<ConsumeScopedServiceHostedService> logger)
    {
        Services = services;
        _logger = logger;
    }

    public IServiceProvider Services { get; }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is starting.");

        DoWork();

        return Task.CompletedTask;
    }

    private void DoWork()
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is working.");

        using (var scope = Services.CreateScope())
        {
            var scopedProcessingService = 
                scope.ServiceProvider
                    .GetRequiredService<IScopedProcessingService>();

            scopedProcessingService.DoWork();
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is stopping.");

        return Task.CompletedTask;
    }
}

Hizmetler ' de kaydedilir Startup.ConfigureServices .The services are registered in Startup.ConfigureServices. IHostedServiceUygulama, AddHostedService uzantı yöntemiyle kaydedilir:The IHostedService implementation is registered with the AddHostedService extension method:

services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();

Sıraya alınan arka plan görevleriQueued background tasks

Arka plan görev kuyruğu .NET Framework 4. x ' i temel alır QueueBackgroundWorkItem (ASP.NET Core için yerleşik olarak zamanlanmış olarak zamanlandı):A background task queue is based on the .NET Framework 4.x QueueBackgroundWorkItem (tentatively scheduled to be built-in for ASP.NET Core):

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);

    Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private ConcurrentQueue<Func<CancellationToken, Task>> _workItems = 
        new ConcurrentQueue<Func<CancellationToken, Task>>();
    private SemaphoreSlim _signal = new SemaphoreSlim(0);

    public void QueueBackgroundWorkItem(
        Func<CancellationToken, Task> workItem)
    {
        if (workItem == null)
        {
            throw new ArgumentNullException(nameof(workItem));
        }

        _workItems.Enqueue(workItem);
        _signal.Release();
    }

    public async Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken)
    {
        await _signal.WaitAsync(cancellationToken);
        _workItems.TryDequeue(out var workItem);

        return workItem;
    }
}

' De QueueHostedService , kuyruktaki arka plan görevleri, uzun süre çalışan uygulama için temel bir sınıf olan bir backgroundserviceolarak kuyruğa alınır ve yürütülür IHostedService :In QueueHostedService, background tasks in the queue are dequeued and executed as a BackgroundService, which is a base class for implementing a long running IHostedService:

public class QueuedHostedService : BackgroundService
{
    private readonly ILogger _logger;

    public QueuedHostedService(IBackgroundTaskQueue taskQueue, 
        ILoggerFactory loggerFactory)
    {
        TaskQueue = taskQueue;
        _logger = loggerFactory.CreateLogger<QueuedHostedService>();
    }

    public IBackgroundTaskQueue TaskQueue { get; }

    protected async override Task ExecuteAsync(
        CancellationToken cancellationToken)
    {
        _logger.LogInformation("Queued Hosted Service is starting.");

        while (!cancellationToken.IsCancellationRequested)
        {
            var workItem = await TaskQueue.DequeueAsync(cancellationToken);

            try
            {
                await workItem(cancellationToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, 
                   "Error occurred executing {WorkItem}.", nameof(workItem));
            }
        }

        _logger.LogInformation("Queued Hosted Service is stopping.");
    }
}

Hizmetler ' de kaydedilir Startup.ConfigureServices .The services are registered in Startup.ConfigureServices. IHostedServiceUygulama, AddHostedService uzantı yöntemiyle kaydedilir:The IHostedService implementation is registered with the AddHostedService extension method:

services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();

Dizin sayfası model sınıfında:In the Index page model class:

  • IBackgroundTaskQueueOluşturucuya eklenir ve öğesine atanır Queue .The IBackgroundTaskQueue is injected into the constructor and assigned to Queue.
  • IServiceScopeFactoryEklenen ve öğesine atandı _serviceScopeFactory .An IServiceScopeFactory is injected and assigned to _serviceScopeFactory. Fabrika, IServiceScope bir kapsam içinde hizmet oluşturmak için kullanılan örnekleri oluşturmak için kullanılır.The factory is used to create instances of IServiceScope, which is used to create services within a scope. Uygulama (bir tekil AppDbContext hizmet) içinde veritabanı kayıtları yazmak için uygulamanın ( kapsamlı bir hizmet) kullanılabilmesi için bir kapsam oluşturulur IBackgroundTaskQueue .A scope is created in order to use the app's AppDbContext (a scoped service) to write database records in the IBackgroundTaskQueue (a singleton service).
public class IndexModel : PageModel
{
    private readonly AppDbContext _db;
    private readonly ILogger _logger;
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public IndexModel(AppDbContext db, IBackgroundTaskQueue queue, 
        ILogger<IndexModel> logger, IServiceScopeFactory serviceScopeFactory)
    {
        _db = db;
        _logger = logger;
        Queue = queue;
        _serviceScopeFactory = serviceScopeFactory;
    }

    public IBackgroundTaskQueue Queue { get; }

Dizin sayfasında Görev Ekle düğmesi seçildiğinde OnPostAddTask Yöntem yürütülür.When the Add Task button is selected on the Index page, the OnPostAddTask method is executed. QueueBackgroundWorkItembir iş öğesini kuyruğa almak için çağrılır:QueueBackgroundWorkItem is called to enqueue a work item:

public IActionResult OnPostAddTaskAsync()
{
    Queue.QueueBackgroundWorkItem(async token =>
    {
        var guid = Guid.NewGuid().ToString();

        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var scopedServices = scope.ServiceProvider;
            var db = scopedServices.GetRequiredService<AppDbContext>();

            for (int delayLoop = 1; delayLoop < 4; delayLoop++)
            {
                try
                {
                    db.Messages.Add(
                        new Message() 
                        { 
                            Text = $"Queued Background Task {guid} has " +
                                $"written a step. {delayLoop}/3"
                        });
                    await db.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, 
                        "An error occurred writing to the " +
                        "database. Error: {Message}", ex.Message);
                }

                await Task.Delay(TimeSpan.FromSeconds(5), token);
            }
        }

        _logger.LogInformation(
            "Queued Background Task {Guid} is complete. 3/3", guid);
    });

    return RedirectToPage();
}

Ek kaynaklarAdditional resources