عنوان:

‫مدیریت چرخه‌ی حیات پردازش‌های پس‌زمینه در Blazor WebAssembly با معرفی IHostedService در دات‌نت 11


نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۳/۳۱ ۰۹:۲۵
آدرس: www.dntips.ir
تا پیش از انتشار دات‌نت 11، توسعه‌دهندگانی که از دات‌نت برای ساخت برنامه‌های سمت کلاینت در بستر مرورگر (Blazor WebAssembly) استفاده می‌کردند، برای اجرای عملیات‌های دوره‌ای یا پس‌زمینه (مانند بروزرسانی خودکار داده‌ها یا برقراری اتصالات هم‌زمان) با چالش‌هایی روبرو بودند. پیاده‌سازی این قابلیت‌ها معمولاً نیازمند ترفندهای جانبی، استفاده از کدهای جاوااسکریپت (JS Interop) یا مدیریت دستی چرخه‌ی حیات کامپوننت‌ها بود.
این در حالی بود که در Blazor Server یا برنامه‌های تحت وب ASP.NET Core، قابلیت استاندارد و قدرتمندی به نام IHostedService وجود داشت که مدیریت این‌گونه پردازش‌ها را به عهده می‌گرفت. مایکروسافت در دات‌نت 11 با معرفی پشتیبانی از IHostedService در Blazor WebAssembly، این شکاف ساختاری را برطرف کرده و به یکپارچگی و برابری قابلیت‌ها (Feature Parity) در کل اکوسیستم Blazor دست یافته است.

بررسی فنی و نحوه کارکرد IHostedService در مرورگر
این قابلیت جدید به شما اجازه می‌دهد تا اینترفیس آشنای IHostedService را پیاده‌سازی کرده و سرویس خود را در کانتینر تزریق وابستگی‌ها (DI Container) کلاینت ثبت کنید. این سرویس به محض لود شدن و استارت برنامه در مرورگر، متد StartAsync خود را اجرا می‌کند و تا زمان باز بودن یا بسته شدن برنامه (Shut down)، به کار خود ادامه می‌دهد.

نمونه پیاده‌سازی یک سرویس دوره‌ای (Periodic Service)
برای درک بهتر، یک سرویس ساده برای بروزرسانی زمان‌بندی‌شده‌ی داده‌ها را بررسی می‌کنیم:
using Microsoft.Extensions.Hosting;
using System;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace BlazorWasmBackgroundService.Services;

public class DataRefreshService : IHostedService
{
    private Timer? _timer;

    // این متد به محض راه‌اندازی برنامه در مرورگر فراخوانی می‌شود
    public Task StartAsync(CancellationToken cancellationToken)
    {
        // تنظیم یک تایمر برای اجرای متد RefreshData هر 5 دقیقه یک‌بار
        _timer = new Timer(RefreshData, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
        return Task.CompletedTask;
    }

    private void RefreshData(object? state)
    {
        // عملیات دریافت داده‌های جدید از API و بروزرسانی وضعیت برنامه
        Console.WriteLine($"[DataRefreshService] داده‌ها در زمان {DateTime.Now} بروزرسانی شدند.");
    }

    // این متد هنگام بسته شدن یا از بین رفتن اپلیکیشن اجرا می‌شود
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Dispose();
        return Task.CompletedTask;
    }
}

نحوه ثبت سرویس در Program.cs
ثبت این سرویس در Blazor WebAssembly کاملاً مشابه برنامه‌های سمت سرور دات‌نت است و پیچیدگی جدیدی ندارد:
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using BlazorWasmBackgroundService.Services;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

// ثبت سرویس پس‌زمینه در کانتینر خدمات برنامه
builder.Services.AddHostedService<DataRefreshService>();

await builder.Build().RunAsync();

نکات کلیدی برای توسعه‌دهندگان
برای بهره‌برداری اصولی از این قابلیت در محیط کلاینت، درک چند نکته حیاتی است:

محدودیت تک‌نخی (Single-thread Restriction):
  • محیط اجرای WebAssembly در مرورگرها به صورت پیش‌فرض تک‌نخی است (روی همان نخ اصلی UI جاوااسکریپت اجرا می‌شود). بنابراین، متدهای شما در IHostedService نباید عملیات‌های سنگین محاسباتی یا پردازش‌های مسدودکننده (Blocking) انجام دهند؛ چرا که باعث قفل شدن و کندی رابط کاربری (UI Freezing) می‌شوند. برای کارهای سنگین محاسباتی، همچنان باید به سراغ تکنولوژی‌هایی مانند Web Workers رفت.

مدیریت وضعیت (State Management) و ارتباط با کامپوننت‌ها:
  • سرویسی که به صورت HostedService ثبت می‌شود، معمولاً داده‌ها را در یک سرویس Singleton دیگر (مثلاً یک State Container) بروزرسانی می‌کند. کامپوننت‌های Blazor می‌توانند به آن سرویس Singleton متصل شده و با گوش دادن به یک رویداد (Event)، پس از هر بار بروزرسانی داده‌ها توسط سرویس پس‌زمینه، متد StateHasChanged خود را صدا بزنند تا UI تازه شود.

کاربرد در سناریوهای واقعی:
  • همگام‌سازی با SignalR: باز نگه داشتن و مدیریت کانال ارتباطی واقعی (Real-time) با سرور در طول حیات برنامه.
  • حافظه پنهان (Caching): پاک‌سازی متناوب داده‌های منقضی شده از حافظه موقت کلاینت.
  • ارسال سیگنال‌های پایش (Heartbeat): اعلام زنده بودن و فعال بودن تب مرورگر کاربر به سرور.

نتیجه‌گیری
پشتیبانی از IHostedService در Blazor WebAssembly دات‌نت 11، ابزاری استاندارد، تمیز و مبتنی بر چرخه‌ی حیات (Lifecycle-aware) را در اختیار توسعه‌دهندگان فرانت‌اند قرار می‌دهد. این ویژگی نیاز به راه‌حل‌های غیر استاندارد را از بین برده و ساختار کدنویسی کلاینت و سرور را بیش از پیش به یکدیگر نزدیک می‌کند. با رعایت اصل عدم مسدودسازی نخ اصلی مرورگر، این قابلیت کنترل فوق‌العاده‌ای روی فرآیندهای دوره‌ای و پس‌زمینه در برنامه‌های مدرن WebAssembly فراهم می‌سازد.