ما هو .NET Generic Host - شرح DI والإعدادات والـ logging و BackgroundService

· · C#, .NET, Generic Host, Worker, التصميم

عندما تبدأ بكتابة تطبيق console أو worker في .NET، يمكنك في الغالب أن تكتفي بوضع منطق بسيط مباشرةً في Main.
لكن حالما يكبر التطبيق ولو قليلاً، تميل نفس الاحتياجات إلى الظهور.

  • تريد قراءة appsettings.json
  • تريد أن تتمكّن متغيّرات البيئة من تجاوز الإعدادات
  • تريد إخراج الـ logs عبر ILogger
  • لا تريد أن يتحوّل إنشاء الكائنات إلى جدار من new
  • تريد حلقة تعمل في الخلفيّة
  • تريد أن يُوقَف التطبيق بشكل نظيف عند Ctrl+C أو عند إيقاف الخدمة

هنا يدخل Generic Host إلى الصورة.
لكنّ الاسم نفسه أيضاً سهل أن يختلط قليلاً.

  • ما الفرق بين Host.CreateApplicationBuilder و Host.CreateDefaultBuilder؟
  • هل IHost هو نفسه DI container؟
  • كيف يرتبط بـ BackgroundService؟
  • هل هو منفصل عن WebApplicationBuilder في ASP.NET Core؟
  • هل يستحقّ الاستخدام في تطبيق console أصلاً؟

عندما تختلط هذه الأفكار، قد يبدو Generic Host وكأنّه «شيء لتطبيقات الويب فقط»، أو على النقيض «شيء يجب أن يُبنى عليه كلّ تطبيق دائماً». كلتا النظرتين خشنتان أكثر من اللازم.

يفترض هذا المقال الإحساس العمليّ في .NET 6 وما بعده كقاعدة، وينظّم هذه النقاط الأربع أوّلاً:

  • ما هو Generic Host فعلاً
  • ما الذي يجمعه ويديره من أجلك
  • كيف يرتبط Host.CreateApplicationBuilder و Host.CreateDefaultBuilder و WebApplication.CreateBuilder ببعضها
  • أين يكون أهدأ مكان للبدء

المحتويات

  1. الجواب القصير أوّلاً
  2. الجداول الأولى للنظر إليها
    • 2.1. ما الذي يحتويه Generic Host
    • 2.2. الفروق بين نقاط دخول الـ builder
  3. الصورة الإجماليّة لـ Generic Host
  4. ما الذي يحسّنه Generic Host
    • 4.1. يمركز توصيل بدء التشغيل
    • 4.2. DI والإعدادات والـ logging مرتبطة من البداية
    • 4.3. يتعامل مع الإيقاف النظيف والعمليّات طويلة الأمد بشكل أسهل
  5. الإعداد الأدنى
    • 5.1. مثال أدنى لتطبيق console
    • 5.2. appsettings.json
    • 5.3. إضافة BackgroundService
  6. الأنماط النموذجيّة
    • 6.1. أدوات console قصيرة العمر
    • 6.2. workers والخدمات في الخلفيّة
    • 6.3. يجلس أيضاً تحت ASP.NET Core
  7. الحالات التي يلائمها جيّداً
  8. الحالات التي يكون فيها غير ضروريّ أو مفرطاً
  9. الفخاخ الشائعة
  10. الخلاصة
  11. المراجع

1. الجواب القصير أوّلاً

  • Generic Host هو الأساس الذي يدير بدء التشغيل والـ lifetime لتطبيق .NET.
  • يشمل DI والإعدادات والـ logging و IHostedService / BackgroundService ومعالجة إيقاف التطبيق.
  • في التطبيقات الجديدة غير الويب، يكون Host.CreateApplicationBuilder(args) عادةً نقطة الدخول الأنظف.
  • WebApplicationBuilder في ASP.NET Core ليس عالماً منفصلاً. إنّه نقطة دخول موجَّهة للويب مبنيّة على نفس نموذج الاستضافة.
  • بعبارة أخرى، Generic Host ليس فقط حول DI container بمفرده. إنّه الآليّة التي تجمع تركيب التطبيق وإدارة الـ lifetime في مكان واحد.

القاعدة العمليّة هي أنّ Generic Host يبدأ بإعطاء عائد بمجرّد أن يكبر تطبيقك أكثر من «اقرأ الوسائط، اطبع مرّة، اخرج».
في الوقت نفسه، فهو ليس شيئاً يجب جرّه إلى كلّ أداة صغيرة.

2. الجداول الأولى للنظر إليها

2.1. ما الذي يحتويه Generic Host

يساعد كثيراً أن تفصل ما هو داخل الصندوق أوّلاً.

الجزء ما يديره Generic Host لماذا يفيد ذلك
DI يبني الخدمات من IServiceCollection يجعل تجنّب سلاسل new أسهل
Configuration يجمع appsettings.json ومتغيّرات البيئة ووسائط سطر الأوامر وغيرها يجعل اختلافات البيئات أسهل في الإدارة
Logging يهيّئ الأساس لـ ILogger<T> يجعل تغيير وجهات الـ logs لاحقاً أسهل
Hosted service يبدأ ويوقف IHostedService / BackgroundService يجعل فصل العمل طويل الأمد عن نقطة دخول التطبيق أسهل
Lifetime يتعامل مع بدء التشغيل والإيقاف عبر IHostApplicationLifetime و IHostEnvironment والتجريدات ذات الصلة يجعل توحيد طريقة انتهاء التطبيق عند Ctrl+C أو SIGTERM أو إيقاف الخدمة أسهل

النقطة المهمّة هنا هي أنّ Generic Host ليس مجرّد «غلاف DI مريح».
في الممارسة العمليّة، يُفهَم بشكل أفضل على أنّه الصندوق الذي يربط منطقة دخول التطبيق ببعضها.

2.2. الفروق بين نقاط دخول الـ builder

هذا أيضاً أسهل للرؤية في جدول واحد.

نقطة الدخول الاستخدام الرئيس أسلوب الكتابة الخيار الأوّل
Host.CreateApplicationBuilder(args) تطبيقات console / worker جديدة غير ويب الكتابة مباشرةً إلى builder.Services و builder.Configuration و builder.Logging استخدمه للتطبيقات الجديدة
Host.CreateDefaultBuilder(args) قواعد كود قائمة أو إعدادات قديمة كثيفة الاعتماد على extension methods يستخدم تكويناً مسلسلاً مثل ConfigureServices استخدمه عند مطابقة الكود القائم
WebApplication.CreateBuilder(args) تطبيقات / APIs ويب ASP.NET Core نقطة دخول موجَّهة للويب مبنيّة على Generic Host استخدمه لتطبيقات الويب

CreateApplicationBuilder و CreateDefaultBuilder ليسا «شيئاً جديداً مقابل شيء قديم منفصل».
كلاهما يرتكز على نفس قدرات الاستضافة الأساسيّة والقيم الافتراضيّة.

الفرق الأكبر هو بشكل رئيس أسلوب كود الإعداد.

لتطبيق جديد غير ويب، يكون Host.CreateApplicationBuilder(args) عادةً نقطة الدخول الأنظف اليوم.
أمّا WebApplication.CreateBuilder(args) فهو أسهل للفهم إذا اعتبرته نفس التدفّق، موسَّعاً لسيناريوهات الويب.

3. الصورة الإجماليّة لـ Generic Host

إذا رسمت الصورة كاملةً، فإنّها تبدو هكذا.

flowchart LR
    Args["args / environment variables / appsettings.json"] --> Builder["Host.CreateApplicationBuilder(args)"]
    Builder --> Config["builder.Configuration"]
    Builder --> Services["builder.Services"]
    Builder --> Logging["builder.Logging"]
    Services --> Hosted["IHostedService / BackgroundService"]
    Builder --> Build["builder.Build()"]
    Build --> Host["IHost"]
    Host --> Run["Run / RunAsync"]
    Run --> Lifetime["startup / shutdown / Ctrl+C / SIGTERM"]
    Lifetime --> Hosted

في التدفّق الشائع، تنشئ الـ builder في Program.cs، وتضيف الخدمات عبر builder.Services، وتضبط الإعدادات والـ logging حسب الحاجة، ثمّ تستدعي Build() للحصول على IHost، وأخيراً تشغّله عبر Run() أو RunAsync().

شيء مهمّ بصمت هو كم القدر المتضمَّن مسبقاً عند نقطة Host.CreateApplicationBuilder(args).
بشكل افتراضيّ، على سبيل المثال، تحصل بالفعل على:

  • المسار الحاليّ كـ content root
  • إعدادات الـ host من متغيّرات البيئة المسبوقة بـ DOTNET_ ووسائط سطر الأوامر
  • إعدادات التطبيق من appsettings.json و appsettings.{Environment}.json و user secrets في Development ومتغيّرات البيئة ووسائط سطر الأوامر
  • مزوّدي logging مثل Console و Debug و EventSource و EventLog على Windows
  • التحقّق من الـ scope والتحقّق من dependencies في Development

لذا فأنت لا تربط كلّ شيء يدويّاً من الصفر.
أنت تبدأ من أساس مكتمل إلى حدّ معقول للاستخدام العاديّ.

4. ما الذي يحسّنه Generic Host

4.1. يمركز توصيل بدء التشغيل

أحد أكبر الفوائد الهادئة هو أنّ نقطة دخول التطبيق تصبح أقلّ ميلاً للتشتّت.

حالما يكبر التطبيق قليلاً، يميل Main إلى جمع أشياء مثل:

  • تحميل ملفّات الإعدادات
  • التجاوزات الخاصّة بالبيئة
  • تهيئة الـ logger
  • توصيل HttpClient و repositories والخدمات
  • بدء العمليّات في الخلفيّة
  • التنظيف عند إشارات الإيقاف

إذا رُبط كلّ ذلك يدويّاً دون host، فإنّ نقطة الدخول كثيراً ما تصبح أكثر لزوجةً مع الوقت حتّى لو بدأت صغيرة.

مع Generic Host، يصبح Program.cs بشكل واضح «المكان الذي تُجمَع فيه الـ dependencies وتوصيل بدء التشغيل».
ذلك وحده غالباً ما يجعل مراجعة الكود أسهل بكثير.

4.2. DI والإعدادات والـ logging مرتبطة من البداية

مع Generic Host، تجلس DI والإعدادات والـ logging جميعاً على نفس الأساس منذ البداية.

يعني ذلك أنّ الـ classes تستطيع بشكل طبيعيّ أن تستقبل أشياء مثل:

  • ILogger<T>
  • IConfiguration
  • IHostEnvironment
  • IOptions<T>

العائد العمليّ هو أنّ الوصول إلى الإعدادات وبناء الخدمات أقلّ احتمالاً للانحراف نحو أساليب مختلفة.

إذا كنت تحتاج إلى قيمة أو قيمتين فقط، فقد تكون قراءة IConfiguration["Section:Key"] مباشرةً كافيةً.
لكن حالما تبدأ الإعدادات بالنموّ، يكون عادةً أهدأ ربطها في classes باستخدام IOptions<T>.

ينطبق الشيء نفسه على الـ logging. بدلاً من بناء ILoggerFactory يدويّاً في أماكن مختلفة، فإنّ حقن ILogger<T> في الـ classes التي تحتاج إليه يحافظ عادةً على شكل الكود أوضح.

تلك إحدى نقاط القوّة الحقيقيّة لـ Generic Host: فهو يتيح التعامل مع هذه الأشياء معاً كجزء من أساس التطبيق بدلاً من كونها اهتمامات غير مترابطة.

4.3. يتعامل مع الإيقاف النظيف والعمليّات طويلة الأمد بشكل أسهل

لا يساعد Generic Host فقط في كيفيّة بدء التطبيق. بل يساعد أيضاً في كيفيّة إيقافه.

عندما يبدأ الـ host، يُستدعى StartAsync لكلّ IHostedService مسجَّل.
في تطبيقات نمط worker، تعمل الخدمات المستضافة بما فيها BackgroundService عبر ExecuteAsync.

في هذا السياق، يعني «الإيقاف النظيف» عدم قتل العمليّة فوراً، بل بدلاً من ذلك:

  • إرسال إشارة الإيقاف
  • الخروج من الحلقات وحالات الانتظار
  • تنظيف الاتّصالات والموارد

ذلك مهمّ جدّاً في التطبيقات طويلة الأمد.
يصبح من الأسهل بكثير توحيد سلوك الإيقاف عبر أحداث Ctrl+C أو SIGTERM أو إيقاف الخدمة.

وعندما يريد التطبيق نفسه أن يطلب من الـ host التوقّف، يكون IHostApplicationLifetime.StopApplication() متاحاً.
يعطيك ذلك طريقة طبيعيّة على مستوى الـ host لتقول: «انتهى العمل، أوقف الآن بشكل نظيف».

5. الإعداد الأدنى

5.1. مثال أدنى لتطبيق console

نقطة مهمّة هي أنّ استخدام Generic Host لا يعني تلقائيّاً أنّك تحتاج إلى BackgroundService.

حتّى أداة console تعمل مرّة واحدة وتخرج يمكن أن تستفيد من Generic Host إن كانت تحتاج إلى DI أو إعدادات أو logging.

إن كنت تضيفه إلى مشروع console عاديّ، فإنّ الخطوة الأولى المعتادة هي الإشارة إلى Microsoft.Extensions.Hosting.

dotnet add package Microsoft.Extensions.Hosting

قد يبدو Program.cs الأدنى هكذا:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddSingleton<JobRunner>();

using IHost host = builder.Build();

try
{
    JobRunner runner = host.Services.GetRequiredService<JobRunner>();
    await runner.RunAsync();
    return 0;
}
catch (Exception ex)
{
    ILogger logger = host.Services
        .GetRequiredService<ILoggerFactory>()
        .CreateLogger("Program");

    logger.LogError(ex, "Unhandled exception occurred during job execution.");
    return 1;
}

internal sealed class JobRunner(
    ILogger<JobRunner> logger,
    IConfiguration configuration,
    IHostEnvironment hostEnvironment)
{
    public Task RunAsync()
    {
        string message = configuration["Sample:Message"] ?? "(no message)";

        logger.LogInformation("Environment: {EnvironmentName}", hostEnvironment.EnvironmentName);
        logger.LogInformation("Message: {Message}", message);

        return Task.CompletedTask;
    }
}

إن لم يكن التطبيق طويل الأمد، فلا تحتاج إلى الذهاب حتّى RunAsync().
يمكنك بناء الـ host وحلّ الخدمات اللازمة وأداء العمل والخروج.
لا يزال ذلك يمنحك الكثير من قيمة Generic Host.

من السهل إغفال هذا.
لا تحتاج إلى جرّ قالب الـ worker إلى كلّ مهمّة قصيرة العمر.

5.2. appsettings.json

للمثال أعلاه، يكون ملفّ إعدادات أدنى مثل هذا كافياً:

{
  "Sample": {
    "Message": "hello from Generic Host"
  }
}

هنا يقرأ الكود configuration["Sample:Message"] مباشرةً.
لقيمة أو قيمتين، هذا جيّد تماماً.

لكن حالما تكبر الإعدادات في نظام حقيقيّ، يكون عادةً من الأفضل التحرّك نحو:

  • classes منفصلة لكلّ section
  • حقن قائم على IOptions<T>
  • التحقّق عند بدء التشغيل

يجعل ذلك تجنّب نشر مفاتيح من نوع stringly-typed في كلّ مكان أسهل.

أيضاً، لأنّ الإعداد الافتراضيّ لـ Generic Host يشمل ليس فقط appsettings.json بل أيضاً appsettings.{Environment}.json ومتغيّرات البيئة ووسائط سطر الأوامر، يصبح من الطبيعيّ دعم أنماط مثل «التجاوز فقط في التطوير» أو «استبدال القيم عبر متغيّرات البيئة في الإنتاج».

5.3. إضافة BackgroundService

إن كان العمل طويل الأمد، فإنّ BackgroundService كثيراً ما يكون ملاءمة طبيعيّة جدّاً.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddScoped<PollingJob>();
builder.Services.AddHostedService<PollingWorker>();

using IHost host = builder.Build();
await host.RunAsync();

internal sealed class PollingWorker(
    IServiceScopeFactory scopeFactory,
    ILogger<PollingWorker> logger) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using PeriodicTimer timer = new(TimeSpan.FromSeconds(30));

        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            using IServiceScope scope = scopeFactory.CreateScope();
            PollingJob job = scope.ServiceProvider.GetRequiredService<PollingJob>();

            await job.RunAsync(stoppingToken);
            logger.LogInformation("Polling completed.");
        }
    }
}

internal sealed class PollingJob(ILogger<PollingJob> logger)
{
    public Task RunAsync(CancellationToken cancellationToken)
    {
        logger.LogInformation("Do work here.");
        return Task.CompletedTask;
    }
}

نقطتان جديرتان بالملاحظة بشكل خاصّ هنا:

  1. الجسم الرئيس لـ BackgroundService يعيش في ExecuteAsync
  2. إذا كنت تحتاج إلى dependencies من نوع scoped، فأنشئ scope عبر IServiceScopeFactory

BackgroundService بحدّ ذاته لا يأتي تلقائيّاً مع scope.
لذا إن أردت استخدام شيء scoped مثل DbContext، فإنّ حلّ المهمّة داخل scope منشأ كما في الأعلى هو الشكل الأكثر أماناً.

اختيار الـ timer نفسه موضوع منفصل، لكن عندما يكون التدفّق قائماً على async، يكون PeriodicTimer كثيراً ما خياراً هادئاً إلى حدّ معقول.
ذلك يرتبط أيضاً بشكل طبيعيّ بمقال الـ timer ذي الصلة.

6. الأنماط النموذجيّة

6.1. أدوات console قصيرة العمر

مهامّ الـ batch وأدوات التحويل أو أوامر الصيانة التي تعمل مرّة واحدة وتخرج يمكنها أن تستفيد من Generic Host.

تشمل الحالات النموذجيّة:

  • قراءة ملفّات الإعدادات
  • كتابة الـ logs
  • حقن HttpClient أو repositories
  • إعادة كود خروج

إذا أخذت ذلك النوع من التطبيقات ولفّفته فوراً في BackgroundService و RunAsync()، فقد ينتهي بك الأمر باستخدام إدارة lifetime الـ host بشكل أثقل ممّا يحتاجه المشكل فعلاً.

للمهامّ القصيرة العمر، يكون مجرّد حلّ JobRunner وتنفيذه، كما في المثال الأدنى، كافياً في الغالب.

6.2. workers والخدمات في الخلفيّة

للـ workers المقيمة والـ polling ومستهلكي الـ queue والمراقبة والمعالجة المجدولة، يكون اقتران Generic Host و BackgroundService عادةً طبيعيّاً جدّاً.

تشمل الفوائد العمليّة:

  • توحيد سلوك بدء التشغيل والإيقاف عبر الـ host
  • توفّر الـ logging والإعدادات و DI من البداية
  • أن يصبح تدفّق الإلغاء من Ctrl+C أو إشارات الإيقاف أسهل
  • جعل العمل طويل الأمد أسهل للفصل عن Program.cs

كما يرتبط بشكل طبيعيّ بسياقات مثل Windows Services والـ containers.
إن كان من المرجّح أن يكبر التطبيق ليصبح خدمة مقيمة، فإنّ Generic Host هو أساس طبيعيّ جدّاً.

في سيناريوهات Windows Service بشكل خاصّ، يكون عادةً أكثر أماناً اعتماد البحث عن الملفّات على IHostEnvironment.ContentRootPath بدلاً من المسار الحاليّ.
يعطيك الـ host فكرة واضحة عن المسار الأساس للتطبيق.

6.3. يجلس أيضاً تحت ASP.NET Core

تستخدم تطبيقات الويب والـ APIs WebApplication.CreateBuilder(args)، لذا قد تبدو للوهلة الأولى عالماً منفصلاً عن Generic Host.

لكن في الممارسة العمليّة، الأفكار مرتبطة بقوّة.

  • builder.Services
  • builder.Configuration
  • builder.Logging

تشعر بأنّها متشابهة لسبب.

في ASP.NET Core، يعيش خادم HTTP أيضاً داخل إدارة lifetime الـ host.
لذا فإنّ فهم Generic Host يساعد في فهم لماذا يُكوَّن DI والإعدادات والـ logging جميعاً في Program.cs للويب أيضاً.

7. الحالات التي يلائمها جيّداً

يميل Generic Host إلى الملاءمة بشكل طبيعيّ في حالات مثل هذه:

  • تطبيقات console التي تستخدم الإعدادات والـ logging و DI
  • مستهلكي الـ queue والـ pollers والـ watchdogs والـ workers الشبيهة بالـ scheduler
  • التطبيقات طويلة الأمد التي تحتاج إلى تنظيف graceful عند Ctrl+C أو SIGTERM
  • التطبيقات التي قد تكبر لاحقاً لتصبح Windows Services أو عمليّات مقيمة في containers
  • التطبيقات التي تريد فيها نفس الأسلوب القائم على extensions كما في ASP.NET Core

ما تشترك فيه هذه الحالات هو الرغبة في منع نقطة دخول التطبيق وإدارة الـ lifetime من أن تصبح فوضويّة.

8. الحالات التي يكون فيها غير ضروريّ أو مفرطاً

هناك أيضاً حالات لا يحتاج فيها Generic Host لأن يكون الأداة الرئيسة من البداية.

  • أدوات صغيرة جدّاً تقرأ الوسائط مرّة وتطبع مرّة وتخرج
  • كود تجريبيّ خشن يُستخدم لفترة قصيرة فقط
  • مشاريع المكتبات
  • الحالات التي تحتاج فيها إلى إعداد واحد فقط ولا تحتاج فعلاً إلى DI أو logging أو إدارة lifetime

في تلك الحالات، يكون التنفيذ الأبسط في الغالب أهدأ من إقامة host.

النقطة المهمّة هي أنّ مجرّد كون Generic Host قويّاً لا يعني أنّ كلّ executable يجب أن يستخدمه.

9. الفخاخ الشائعة

فيما يلي بعض الأخطاء السهلة في البداية:

  • التفكير في أنّ Generic Host هو فقط DI container
    • في الواقع هو الأساس الذي يشمل بدء التشغيل والإيقاف والإعدادات والـ logging والخدمات المستضافة.
  • بدء تطبيق جديد بـ Host.CreateDefaultBuilder بحكم العادة
    • ما لم تكن تطابق قاعدة كود قائمة، يكون Host.CreateApplicationBuilder عادةً نقطة البداية الأنظف.
  • حقن خدمات scoped مباشرةً في BackgroundService
    • الخدمات المستضافة ليس لديها scope افتراضيّ. إنشاء واحد عبر IServiceScopeFactory هو المسار الأكثر أماناً.
  • بناء worker ذي تشغيل واحد دون إخبار الـ host بالتوقّف
    • إن استخدمت قالب worker لتطبيق «يعمل مرّة»، فأنت تحتاج إلى IHostApplicationLifetime.StopApplication() عند انتهاء العمل، وإلّا يستمرّ الـ host بالعمل.
  • استخدام Environment.Exit عندما تريد فعلاً إيقافاً نظيفاً
    • إن كنت تستخدم الـ host بالفعل، فإنّ StopApplication() هو عادةً الطريقة الأنظف للتوقّف.
  • افتراض المسار الحاليّ في Windows Service
    • يكون البحث عن الملفّات أكثر استقراراً عادةً عند الاعتماد على IHostEnvironment.ContentRootPath.
  • لفّ CLI قصير العمر في BackgroundService من البداية
    • إن كان العمل يعمل مرّة واحدة، فإنّ حلّ class خدمة عاديّ وتنفيذه كافٍ في الغالب.
  • استخدام callback timers باستخفاف داخل BackgroundService
    • إن كان التدفّق قائماً على async، فإنّ PeriodicTimer يؤدّي عادةً إلى كود أسهل للقراءة وأقلّ احتمالاً للانحراف.

مع Generic Host، فإنّ مجرّد فصل «مهمّة قصيرة العمر» مقابل «مهمّة مقيمة» مبكّراً يزيل بالفعل الكثير من الالتباس.

10. الخلاصة

إذا وضعتها في جملة واحدة، فإنّ Generic Host هو الأساس الذي يجمع نقطة دخول تطبيق .NET وإدارة الـ lifetime.

النقاط الرئيسة التي تستحقّ التذكّر هي:

  1. يشمل Generic Host ليس فقط DI بل أيضاً الإعدادات والـ logging ومعالجة الإيقاف والخدمات المستضافة
  2. للتطبيقات الجديدة غير الويب، يكون Host.CreateApplicationBuilder(args) عادةً نقطة البداية الأنظف
  3. للمهامّ القصيرة العمر، لا بأس ببناء الـ host وتنفيذ خدمة مباشرةً دون BackgroundService
  4. للمعالجة المقيمة، يصبح BackgroundService بالإضافة إلى إدارة lifetime الـ host قيّماً جدّاً
  5. BackgroundService ليس له scope افتراضيّ، لذا ينبغي حلّ الخدمات scoped داخل scope صريح
  6. WebApplicationBuilder في ASP.NET Core يجلس على نفس النموذج الإجماليّ

Generic Host ليس طقساً ثقيلاً لذاته.
حالما تبدأ الإعدادات والـ logging وتوصيل الـ dependencies وبدء التشغيل والإيقاف بالنموّ، يصبح طريقة لإبقاء تلك الاهتمامات معاً عند نقطة الدخول بدلاً من السماح لها بالتسرّب في كلّ أنحاء التطبيق.

من ناحية أخرى، إن كانت الأداة لا تزال صغيرة جدّاً، فلست مضطرّاً لإحضاره.
حالما تستطيع التمييز بين تلك الحالات، يتوقّف Generic Host عن أن يبدو وكأنّه «شيء تضيفه بحكم العادة» ويبدأ بأن يبدو أساساً عمليّاً جدّاً.

11. المراجع

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

روابط عامة

العودة إلى المدونة