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

, Luke Latham ve Jeow li Hua tarafındanBy Luke Latham and 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, IHostedService arabirimini uygulayan bir arka plan görevi mantığı içeren bir sınıftır.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şturun.Create a new project.
  2. Çalışan hizmetiseçin.Select Worker Service. İleri ' yiseç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).

Microsoft.NET.Sdk.Web SDK kullanan Web uygulamaları için, 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

IHostedService arabirimi, 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 ApplicationStarted çağrıldıktan sonra çalışması için değiştirilebilir.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, ConfigureWebHostDefaultsçağrıldıktan sonra barındırılan hizmeti (aşağıdaki örnekteVideosWatcher) ekleyin: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) –, ana bilgisayar düzgün bir şekilde kapanma gerçekleştirirken tetiklenir.StopAsync(CancellationToken) – Triggered when the host is performing a graceful shutdown. StopAsync arka plan görevinin sonundaki mantığı içerir.StopAsync contains the logic to end the background task. Yönetilmeyen kaynakların atılmaya yönelik IDisposable ve sonlandırıcılar (Yıkıcılar) uygulayın.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.
    • StopAsync içinde çağrılan yöntemler hemen döndürmelidir.Any methods called in StopAsync should return promptly.

    Ancak,—istek iptal edildikten sonra, ç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 şekilde kapanıyorsa (örneğin, uygulamanın işlemi başarısız olursa) StopAsync çağrımayabilir.If the app shuts down unexpectedly (for example, the app's process fails), StopAsync might not be called. Bu nedenle, StopAsync veya içinde gerçekleştirilen işlemler tarafından çağrılan yöntemler 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şturulursa, StopAsync çağrılmasa bile Dispose çağrılmalıdır.If an error is thrown during background task execution, Dispose should be called even if StopAsync isn't called.

BackgroundServiceBackgroundService

BackgroundService, uzun süre çalışan bir IHostedServiceuygulamaya yönelik temel bir sınıftır.BackgroundService is a base class for implementing a long running IHostedService. BackgroundService, hizmetin mantığını içerecek ExecuteAsync(CancellationToken stoppingToken) soyut yöntemi sağlar.BackgroundService provides the ExecuteAsync(CancellationToken stoppingToken) abstract method to contain the service's logic. stoppingToken, ıhostedservice. StopAsync çağrıldığında tetiklenir.The stoppingToken is triggered when IHostedService.StopAsync is called. Bu yöntemin uygulanması, arka plan hizmetinin tüm ömrünü temsil eden bir Task döndürür.The implementation of this method returns a Task that represents the entire lifetime of the background service.

Ayrıca, isteğe bağlı olarak, hizmetiniz için başlatma ve kapatılma kodunu çalıştırmak üzere IHostedService tanımlı yöntemleri geçersiz kılın:In addition, optionally override the methods defined on IHostedService to run startup and shutdown code for your service:

  • Uygulama ana bilgisayarı düzgün kapanma yaparken StopAsync(CancellationToken cancellationToken)StopAsync çağrılır.StopAsync(CancellationToken cancellationToken)StopAsync is called when the application host is performing a graceful shutdown. cancellationToken, ana bilgisayar hizmeti zorla sonlandırmak için karar verdiğinde çağrılır.The cancellationToken is signalled when the host decides to forcibly terminate the service. Bu yöntem geçersiz kılınırsa, hizmetin düzgün kapatılmasını sağlamak için temel sınıf yöntemini çağırmanız (ve await) gerekir .If this method is overridden, you must call (and await) the base class method to ensure the service shuts down properly.
  • arka plan hizmetini başlatmak için StartAsync(CancellationToken cancellationToken)StartAsync çağırılır.StartAsync(CancellationToken cancellationToken)StartAsync is called to start the background service. Başlangıç işlemi kesintiye uğrarsa cancellationToken çağrılır.The cancellationToken is signalled if the startup process is interrupted. Uygulama, hizmetin başlatma sürecini temsil eden bir Task döndürür.The implementation returns a Task that represents the startup process for the service. Bu Task tamamlanana kadar başka hizmet başlatılamaz.No further services are started until this Task completes. Bu yöntem geçersiz kılınırsa, hizmetin düzgün şekilde başlamasını sağlamak için temel sınıf yöntemini çağırmanız (ve await) gerekir .If this method is overridden, you must call (and await) the base class method to ensure the service starts properly.

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 yöntemini tetikler.The timer triggers the task's DoWork method. Zamanlayıcı StopAsync devre dışı bırakılır ve hizmet kapsayıcısı Disposebırakıldığında atıldı: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)
    {
        executionCount++;

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

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

Hizmet, AddHostedService uzantısı yöntemiyle IHostBuilder.ConfigureServices (program.cs) 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

Kapsamlı hizmetleri bir BackgroundServiceiçinde 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. DoWork yöntemi bir Taskdöndürür.The DoWork method returns a Task. Tanıtım amacıyla, DoWork yönteminde on saniyelik bir gecikme beklenir.For demonstration purposes, a delay of ten seconds is awaited in the DoWork method.
  • Hizmete bir ILogger eklenir.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, DoWork yöntemini çağırmak için kapsamlı arka plan görev hizmetini çözümlemek üzere bir kapsam oluşturur.The hosted service creates a scope to resolve the scoped background task service to call its DoWork method. DoWork, ExecuteAsyncbeklemiş olan bir Taskdöndürür: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 IHostBuilder.ConfigureServices kaydedilir (program.cs).The services are registered in IHostBuilder.ConfigureServices (Program.cs). Barındırılan hizmet AddHostedService uzantısı 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 QueueBackgroundWorkItem temel alır (ASP.NET Core için yerleşikolarak, kesin olarak zamanlandı):A background task queue is based on the .NET 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;
    }
}

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

  • BackgroundProcessing yöntemi, ExecuteAsyncbeklemiş olan bir Taskdöndürür.The BackgroundProcessing method returns a Task, which is awaited in ExecuteAsync.
  • Kuyruktaki arka plan görevleri, BackgroundProcessingsırada kuyruğa alınır ve yürütülür.Background tasks in the queue are dequeued and executed in BackgroundProcessing.
  • İş öğeleri, hizmet StopAsync' de durdurulmadan önce bekletildi.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 hizmeti, giriş cihazında w anahtarı seçildiğinde barındırılan hizmet için görevleri sıraya alır:A MonitorLoop service handles enqueuing tasks for the hosted service whenever the w key is selected on an input device:

  • IBackgroundTaskQueue, MonitorLoop hizmetine eklenir.The IBackgroundTaskQueue is injected into the MonitorLoop service.
  • IBackgroundTaskQueue.QueueBackgroundWorkItem bir 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 bir ifade, görev iptal edildiğinde OperationCanceledException 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 IHostBuilder.ConfigureServices kaydedilir (program.cs).The services are registered in IHostBuilder.ConfigureServices (Program.cs). Barındırılan hizmet AddHostedService uzantısı yöntemiyle kaydedilir:The hosted service is registered with the AddHostedService extension method:

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

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, IHostedService arabirimini uygulayan bir arka plan görevi mantığı içeren bir sınıftır.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 ana bilgisayarıkullanılırken, sunucu başlatıldıktan ve ıapplicationlifetime 'dan sonra StartAsync ç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, ApplicationStarted tetiklenene kadar StartAsync çağrılır.When using the Generic Host, StartAsync is called before ApplicationStarted is triggered.

  • StopAsync (CancellationToken) –, ana bilgisayar düzgün bir şekilde kapanma gerçekleştirirken tetiklenir.StopAsync(CancellationToken) – Triggered when the host is performing a graceful shutdown. StopAsync arka plan görevinin sonundaki mantığı içerir.StopAsync contains the logic to end the background task. Yönetilmeyen kaynakların atılmaya yönelik IDisposable ve sonlandırıcılar (Yıkıcılar) uygulayın.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.
    • StopAsync içinde çağrılan yöntemler hemen döndürmelidir.Any methods called in StopAsync should return promptly.

    Ancak,—istek iptal edildikten sonra, ç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 şekilde kapanıyorsa (örneğin, uygulamanın işlemi başarısız olursa) StopAsync çağrımayabilir.If the app shuts down unexpectedly (for example, the app's process fails), StopAsync might not be called. Bu nedenle, StopAsync veya içinde gerçekleştirilen işlemler tarafından çağrılan yöntemler 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şturulursa, StopAsync çağrılmasa bile Dispose ç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 yöntemini tetikler.The timer triggers the task's DoWork method. Zamanlayıcı StopAsync devre dışı bırakılır ve hizmet kapsayıcısı Disposebırakıldığında atıldı: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();
    }
}

Hizmet, AddHostedService uzantısı yöntemiyle Startup.ConfigureServices 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 IHostedServiceiçinde kullanmak için 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, hizmetine bir ILogger 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, DoWork yöntemini çağırmak için kapsamlı arka plan görev hizmetini çözümlemek üzere bir kapsam oluşturur: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 Startup.ConfigureServiceskaydedilir.The services are registered in Startup.ConfigureServices. IHostedService uygulama AddHostedService uzantısı 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 QueueBackgroundWorkItem temel alır (ASP.NET Core için kesin 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;
    }
}

QueueHostedService, kuyruktaki arka plan görevleri, uzun süre çalışan bir IHostedServiceuygulamak için temel bir sınıf olan bir BackgroundServiceolarak kuyruğa alınır ve yürütülür: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 Startup.ConfigureServiceskaydedilir.The services are registered in Startup.ConfigureServices. IHostedService uygulama AddHostedService uzantısı 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:

  • IBackgroundTaskQueue oluşturucuya eklenir ve Queueatanır.The IBackgroundTaskQueue is injected into the constructor and assigned to Queue.
  • IServiceScopeFactory eklenen ve _serviceScopeFactoryatanmış.An IServiceScopeFactory is injected and assigned to _serviceScopeFactory. Fabrika, bir kapsam içinde hizmet oluşturmak için kullanılan IServiceScopeö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. Bir kapsam, veritabanı kayıtlarını IBackgroundTaskQueue (bir tek hizmet) yazmak için uygulamanın AppDbContext ( kapsamlı bir hizmet) kullanmak üzere oluşturulur.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öntemi yürütülür.When the Add Task button is selected on the Index page, the OnPostAddTask method is executed. QueueBackgroundWorkItem bir 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