مقدمه

در درس‌های گذشته، با مفاهیم بنیادی وب مانند HTTP، HTML، CSS و JavaScript آشنا شدیم. اکنون زمان آن است که به فریم‌ورک سمت سرور خود، یعنی ASP.NET Core، بازگشته و معماری داخلی آن را با دقت بیشتری بررسی کنیم. درک نحوه‌ی راه‌اندازی، پیکربندی و پردازش درخواست‌ها در این فریم‌ورک، برای ساخت هر نوع اپلیکیشن وب، از یک وبلاگ ساده گرفته تا یک وب‌سرویس پیچیده، ضروری است.

در این درس، ما به کالبدشکافی فایل Program.cs، که نقطه‌ی شروع هر اپلیکیشن ASP.NET Core مدرن است، می‌پردازیم. خواهیم دید که چگونه سرویس‌ها در کانتینر تزریق وابستگی ثبت می‌شوند و چگونه خط لوله‌ی پردازش درخواست با استفاده از میان‌افزارها (middleware) ساخته می‌شود.

فایل Program.cs: قلب تپنده‌ی اپلیکیشن

در پروژه‌های ASP.NET Core مبتنی بر .NET 6 و بالاتر، تمام منطق راه‌اندازی برنامه در فایل Program.cs متمرکز شده است. این فایل مسئول انجام دو کار اصلی است:

  1. پیکربندی سرویس‌ها (Configure Services): ثبت تمام سرویس‌هایی که برنامه به آن‌ها نیاز دارد در کانتینر تزریق وابستگی (Dependency Injection - DI).
  2. پیکربندی خط لوله‌ی درخواست (Configure Request Pipeline): تعریف و ترتیب میان‌افزارهایی که هر درخواست HTTP باید از آن‌ها عبور کند.

بیایید نگاهی دقیق‌تر به کد پیش‌فرض این فایل در یک پروژه‌ی Razor Pages بیندازیم.

Copy Icon Program.cs (Default Template)
var builder = WebApplication.CreateBuilder(args);

// 1. Add services to the container.
builder.Services.AddRazorPages();

var app = builder.Build();

// 2. Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

بخش اول: پیکربندی سرویس‌ها

خط var builder = WebApplication.CreateBuilder(args); یک میزبان وب (web host) را با تنظیمات پیش‌فرض ایجاد می‌کند. این میزبان مسئول مدیریت طول عمر برنامه و فراهم کردن سرویس‌های اصلی مانند لاگ‌گیری و پیکربندی است.

مهم‌ترین بخش در اینجا، پراپرتی builder.Services است. این پراپرتی یک کالکشن از تمام سرویس‌هایی است که در کانتینر تزریق وابستگی ثبت شده‌اند. تزریق وابستگی (DI) یک الگوی طراحی است که به ما اجازه می‌دهد تا وابستگی‌های یک کلاس را از خارج به آن "تزریق" کنیم، به جای اینکه خود کلاس مسئول ساختن آن‌ها باشد. این کار کد را بسیار ماژولارتر، قابل نگهداری‌تر و قابل تست‌تر می‌کند.

در کد بالا، خط builder.Services.AddRazorPages(); تمام سرویس‌های مورد نیاز برای کار با Razor Pages را به کانتینر اضافه می‌کند. در درس‌های قبل دیدیم که چگونه با استفاده از builder.Services.AddDbContext(...)، کانتکست پایگاه داده‌ی خود را نیز به عنوان یک سرویس ثبت کردیم.

بخش دوم: پیکربندی خط لوله‌ی درخواست

پس از فراخوانی var app = builder.Build();، تمام سرویس‌ها ثبت شده و ما یک نمونه از خود اپلیکیشن را در اختیار داریم. اکنون می‌توانیم خط لوله‌ی پردازش درخواست را با اضافه کردن میان‌افزارها پیکربندی کنیم.

ترتیب میان‌افزارها بسیار مهم است. هر درخواست از این خط لوله به ترتیب عبور می‌کند. بیایید برخی از میان‌افزارهای پیش‌فرض را بررسی کنیم:

  • UseExceptionHandler و UseHsts: این‌ها میان‌افزارهای امنیتی و مدیریت خطا هستند که فقط در محیط تولید (production) فعال می‌شوند.
  • UseHttpsRedirection: تمام درخواست‌های HTTP را به صورت خودکار به HTTPS هدایت می‌کند.
  • UseStaticFiles: به برنامه اجازه می‌دهد تا فایل‌های استاتیک مانند تصاویر، CSS و جاوااسکریپت را از پوشه‌ی wwwroot به کاربر تحویل دهد. این میان‌افزار معمولاً در ابتدای خط لوله قرار می‌گیرد، زیرا اگر یک درخواست برای یک فایل استاتیک باشد، نیازی به پردازش بیشتر نیست.
  • UseRouting: این میان‌افزار سیستم مسیریابی (routing) ASP.NET Core را فعال می‌کند. این سیستم درخواست‌های ورودی را بررسی کرده و تصمیم می‌گیرد که کدام "نقطه‌ی پایانی" (endpoint) باید آن را پردازش کند.
  • UseAuthorization: میان‌افزار مربوط به بررسی مجوزهای دسترسی کاربر.
  • MapRazorPages: این متد، مسیریابی را برای تمام صفحات Razor موجود در پوشه‌ی Pages تنظیم می‌کند. این همان بخشی است که به ASP.NET Core می‌گوید که درخواستی به آدرس /Movies/Index باید توسط صفحه‌ی Movies/Index.cshtml پردازش شود.

در نهایت، app.Run() برنامه را اجرا کرده و آن را در حالت گوش دادن به درخواست‌های HTTP ورودی قرار می‌دهد.