Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Tarafından Jeow Li Huan
Note
Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.
Warning
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.
ASP.NET Core'da, arka plan görevleri barındırılan servisler olarak uygulanabilir. Barındırılan hizmet, IHostedService arabirimini uygulayan arka plan görev mantığına sahip bir sınıftır. Barındırılan hizmetler Worker Service uygulamalarında ve web uygulamalarında kullanılabilir. Bu makalede üç barındırılan hizmet örneği verilmiştir:
- Zamanlayıcı üzerinde çalışan arka plan görevi.
- Barındırılmış hizmet, kapsamlı bir hizmeti etkinleştirir. Kapsamı belirlenmiş hizmet bağımlılık ekleme (DI) kullanabilir.
- Kuyruğa alınmış, sıralı olarak çalışan arka plan görevleri.
Çalışan Hizmeti şablonu
ASP.NET Temel Çalışan Hizmeti şablonu, uzun süre çalışan hizmet uygulamaları yazmak için bir başlangıç noktası sağlar. Çalışan Hizmeti şablonundan oluşturulan bir uygulama, proje dosyasında Çalışan SDK'sını belirtir:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Şablonu barındırılan hizmetler uygulamasının temeli olarak kullanmak için:
- Yeni bir proje oluşturma.
- Çalışan Hizmeti'ne tıklayın. sonrakiseçin.
- Proje adı alanına bir proje adı girin veya varsayılan proje adını kabul edin. sonrakiseçin.
- Ek bilgi iletişim kutusunda Çerçeve Seçin. Oluştur'i seçin.
Package
Çalışan Hizmeti şablonunu temel alan bir uygulama, Microsoft.NET.Sdk.Worker SDK'sını kullanır ve Microsoft.Extensions.Hosting NuGet paketine açık bir paket başvurusuna sahiptir. Örneğin, Worker Service örnek uygulamasının proje dosyasına (BackgroundTasksSample.csproj) bakın.
SDK kullanan web uygulamaları için, Microsoft.Extensions.Hosting NuGet paketi paylaşılan çerçeveden örtük olarak başvurulur. Uygulamanın proje dosyasında açık bir paket başvurusu gerekli değildir.
Web uygulamasında barındırılan hizmetler
Barındırılan hizmetler Çalışan Hizmeti uygulamalarıyla sınırlı değildir.
Microsoft.NET.Sdk.Web SDK kullanan bir web uygulaması, barındırılan hizmetleri WebApplicationBuilder.Services dosyasında, Program üzerinde aynı AddHostedService uzantı yöntemini çağırarak kaydeder. Ana bilgisayar, IHostedServiceIHostedService arabirimi bölümünde açıklandığı gibi kayıtlı barındırılan hizmetleri otomatik olarak başlatır ve durdurur.
Aşağıdaki Program dosya web örnek uygulamasındandır (BackgroundTasksWebSample). Bu makalenin geri kalanında açıklanan üç barındırılan hizmeti kaydeder, durum iletisi döndüren bir kök uç noktayı eşler ve bunlardan biri için iş öğesini kuyruğa alan bir uç nokta ekler:
using BackgroundTasksWebSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHostedService<TimedHostedService>();
builder.Services.AddHostedService<ConsumeScopedServiceHostedService>();
builder.Services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
builder.Services.AddHostedService<QueuedHostedService>();
builder.Services.AddSingleton<IBackgroundTaskQueue>(_ =>
new BackgroundTaskQueue(builder.Configuration.GetValue("QueueCapacity", 100)));
var app = builder.Build();
app.MapGet("/", () => "Hosted service is running in the background.");
app.MapPost("/queue", async (
IBackgroundTaskQueue taskQueue,
ILogger<Program> logger,
CancellationToken cancellationToken) =>
{
await taskQueue.QueueBackgroundWorkItemAsync(async token =>
{
var guid = Guid.NewGuid();
logger.LogInformation("Queued Background Task {Guid} is starting.", guid);
try
{
await Task.Delay(TimeSpan.FromSeconds(5), token);
}
catch (OperationCanceledException)
{
logger.LogInformation("Queued Background Task {Guid} was cancelled.", guid);
return;
}
logger.LogInformation("Queued Background Task {Guid} is complete.", guid);
}, cancellationToken);
return Results.Accepted();
});
app.Run();
Önceki kodda:
-
TimedHostedService,ConsumeScopedServiceHostedServiceveQueuedHostedService, AddHostedService uzantı yöntemiyle kaydedilir. - Barındırılan bir hizmet tekil olarak kaydedilir, bu nedenle yapıcı enjeksiyonu yoluyla Entity Framework Core gibi
DbContextalamaz.IScopedProcessingServicekapsamlı hizmet olarak kaydedilir veConsumeScopedServiceHostedServicebunu çözmek için bir kapsam oluşturur. Daha fazla bilgi için Arka plan görevinde kapsamlı yaşam süreli hizmet kullanma bölümüne bakın. -
IBackgroundTaskQueuesingleton'ı,QueuedHostedServiceuç noktası ve/queuekullanır.202 Acceptedadresine yapılan birPOSTisteği, iş öğesi yürütülmeyi beklemeden kuyruğa alındıktan sonra/queueyanıtı döndürür. Sınırlanmış kuyruk doluysa, istek iş öğesini kuyruğa eklemek için kuyrukta yer açılana kadar bekler.QueuedHostedServicekuyruğa alınan iş öğelerini arka planda çalıştırır. Daha fazla bilgi için Kuyruğa alınan arka plan görevleri bölümüne bakın.
Aşağıdaki hizmet kaydı parçacıkları, Çalışan Hizmeti örnek uygulamasından (BackgroundTasksSample) alınmıştır; burada services, IServiceCollection öğesine geçirilen ConfigureServices parametresidir. Web uygulamasında builder.Services yerine services kullanın.
IHostedService arabirimi
Arayüz, IHostedService konak tarafından yönetilen nesneler için iki metot tanımlar:
StartAsync
StartAsync(CancellationToken), arka plan görevini başlatma mantığını içerir.
StartAsyncdaha önce çağrılır:
- Uygulamanın istek işleme işlem hattı yapılandırılır.
- Sunucu başlatılır ve IApplicationLifetime.ApplicationStarted tetiklendi .
StartAsync barındırılan hizmetler sıralı olarak çalıştırıldığından ve tamamlanmaya kadar StartAsync başka hizmet başlatılmadığından, kısa süre çalışan görevlerle sınırlı olmalıdır.
Barındırılan hizmet örnekleri, uygulama ServicesStartConcurrently değerini true olarak ayarlayarak eşzamanlı başlatmayı etkinleştirmediği sürece, bağımlılık enjeksiyonu kapsayıcısına kaydedildikleri sırayla başlatılır:
builder.Services.Configure<HostOptions>(options =>
{
options.ServicesStartConcurrently = true;
});
StopAsync
-
Ana bilgisayar düzgün bir kapatma gerçekleştirdiğinde StopAsync(CancellationToken) tetiklenir.
StopAsyncarka plan görevini sonlandırma mantığını içerir. IDisposableYönetilmeyen kaynakları atmak için sonlandırıcılar (yıkıcılar) uygulayın.
İptal belirteci, kapatma işleminin daha fazla düzenli bir şekilde yapılmaması gerektiğini göstermek için varsayılan olarak 30 saniyelik bir zaman aşımına sahiptir. Belirteçte iptal istendiğinde:
- Uygulamanın gerçekleştirdiği kalan arka plan işlemleri durdurulmalıdır.
- içinde
StopAsyncçağrılan tüm yöntemler hemen döndürülmelidir.
Ancak iptal istendikten sonra görevler terk edilmez; çağıran tüm görevlerin tamamlanmasını bekler.
Uygulama beklenmedik bir şekilde kapanırsa (örneğin, uygulamanın işlemi başarısız olursa) StopAsync çağrılmayabilir. Bu nedenle, StopAsync içinde çağrılan herhangi bir yöntem veya gerçekleştirilen işlemler gerçekleşmeyebilir.
Varsayılan 30 saniyelik kapatma zaman aşımını genişletmek için şunu ayarlayın:
- ShutdownTimeout Genel Ana Bilgisayar kullanılırken. Daha fazla bilgi için, bkz. ASP.NET Core'da .NET Genel Ana Bilgisayarı.
- Web Host kullanılırken kapatma zaman aşımı ayarları ana bilgisayar yapılandırmasında. Daha fazla bilgi için bkz . ASP.NET Core Web Host.
Barındırılan hizmet, uygulama başlangıcında bir kez etkinleştirilir ve uygulama kapatıldığında düzgün bir şekilde kapatılır. Arka plan görevi yürütme sırasında hata oluşursa, Dispose çağrılmasa StopAsync bile çağrılmalıdır.
Barındırılan hizmet örnekleri, uygulama ServicesStopConcurrently değerini true olarak ayarlayarak eşzamanlı kapatma davranışını etkinleştirmeyi seçmediği sürece, bağımlılık enjeksiyonu kapsayıcısına kaydolduklarının ters sırasında durdurulur:
builder.Services.Configure<HostOptions>(options =>
{
options.ServicesStopConcurrently = true;
});
BackgroundService temel sınıfı
BackgroundService, uzun süre çalışan bir IHostedService uygulaması için temel bir sınıftır.
Arka plan hizmetini çalıştırmak için iş parçacığı havuzunda ExecuteAsync(CancellationToken) çağrılır. Uygulama, arka plan hizmetinin tüm ömrünü temsil eden bir Task döndürür. StopAsync(CancellationToken) içindeki konak blokları tamamlanmasını bekliyorExecuteAsync.
Arka plan hizmetini çalıştırmak için ExecuteAsync(CancellationToken) çağrılır. Uygulama, arka plan hizmetinin tüm ömrünü temsil eden bir Task döndürür. Başka hizmet başlatılmaz, örneğin çağrısı yapılana kadar await gibi. içinde ExecuteAsyncuzun, başlatmayı engelleyen bir çalışma gerçekleştirmekten kaçının. StopAsync(CancellationToken) içindeki konak blokları tamamlanmasını bekliyorExecuteAsync.
IHostedService.StopAsync çağrıldığında iptal belirteci tetikleniyor. Sizin ExecuteAsync uygulamanız, hizmeti düzgün bir şekilde kapatmak için iptal belirteci tetiklendiğinde hemen sona ermelidir. Aksi takdirde, hizmet kapatma zaman aşımında ani bir şekilde durdurulur. Daha fazla bilgi için IHostedService arabirimi bölümüne bakın.
Daha fazla bilgi için bkz . BackgroundService kaynak kodu.
Zamanlanmış arka plan görevleri
Zamanlanmış arka plan görevi System.Threading.Timer sınıfını kullanır. Zamanlayıcı, görevin DoWork yöntemini tetikler. Zamanlayıcı, StopAsync üzerinde devre dışı bırakılır ve hizmet kapsayıcısı Dispose üzerinde atıldığında kaldırılır.
public class TimedHostedService(ILogger<TimedHostedService> logger) : IHostedService, IDisposable
{
private int executionCount = 0;
private Timer? _timer = null;
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, DoWork'in önceki yürütmelerinin tamamlanmasını beklemez, bu nedenle gösterilen yaklaşım her senaryo için uygun olmayabilir.
Interlocked.Increment , birden çok iş parçacığının eşzamanlı olarak güncelleştirilmesini executionCount engelleyen bir atomik işlem olarak yürütme sayacını artırmak için kullanılır.
Hizmet, Program dosyasında AddHostedService uzantı yöntemiyle kaydedilir:
services.AddHostedService<TimedHostedService>();
Bir arka plan görevinde kapsamlandırılmış hizmet kullanma
Kapsamı belirlenmiş hizmetleri bir BackgroundService içinde kullanmak için bir kapsam oluşturun. Barındırılan bir hizmet için varsayılan olarak hiçbir kapsam oluşturulmaz.
Kapsamı belirlenmiş arka plan görev hizmeti, arka plan görevinin mantığını içerir. Aşağıdaki örnekte:
- Hizmet eşzamansızdır.
DoWorkyöntemi birTaskdöndürür. Demonstrasyon amacıylaDoWorkyönteminde on saniyelik bir gecikme beklenmektedir. - ILogger hizmetine eklenir.
internal interface IScopedProcessingService
{
Task DoWork(CancellationToken stoppingToken);
}
internal class ScopedProcessingService(
ILogger<ScopedProcessingService> logger) : IScopedProcessingService
{
private int executionCount = 0;
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ı bir arka plan görev hizmetini çözümlemek amacıyla bir kapsam oluşturur.
DoWorkiçinde beklenen Taskbir ExecuteAsyncdöndürür:
public class ConsumeScopedServiceHostedService(
IServiceProvider services,
ILogger<ConsumeScopedServiceHostedService> logger) : BackgroundService
{
public IServiceProvider Services { get; } = services;
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 base.StopAsync(stoppingToken);
}
}
Hizmetler Program dosyasında kayıtlıdır. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
Kuyruğa alınan arka plan görevleri
Arka plan görev kuyruğu .NET Framework 4.x'i QueueBackgroundWorkItemtemel alır:
public interface IBackgroundTaskQueue
{
ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken);
}
public class BackgroundTaskQueue(int capacity) : IBackgroundTaskQueue
{
// Capacity should be set based on the expected application load and
// number of concurrent threads accessing the queue.
// BoundedChannelFullMode.Wait causes calls to WriteAsync() to return a task,
// which only completes when space becomes available. In the event that many
// publishers/calls start accumulating, using BoundedChannelFullMode.Wait can
// lead to backpressure.
private readonly Channel<Func<CancellationToken, ValueTask>> _queue =
Channel.CreateBounded<Func<CancellationToken, ValueTask>>(new BoundedChannelOptions(capacity)
{
FullMode = BoundedChannelFullMode.Wait
});
public async ValueTask QueueBackgroundWorkItemAsync(
Func<CancellationToken, ValueTask> workItem)
{
if (workItem == null)
{
throw new ArgumentNullException(nameof(workItem));
}
await _queue.Writer.WriteAsync(workItem);
}
public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken)
{
var workItem = await _queue.Reader.ReadAsync(cancellationToken);
return workItem;
}
}
Aşağıdaki QueueHostedService örnekte:
-
BackgroundProcessingyöntemi,Taskiçinde beklenen birExecuteAsyncdöndürür. - Kuyruktaki arka plan görevleri
BackgroundProcessingiçinde kuyruktan çıkarılır ve yürütülür. - Hizmet durdurulmadan önce
StopAsynciş öğeleri beklenir.
public class QueuedHostedService(
IBackgroundTaskQueue taskQueue,
ILogger<QueuedHostedService> logger) : BackgroundService
{
public IBackgroundTaskQueue TaskQueue { get; } = taskQueue;
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 w tuşuna basıldığında barındırılan hizmet için sıralama görevlerini işler.
-
IBackgroundTaskQueue,MonitorLoophizmetine enjekte edilir. -
IBackgroundTaskQueue.QueueBackgroundWorkItembir iş öğesini sıralamak için çağrılır. - İş öğesi, uzun süre çalışan bir arka plan görevinin benzetimini gerçekleştirir:
- Üç adet 5 saniyelik gecikme yürütülür (
Task.Delay). - Bir
try-catchaçklamas; görevin iptal edilmesi durumunda OperationCanceledException durumu yakalar.
- Üç adet 5 saniyelik gecikme yürütülür (
public class MonitorLoop(
IBackgroundTaskQueue taskQueue,
ILogger<MonitorLoop> logger,
IHostApplicationLifetime applicationLifetime)
{
private readonly CancellationToken _cancellationToken = applicationLifetime.ApplicationStopping;
public void StartMonitorLoop()
{
logger.LogInformation("MonitorAsync Loop is starting.");
// Run a console user input loop in a background thread
Task.Run(async () => await MonitorAsync());
}
private async ValueTask MonitorAsync()
{
while (!_cancellationToken.IsCancellationRequested)
{
var keyStroke = Console.ReadKey();
if (keyStroke.Key == ConsoleKey.W)
{
// Enqueue a background work item
await taskQueue.QueueBackgroundWorkItemAsync(BuildWorkItem);
}
}
}
private async ValueTask BuildWorkItem(CancellationToken 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 Program dosyasına kaydedilir. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddSingleton<MonitorLoop>();
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue>(ctx =>
{
if (!int.TryParse(hostContext.Configuration["QueueCapacity"], out var queueCapacity))
queueCapacity = 100;
return new BackgroundTaskQueue(queueCapacity);
});
MonitorLoop, Program dosyasında başlatılır:
var monitorLoop = host.Services.GetRequiredService<MonitorLoop>();
monitorLoop.StartMonitorLoop();
Bir web uygulamasında uç nokta, konsol giriş döngüsü yerine iş öğelerini kuyruğa alabilir. Bir örnek için web uygulamasında barındırılan hizmetler bölümüne bakın.
Eşzamansız zamanlanmış arka plan görevi
Aşağıdaki kod zaman uyumsuz zamanlanmış bir arka plan görevi oluşturur:
namespace TimedBackgroundTasks;
public class TimedHostedService : BackgroundService
{
private readonly ILogger<TimedHostedService> _logger;
private int _executionCount;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service running.");
// When the timer should have no due-time, then do the work once now.
await DoWork();
using PeriodicTimer timer = new(TimeSpan.FromSeconds(30));
try
{
while (await timer.WaitForNextTickAsync(stoppingToken))
{
await DoWork();
}
}
catch (OperationCanceledException)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
}
}
private async Task DoWork()
{
int count = Interlocked.Increment(ref _executionCount);
// Simulate work
await Task.Delay(TimeSpan.FromSeconds(2));
_logger.LogInformation("Timed Hosted Service is working. Count: {Count}", count);
}
}
Yerleşik AOT
Çalışan Hizmeti şablonları,
- Yeni bir proje oluşturma.
- Çalışan Hizmeti'ne tıklayın. sonrakiseçin.
- Proje adı alanına bir proje adı girin veya varsayılan proje adını kabul edin. sonrakiseçin.
- Ek bilgi iletişim kutusunda:
- Bir Çerçeve seçin.
- Yerel AOT yayımlamayı etkinleştir onay kutusunu işaretleyin.
- Oluştur'i seçin.
AOT seçeneği proje dosyasına ekler <PublishAot>true</PublishAot> :
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
+ <PublishAot>true</PublishAot>
<UserSecretsId>dotnet-WorkerWithAot-e94b2</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0-preview.4.23259.5" />
</ItemGroup>
</Project>
Ek kaynaklar
ASP.NET Core'da, arka plan görevleri barındırılan servisler olarak uygulanabilir. Barındırılan hizmet, IHostedService arabirimini uygulayan arka plan görev mantığına sahip bir sınıftır. Bu makalede üç barındırılan hizmet örneği verilmiştir:
- Zamanlayıcı üzerinde çalışan arka plan görevi.
- Barındırılmış hizmet, kapsamlı bir hizmeti etkinleştirir. Kapsamı belirlenmiş hizmet bağımlılık ekleme (DI) kullanabilir.
- Kuyruğa alınmış, sıralı olarak çalışan arka plan görevleri.
Çalışan Hizmeti şablonu
ASP.NET Temel Çalışan Hizmeti şablonu, uzun süre çalışan hizmet uygulamaları yazmak için bir başlangıç noktası sağlar. Çalışan Hizmeti şablonundan oluşturulan bir uygulama, proje dosyasında Çalışan SDK'sını belirtir:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Şablonu barındırılan hizmetler uygulamasının temeli olarak kullanmak için:
- Yeni bir proje oluşturma.
- Çalışan Hizmeti'ne tıklayın. sonrakiseçin.
- Proje adı alanına bir proje adı girin veya varsayılan proje adını kabul edin. sonrakiseçin.
- Ek bilgi iletişim kutusunda Çerçeve Seçin. Oluştur'i seçin.
Package
Çalışan Hizmeti şablonunu temel alan bir uygulama SDK'yi Microsoft.NET.Sdk.Worker kullanır ve Microsoft.Extensions.Hosting paketine açık bir paket başvurusuna sahiptir. Örneğin, örnek uygulamanın proje dosyasına (BackgroundTasksSample.csproj ) bakın.
SDK kullanan web uygulamaları için Microsoft.NET.Sdk.Web Microsoft.Extensions.Hosting paketine paylaşılan çerçeveden örtük olarak başvurulur. Uygulamanın proje dosyasında açık bir paket başvurusu gerekli değildir.
IHostedService arabirimi
Arayüz, IHostedService konak tarafından yönetilen nesneler için iki metot tanımlar:
StartAsync
StartAsync(CancellationToken), arka plan görevini başlatma mantığını içerir.
StartAsyncdaha önce çağrılır:
- Uygulamanın istek işleme işlem hattı yapılandırılır.
- Sunucu başlatılır ve IApplicationLifetime.ApplicationStarted tetiklendi .
StartAsync barındırılan hizmetler sıralı olarak çalıştırıldığından ve tamamlanmaya kadar StartAsync başka hizmet başlatılmadığından, kısa süre çalışan görevlerle sınırlı olmalıdır.
StopAsync
-
Ana bilgisayar düzgün bir kapatma gerçekleştirdiğinde StopAsync(CancellationToken) tetiklenir.
StopAsyncarka plan görevini sonlandırma mantığını içerir. IDisposableYönetilmeyen kaynakları atmak için sonlandırıcılar (yıkıcılar) uygulayın.
İptal belirteci, kapatma işleminin daha fazla düzenli bir şekilde yapılmaması gerektiğini göstermek için varsayılan olarak 30 saniyelik bir zaman aşımına sahiptir. Belirteçte iptal istendiğinde:
- Uygulamanın gerçekleştirdiği kalan arka plan işlemleri durdurulmalıdır.
- içinde
StopAsyncçağrılan tüm yöntemler hemen döndürülmelidir.
Ancak iptal istendikten sonra görevler terk edilmez; çağıran tüm görevlerin tamamlanmasını bekler.
Uygulama beklenmedik bir şekilde kapanırsa (örneğin, uygulamanın işlemi başarısız olursa) StopAsync çağrılmayabilir. Bu nedenle, StopAsync içinde çağrılan herhangi bir yöntem veya gerçekleştirilen işlemler gerçekleşmeyebilir.
Varsayılan 30 saniyelik kapatma zaman aşımını genişletmek için şunu ayarlayın:
- ShutdownTimeout Genel Ana Bilgisayar kullanılırken. Daha fazla bilgi için, bkz. ASP.NET Core'da .NET Genel Ana Bilgisayarı.
- Web Host kullanılırken kapatma zaman aşımı ayarları ana bilgisayar yapılandırmasında. Daha fazla bilgi için bkz . ASP.NET Core Web Host.
Barındırılan hizmet, uygulama başlangıcında bir kez etkinleştirilir ve uygulama kapatıldığında düzgün bir şekilde kapatılır. Arka plan görevi yürütme sırasında hata oluşursa, Dispose çağrılmasa StopAsync bile çağrılmalıdır.
BackgroundService temel sınıfı
BackgroundService, uzun süre çalışan bir IHostedService uygulaması için temel bir sınıftır.
Arka plan hizmetini çalıştırmak için ExecuteAsync(CancellationToken) çağrılır. Uygulama, arka plan hizmetinin tüm ömrünü temsil eden bir Task döndürür. Başka hizmet başlatılmaz, örneğin çağrısı yapılana kadar await gibi. içinde ExecuteAsyncuzun, başlatmayı engelleyen bir çalışma gerçekleştirmekten kaçının. StopAsync(CancellationToken) içindeki konak blokları tamamlanmasını bekliyorExecuteAsync.
IHostedService.StopAsync çağrıldığında iptal belirteci tetikleniyor. Sizin ExecuteAsync uygulamanız, hizmeti düzgün bir şekilde kapatmak için iptal belirteci tetiklendiğinde hemen sona ermelidir. Aksi takdirde, hizmet kapatma zaman aşımında ani bir şekilde durdurulur. Daha fazla bilgi için IHostedService arabirimi bölümüne bakın.
Daha fazla bilgi için bkz . BackgroundService kaynak kodu.
Zamanlanmış arka plan görevleri
Zamanlanmış arka plan görevi System.Threading.Timer sınıfını kullanır. Zamanlayıcı, görevin DoWork yöntemini tetikler. Zamanlayıcı, StopAsync üzerinde devre dışı bırakılır ve hizmet kapsayıcısı Dispose üzerinde atıldığında kaldırılır.
public class TimedHostedService : IHostedService, IDisposable
{
private int executionCount = 0;
private readonly ILogger<TimedHostedService> _logger;
private Timer? _timer = null;
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, DoWork'in önceki yürütmelerinin tamamlanmasını beklemez, bu nedenle gösterilen yaklaşım her senaryo için uygun olmayabilir.
Interlocked.Increment , birden çok iş parçacığının eşzamanlı olarak güncelleştirilmesini executionCount engelleyen bir atomik işlem olarak yürütme sayacını artırmak için kullanılır.
Hizmet, IHostBuilder.ConfigureServices (Program.cs) içindeki AddHostedService uzantı yöntemiyle kaydedilir.
services.AddHostedService<TimedHostedService>();
Bir arka plan görevinde kapsamlandırılmış hizmet kullanma
Kapsamı belirlenmiş hizmetleri bir BackgroundService içinde kullanmak için bir kapsam oluşturun. Barındırılan bir hizmet için varsayılan olarak hiçbir kapsam oluşturulmaz.
Kapsamı belirlenmiş arka plan görev hizmeti, arka plan görevinin mantığını içerir. Aşağıdaki örnekte:
- Hizmet eşzamansızdır.
DoWorkyöntemi birTaskdöndürür. Demonstrasyon amacıylaDoWorkyönteminde on saniyelik bir gecikme beklenmektedir. - ILogger hizmetine eklenir.
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ı bir arka plan görev hizmetini çözümlemek amacıyla bir kapsam oluşturur.
DoWorkiçinde beklenen Taskbir ExecuteAsyncdöndürür:
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 base.StopAsync(stoppingToken);
}
}
Hizmetler IHostBuilder.ConfigureServices (Program.cs) içinde kayıtlıdır. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
Kuyruğa alınan arka plan görevleri
Arka plan görev kuyruğu .NET Framework 4.x'i QueueBackgroundWorkItemtemel alır:
public interface IBackgroundTaskQueue
{
ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken);
}
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, ValueTask>> _queue;
public BackgroundTaskQueue(int capacity)
{
// Capacity should be set based on the expected application load and
// number of concurrent threads accessing the queue.
// BoundedChannelFullMode.Wait causes calls to WriteAsync() to return a task,
// which only completes when space becomes available. In the event that many
// publishers/calls start accumulating, using BoundedChannelFullMode.Wait can
// lead to backpressure.
var options = new BoundedChannelOptions(capacity)
{
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, ValueTask>>(options);
}
public async ValueTask QueueBackgroundWorkItemAsync(
Func<CancellationToken, ValueTask> workItem)
{
if (workItem == null)
{
throw new ArgumentNullException(nameof(workItem));
}
await _queue.Writer.WriteAsync(workItem);
}
public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken)
{
var workItem = await _queue.Reader.ReadAsync(cancellationToken);
return workItem;
}
}
Aşağıdaki QueueHostedService örnekte:
-
BackgroundProcessingyöntemi,Taskiçinde beklenen birExecuteAsyncdöndürür. - Kuyruktaki arka plan görevleri
BackgroundProcessingiçinde kuyruktan çıkarılır ve yürütülür. - Hizmet durdurulmadan önce
StopAsynciş öğeleri beklenir.
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 w tuşuna basıldığında barındırılan hizmet için sıralama görevlerini işler.
-
IBackgroundTaskQueue,MonitorLoophizmetine enjekte edilir. -
IBackgroundTaskQueue.QueueBackgroundWorkItembir iş öğesini sıralamak için çağrılır. - İş öğesi, uzun süre çalışan bir arka plan görevinin benzetimini gerçekleştirir:
- Üç adet 5 saniyelik gecikme yürütülür (
Task.Delay). - Bir
try-catchaçklamas; görevin iptal edilmesi durumunda OperationCanceledException durumu yakalar.
- Üç adet 5 saniyelik gecikme yürütülür (
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("MonitorAsync Loop is starting.");
// Run a console user input loop in a background thread
Task.Run(async () => await MonitorAsync());
}
private async ValueTask MonitorAsync()
{
while (!_cancellationToken.IsCancellationRequested)
{
var keyStroke = Console.ReadKey();
if (keyStroke.Key == ConsoleKey.W)
{
// Enqueue a background work item
await _taskQueue.QueueBackgroundWorkItemAsync(BuildWorkItem);
}
}
}
private async ValueTask BuildWorkItem(CancellationToken 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 (Program.cs) içinde kayıtlıdır. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddSingleton<MonitorLoop>();
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue>(ctx =>
{
if (!int.TryParse(hostContext.Configuration["QueueCapacity"], out var queueCapacity))
queueCapacity = 100;
return new BackgroundTaskQueue(queueCapacity);
});
MonitorLoop, Program.cs'de başlatılır.
var monitorLoop = host.Services.GetRequiredService<MonitorLoop>();
monitorLoop.StartMonitorLoop();
Eşzamansız zamanlanmış arka plan görevi
Aşağıdaki kod zaman uyumsuz zamanlanmış bir arka plan görevi oluşturur:
namespace TimedBackgroundTasks;
public class TimedHostedService : BackgroundService
{
private readonly ILogger<TimedHostedService> _logger;
private int _executionCount;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service running.");
// When the timer should have no due-time, then do the work once now.
await DoWork();
using PeriodicTimer timer = new(TimeSpan.FromSeconds(30));
try
{
while (await timer.WaitForNextTickAsync(stoppingToken))
{
await DoWork();
}
}
catch (OperationCanceledException)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
}
}
private async Task DoWork()
{
int count = Interlocked.Increment(ref _executionCount);
// Simulate work
await Task.Delay(TimeSpan.FromSeconds(2));
_logger.LogInformation("Timed Hosted Service is working. Count: {Count}", count);
}
}
Ek kaynaklar
ASP.NET Core'da, arka plan görevleri barındırılan servisler olarak uygulanabilir. Barındırılan hizmet, IHostedService arabirimini uygulayan arka plan görev mantığına sahip bir sınıftır. Bu makalede üç barındırılan hizmet örneği verilmiştir:
- Zamanlayıcı üzerinde çalışan arka plan görevi.
- Barındırılmış hizmet, kapsamlı bir hizmeti etkinleştirir. Kapsamı belirlenmiş hizmet bağımlılık ekleme (DI) kullanabilir.
- Kuyruğa alınmış, sıralı olarak çalışan arka plan görevleri.
Örnek kodu görüntüleme veya indirme (indirme)
Çalışan Hizmeti şablonu
ASP.NET Temel Çalışan Hizmeti şablonu, uzun süre çalışan hizmet uygulamaları yazmak için bir başlangıç noktası sağlar. Çalışan Hizmeti şablonundan oluşturulan bir uygulama, proje dosyasında Çalışan SDK'sını belirtir:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Şablonu barındırılan hizmetler uygulamasının temeli olarak kullanmak için:
- Yeni bir proje oluşturma.
- Çalışan Hizmeti'ne tıklayın. sonrakiseçin.
- Proje adı alanına bir proje adı girin veya varsayılan proje adını kabul edin. Oluştur'i seçin.
- Yeni Çalışan hizmeti oluştur iletişim kutusunda Oluştur'u seçin.
Package
Çalışan Hizmeti şablonunu temel alan bir uygulama SDK'yi Microsoft.NET.Sdk.Worker kullanır ve Microsoft.Extensions.Hosting paketine açık bir paket başvurusuna sahiptir. Örneğin, örnek uygulamanın proje dosyasına (BackgroundTasksSample.csproj ) bakın.
SDK kullanan web uygulamaları için Microsoft.NET.Sdk.Web Microsoft.Extensions.Hosting paketine paylaşılan çerçeveden örtük olarak başvurulur. Uygulamanın proje dosyasında açık bir paket başvurusu gerekli değildir.
IHostedService arabirimi
Arayüz, IHostedService konak tarafından yönetilen nesneler için iki metot tanımlar:
StartAsync
StartAsync arka plan görevini başlatma mantığını içerir.
StartAsyncdaha önce çağrılır:
- Uygulamanın istek işleme işlem hattı yapılandırılır.
- Sunucu başlatılır ve IApplicationLifetime.ApplicationStarted tetiklendi .
Uygulamanın işlem hattı yapılandırıldıktan ve StartAsync çağrıldıktan sonra barındırılan hizmetin ApplicationStarted çalışması için varsayılan davranış değiştirilebilir. Varsayılan davranışı değiştirmek için çağrısı yaptıktan sonra VideosWatcherbarındırılan hizmeti (ConfigureWebHostDefaultsaşağıdaki örnekte) ekleyin:
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
-
Ana bilgisayar düzgün bir kapatma gerçekleştirdiğinde StopAsync(CancellationToken) tetiklenir.
StopAsyncarka plan görevini sonlandırma mantığını içerir. IDisposableYönetilmeyen kaynakları atmak için sonlandırıcılar (yıkıcılar) uygulayın.
İptal belirteci, kapatma işleminin artık sorunsuz bir şekilde yapılmaması gerektiğini belirtmek için varsayılan beş saniyelik bir zaman aşımına sahiptir. Belirteçte iptal istendiğinde:
- Uygulamanın gerçekleştirdiği kalan arka plan işlemleri durdurulmalıdır.
- içinde
StopAsyncçağrılan tüm yöntemler hemen döndürülmelidir.
Ancak iptal istendikten sonra görevler terk edilmez; çağıran tüm görevlerin tamamlanmasını bekler.
Uygulama beklenmedik bir şekilde kapanırsa (örneğin, uygulamanın işlemi başarısız olursa) StopAsync çağrılmayabilir. Bu nedenle, StopAsync içinde çağrılan herhangi bir yöntem veya gerçekleştirilen işlemler gerçekleşmeyebilir.
Varsayılan beş saniyelik kapatma zaman aşımını genişletmek için şunu ayarlayın:
- ShutdownTimeout Genel Ana Bilgisayar kullanılırken. Daha fazla bilgi için, bkz. ASP.NET Core'da .NET Genel Ana Bilgisayarı.
- Web Host kullanılırken kapatma zaman aşımı ayarları ana bilgisayar yapılandırmasında. Daha fazla bilgi için bkz . ASP.NET Core Web Host.
Barındırılan hizmet, uygulama başlangıcında bir kez etkinleştirilir ve uygulama kapatıldığında düzgün bir şekilde kapatılır. Arka plan görevi yürütme sırasında hata oluşursa, Dispose çağrılmasa StopAsync bile çağrılmalıdır.
BackgroundService temel sınıfı
BackgroundService, uzun süre çalışan bir IHostedService uygulaması için temel bir sınıftır.
Arka plan hizmetini çalıştırmak için ExecuteAsync(CancellationToken) çağrılır. Uygulama, arka plan hizmetinin tüm ömrünü temsil eden bir Task döndürür. Başka hizmet başlatılmaz, örneğin çağrısı yapılana kadar await gibi. içinde ExecuteAsyncuzun, başlatmayı engelleyen bir çalışma gerçekleştirmekten kaçının. StopAsync(CancellationToken) içindeki konak blokları tamamlanmasını bekliyorExecuteAsync.
IHostedService.StopAsync çağrıldığında iptal belirteci tetikleniyor. Sizin ExecuteAsync uygulamanız, hizmeti düzgün bir şekilde kapatmak için iptal belirteci tetiklendiğinde hemen sona ermelidir. Aksi takdirde, hizmet kapatma zaman aşımında ani bir şekilde durdurulur. Daha fazla bilgi için IHostedService arabirimi bölümüne bakın.
StartAsync barındırılan hizmetler sıralı olarak çalıştırıldığından ve tamamlanmaya kadar StartAsync başka hizmet başlatılmadığından, kısa süre çalışan görevlerle sınırlı olmalıdır. Uzun süre çalışan görevler ExecuteAsync içine yerleştirilmelidir. Daha fazla bilgi için BackgroundService kaynağına bakın.
Zamanlanmış arka plan görevleri
Zamanlanmış arka plan görevi System.Threading.Timer sınıfını kullanır. Zamanlayıcı, görevin DoWork yöntemini tetikler. Zamanlayıcı, StopAsync üzerinde devre dışı bırakılır ve hizmet kapsayıcısı Dispose üzerinde atıldığında kaldırılır.
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, DoWork'in önceki yürütmelerinin tamamlanmasını beklemez, bu nedenle gösterilen yaklaşım her senaryo için uygun olmayabilir.
Interlocked.Increment , birden çok iş parçacığının eşzamanlı olarak güncelleştirilmesini executionCount engelleyen bir atomik işlem olarak yürütme sayacını artırmak için kullanılır.
Hizmet, IHostBuilder.ConfigureServices (Program.cs) içindeki AddHostedService uzantı yöntemiyle kaydedilir.
services.AddHostedService<TimedHostedService>();
Bir arka plan görevinde kapsamlandırılmış hizmet kullanma
Kapsamı belirlenmiş hizmetleri bir BackgroundService içinde kullanmak için bir kapsam oluşturun. Barındırılan bir hizmet için varsayılan olarak hiçbir kapsam oluşturulmaz.
Kapsamı belirlenmiş arka plan görev hizmeti, arka plan görevinin mantığını içerir. Aşağıdaki örnekte:
- Hizmet eşzamansızdır.
DoWorkyöntemi birTaskdöndürür. Demonstrasyon amacıylaDoWorkyönteminde on saniyelik bir gecikme beklenmektedir. - ILogger hizmetine eklenir.
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ı bir arka plan görev hizmetini çözümlemek amacıyla bir kapsam oluşturur.
DoWorkiçinde beklenen Taskbir ExecuteAsyncdöndürür:
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 base.StopAsync(stoppingToken);
}
}
Hizmetler IHostBuilder.ConfigureServices (Program.cs) içinde kayıtlıdır. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
Kuyruğa alınan arka plan görevleri
Arka plan görev kuyruğu .NET Framework 4.x'i QueueBackgroundWorkItemtemel alır:
public interface IBackgroundTaskQueue
{
ValueTask QueueBackgroundWorkItemAsync(Func<CancellationToken, ValueTask> workItem);
ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken);
}
public class BackgroundTaskQueue : IBackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, ValueTask>> _queue;
public BackgroundTaskQueue(int capacity)
{
// Capacity should be set based on the expected application load and
// number of concurrent threads accessing the queue.
// BoundedChannelFullMode.Wait causes calls to WriteAsync() to return a task,
// which only completes when space becomes available. In the event that many
// publishers/calls start accumulating, using BoundedChannelFullMode.Wait can
// lead to backpressure.
var options = new BoundedChannelOptions(capacity)
{
FullMode = BoundedChannelFullMode.Wait
};
_queue = Channel.CreateBounded<Func<CancellationToken, ValueTask>>(options);
}
public async ValueTask QueueBackgroundWorkItemAsync(
Func<CancellationToken, ValueTask> workItem)
{
if (workItem == null)
{
throw new ArgumentNullException(nameof(workItem));
}
await _queue.Writer.WriteAsync(workItem);
}
public async ValueTask<Func<CancellationToken, ValueTask>> DequeueAsync(
CancellationToken cancellationToken)
{
var workItem = await _queue.Reader.ReadAsync(cancellationToken);
return workItem;
}
}
Aşağıdaki QueueHostedService örnekte:
-
BackgroundProcessingyöntemi,Taskiçinde beklenen birExecuteAsyncdöndürür. - Kuyruktaki arka plan görevleri
BackgroundProcessingiçinde kuyruktan çıkarılır ve yürütülür. - Hizmet durdurulmadan önce
StopAsynciş öğeleri beklenir.
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 w tuşuna basıldığında barındırılan hizmet için sıralama görevlerini işler.
-
IBackgroundTaskQueue,MonitorLoophizmetine enjekte edilir. -
IBackgroundTaskQueue.QueueBackgroundWorkItembir iş öğesini sıralamak için çağrılır. - İş öğesi, uzun süre çalışan bir arka plan görevinin benzetimini gerçekleştirir:
- Üç adet 5 saniyelik gecikme yürütülür (
Task.Delay). - Bir
try-catchaçklamas; görevin iptal edilmesi durumunda OperationCanceledException durumu yakalar.
- Üç adet 5 saniyelik gecikme yürütülür (
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("MonitorAsync Loop is starting.");
// Run a console user input loop in a background thread
Task.Run(async () => await MonitorAsync());
}
private async ValueTask MonitorAsync()
{
while (!_cancellationToken.IsCancellationRequested)
{
var keyStroke = Console.ReadKey();
if (keyStroke.Key == ConsoleKey.W)
{
// Enqueue a background work item
await _taskQueue.QueueBackgroundWorkItemAsync(BuildWorkItem);
}
}
}
private async ValueTask BuildWorkItem(CancellationToken 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 (Program.cs) içinde kayıtlıdır. Barındırılan hizmet, AddHostedService uzantı yöntemi kullanılarak kaydedilir.
services.AddSingleton<MonitorLoop>();
services.AddHostedService<QueuedHostedService>();
services.AddSingleton<IBackgroundTaskQueue>(ctx => {
if (!int.TryParse(hostContext.Configuration["QueueCapacity"], out var queueCapacity))
queueCapacity = 100;
return new BackgroundTaskQueue(queueCapacity);
});
MonitorLoop, Program.Main'de başlatılır.
var monitorLoop = host.Services.GetRequiredService<MonitorLoop>();
monitorLoop.StartMonitorLoop();
Ek kaynaklar
ASP.NET Core