معماری Pipeline و Middleware در ASP.NET Core MVC: قلب تپنده برنامههای وب مدرن
1. چیستی Pipeline در ASP.NET Core MVC:
تصور کنید یک کارخانه تولیدی را که در آن مواد اولیه از یک سری ایستگاههای کاری عبور میکنند تا در نهایت به محصول نهایی تبدیل شوند. در ASP.NET Core MVC، Pipeline پردازش درخواست HTTP دقیقاً همین نقش را ایفا میکند. این Pipeline مجموعهای از اجزای نرمافزاری به نام Middleware است که به ترتیب خاصی در کنار یکدیگر قرار گرفتهاند و هر کدام وظیفه خاصی را در طول چرخه حیات یک درخواست HTTP ورودی انجام میدهند.
هنگامی که یک کاربر از طریق مرورگر خود یک درخواست (Request) به سرور ASP.NET Core ارسال میکند، این درخواست ابتدا وارد Pipeline میشود. سپس، این درخواست از میان هر یک از Middlewareهای موجود در Pipeline عبور میکند. هر Middleware میتواند عملیات خاصی را بر روی درخواست (و یا پاسخ نهایی) انجام دهد، مانند:
- بررسی احراز هویت کاربر (Authentication)
- اعتبارسنجی مجوز دسترسی کاربر (Authorization)
- ثبت وقایع (Logging)
- ارائه فایلهای استاتیک (Static Files)
- مدیریت Session کاربر
- انجام عملیات مسیریابی (Routing) برای تعیین Controller و Action مربوطه
- مدیریت خطاها (Error Handling)
- فشردهسازی پاسخ (Response Compression)
- افزودن هدرهای امنیتی
- و بسیاری موارد دیگر
در نهایت، پس از عبور درخواست از تمامی Middlewareهای موجود در Pipeline (یا در صورت وجود، قبل از رسیدن به انتهای Pipeline)، درخواست به Endpoint نهایی برنامه میرسد. در یک برنامه ASP.NET Core MVC، این Endpoint معمولاً یک Action Method در یک Controller است که منطق اصلی پردازش درخواست و تولید پاسخ را بر عهده دارد. پس از اینکه Action Method پاسخ (Response) را تولید کرد، این پاسخ نیز مجدداً از طریق Pipeline و به صورت معکوس از میان همان Middlewareها عبور میکند تا قبل از ارسال به کاربر، پردازشهای لازم (مانند افزودن هدرها، فشردهسازی و غیره) بر روی آن انجام شود.
2. چیستی Middleware در ASP.NET Core MVC:
Middleware در ASP.NET Core MVC، یک جزء نرمافزاری مستقل و قابل استفاده مجدد است که میتواند برای انجام وظایف خاص در طول پردازش درخواست و پاسخ HTTP به Pipeline اضافه شود. هر Middleware به عنوان یک حلقه در زنجیره Pipeline عمل میکند و مسئول انجام یک عمل خاص است.
Middlewareها معمولاً به صورت کلاسهایی پیادهسازی میشوند که دارای یک متد به نام InvokeAsync (یا Invoke) هستند. این متد دو پارامتر اصلی دریافت میکند:
HttpContext: که شامل اطلاعات مربوط به درخواست HTTP جاری (مانند متد، هدرها، بدنه درخواست و غیره) و همچنین اطلاعات مربوط به پاسخ HTTP در حال ساخت است.
RequestDelegate next: که نماینده (Delegate) Middleware بعدی در Pipeline است.
نحوه عملکرد یک Middleware به این صورت است که ابتدا منطق مربوط به خود را بر روی HttpContext اعمال میکند. سپس، میتواند تصمیم بگیرد که آیا درخواست را به Middleware بعدی در Pipeline ارسال کند یا خیر. اگر Middleware متد next را فراخوانی کند، درخواست به Middleware بعدی منتقل میشود. اگر Middleware متد next را فراخوانی نکند، پردازش Pipeline متوقف شده و Middleware میتواند پاسخ نهایی را تولید و ارسال کند (اصطلاحاً به این عمل Short-circuiting یا میانبُر زدن Pipeline گفته میشود).
علاوه بر پیادهسازی به صورت کلاس، Middlewareها میتوانند به صورت Anonymous Middleware یا Middlewareهای درونخطی نیز تعریف شوند. این نوع Middlewareها معمولاً برای انجام وظایف ساده و کوتاه استفاده میشوند و به صورت یک Delegate در هنگام پیکربندی Pipeline تعریف میگردند.
3. کارکرد Middleware در ASP.NET Core MVC:
Middlewareها در ASP.NET Core MVC طیف وسیعی از وظایف را بر عهده دارند و نقش بسیار مهمی در عملکرد و قابلیتهای برنامههای وب ایفا میکنند. برخی از مهمترین کارکردهای Middlewareها عبارتند از:
- احراز هویت و مجوزدهی (Authentication and Authorization): Middlewareهای احراز هویت، هویت کاربر درخواستکننده را شناسایی میکنند، در حالی که Middlewareهای مجوزدهی، تعیین میکنند که آیا کاربر احراز هویت شده، اجازه دسترسی به منبع درخواستی را دارد یا خیر. این Middlewareها امنیت برنامه را تضمین میکنند.
- ثبت وقایع و عیبیابی (Logging and Diagnostics): Middlewareهای Logging اطلاعات مربوط به درخواستها، پاسخها، خطاها و سایر رویدادهای مهم را ثبت میکنند که برای نظارت بر عملکرد برنامه و عیبیابی مشکلات بسیار مفید است. Middlewareهای Diagnostics نیز میتوانند اطلاعات مفیدی در مورد خطاها و استثنائات رخ داده در برنامه ارائه دهند.
- ارائه فایلهای استاتیک (Static Files): Middlewareهای Static Files امکان ارائه فایلهای استاتیک مانند تصاویر، فایلهای CSS، فایلهای JavaScript و غیره را بدون نیاز به پردازش توسط Controllerها فراهم میکنند که باعث بهبود عملکرد میشود.
- مسیریابی (Routing): Middlewareهای Routing وظیفه تطبیق URL درخواست با یک Controller و Action Method خاص را بر عهده دارند. این Middleware تعیین میکند که کدام قسمت از برنامه باید درخواست را پردازش کند.
- مدیریت Session (Session Management): Middlewareهای Session امکان ذخیره و بازیابی اطلاعات مربوط به Session کاربر را در طول تعاملات مختلف فراهم میکنند. این برای حفظ وضعیت کاربر در بین درخواستها ضروری است.
- مدیریت خطاها (Error Handling): Middlewareهای مدیریت خطا مانند ExceptionHandlerMiddleware و DeveloperExceptionPageMiddleware به طور مرکزی خطاها و استثنائات رخ داده در Pipeline را مدیریت کرده و پاسخ مناسبی را به کاربر ارائه میدهند.
- فشردهسازی پاسخ (Response Compression): Middlewareهای فشردهسازی میتوانند حجم پاسخهای HTTP را کاهش داده و در نتیجه سرعت بارگذاری صفحات وب را برای کاربران بهبود بخشند.
- پشتیبانی از CORS (Cross-Origin Resource Sharing): Middlewareهای CORS امکان کنترل دسترسی منابع وب از دامنههای مختلف را فراهم میکنند و از مسائل امنیتی مربوط به درخواستهای بین دامنهای جلوگیری میکنند.
- افزودن هدرهای امنیتی (Security Headers): Middlewareها میتوانند هدرهای امنیتی مختلفی را به پاسخهای HTTP اضافه کنند تا از برنامه در برابر حملات رایج وب محافظت کنند.
- انجام منطق سفارشی (Custom Logic): توسعهدهندگان میتوانند Middlewareهای سفارشی خود را برای انجام هرگونه منطق تجاری یا عملیات خاص مورد نیاز برنامه ایجاد کنند. این انعطافپذیری بسیار بالایی را در اختیار توسعهدهندگان قرار میدهد.
4. چگونگی عملکرد Pipeline و Middleware:
عملکرد Pipeline و Middleware در ASP.NET Core MVC به صورت یک زنجیره متصل از اجزا صورت میگیرد. هنگامی که یک درخواست HTTP وارد برنامه میشود، مراحل زیر به ترتیب انجام میشوند:
- دریافت درخواست: سرور وب (مانند Kestrel) درخواست HTTP را دریافت میکند.
- ورود به Pipeline: درخواست وارد Pipeline پردازش میشود.
- عبور از Middlewareها: درخواست به ترتیب از میان هر یک از Middlewareهای پیکربندی شده در Pipeline عبور میکند.
- پردازش توسط هر Middleware: هر Middleware منطق خاص خود را بر روی HttpContext اعمال میکند. این منطق میتواند شامل بررسی درخواست، تغییر آن، انجام عملیات خاص، یا تولید پاسخ باشد.
- فراخوانی Middleware بعدی: در صورت نیاز، هر Middleware متد next را فراخوانی میکند تا درخواست به Middleware بعدی در Pipeline منتقل شود.
- رسیدن به Endpoint: در نهایت، درخواست (اگر Pipeline به طور کامل طی شود) به Endpoint نهایی برنامه میرسد (معمولاً یک Action Method در یک Controller).
- تولید پاسخ: Endpoint پاسخ HTTP را تولید میکند.
- عبور معکوس از Pipeline: پاسخ تولید شده به صورت معکوس از میان همان Middlewareهایی که درخواست از آنها عبور کرده بود، عبور میکند.
- پردازش پاسخ توسط Middlewareها: هر Middleware میتواند در این مرحله نیز عملیاتی را بر روی پاسخ انجام دهد (مانند افزودن هدرها، فشردهسازی و غیره).
- ارسال پاسخ: در نهایت، پاسخ HTTP به کاربر ارسال میشود.
نکته کلیدی در عملکرد Pipeline، ترتیب قرارگیری Middlewareها است. ترتیبی که Middlewareها در Pipeline پیکربندی میشوند، تأثیر مستقیمی بر نحوه پردازش درخواست و پاسخ دارد. برای مثال، Middleware احراز هویت باید قبل از Middleware مجوزدهی قرار گیرد، زیرا ابتدا باید هویت کاربر مشخص شود تا بتوان مجوز دسترسی او را بررسی کرد. به همین ترتیب، Middleware مدیریت خطا معمولاً در ابتدای Pipeline قرار میگیرد تا بتواند هرگونه خطای احتمالی در طول پردازش درخواست توسط سایر Middlewareها یا Endpoint را مدیریت کند.
5. پیکربندی Pipeline و افزودن Middleware:
Pipeline در ASP.NET Core MVC در متد Configure کلاس Startup.cs پیکربندی میشود. شیء IApplicationBuilder که به این متد تزریق میشود، برای افزودن Middlewareها به Pipeline استفاده میشود. متدهای Extension مختلفی بر روی IApplicationBuilder وجود دارند که برای افزودن Middlewareهای مختلف به کار میروند. برخی از رایجترین این متدها عبارتند از:
- app.UseStaticFiles(): برای فعال کردن ارائه فایلهای استاتیک.
- app.UseRouting(): برای فعال کردن مسیریابی.
- app.UseAuthentication(): برای فعال کردن مکانیسمهای احراز هویت.
- app.UseAuthorization(): برای فعال کردن مکانیسمهای مجوزدهی.
- app.UseSession(): برای فعال کردن مدیریت Session.
- app.UseExceptionHandler(): برای مدیریت خطاهای تولید شده در محیط غیر توسعه.
- app.UseDeveloperExceptionPage(): برای نمایش جزئیات خطاها در محیط توسعه.
- app.UseHsts(): برای فعال کردن HSTS
- app.UseHttpsRedirection(): برای فعال کردن تغییر مسیر به HTTPS
- app.UseCors(): برای فعال کردن CORS
- app.UseMiddleware(): برای افزودن یک Middleware سفارشی که به صورت یک کلاس پیادهسازی شده است.
- app.Use(): برای افزودن یک Middleware درونخطی (Anonymous Middleware) به صورت یک Delegate.
- app.Map() و app.MapWhen(): برای شاخهبندی Pipeline بر اساس مسیر درخواست یا شرایط خاص.
مثال ساده از پیکربندی Pipeline در Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
در این مثال، Middlewareها به ترتیب زیر به Pipeline اضافه شدهاند:
- Middlewareهای مدیریت خطا بر اساس محیط (توسعه یا تولید).
- Middleware هدایت اجباری به HTTPS.
- Middleware ارائه فایلهای استاتیک.
- Middleware مسیریابی.
- Middleware احراز هویت.
- Middleware مجوزدهی.
- Middleware مدیریت Session.
- Middleware Endpoint Routing برای اتصال درخواستها به Controllerها و Action Methodها.
6. ایجاد Middleware سفارشی:
توسعهدهندگان میتوانند Middlewareهای سفارشی خود را برای انجام منطق خاص مورد نیاز برنامه ایجاد کنند. برای ایجاد یک Middleware سفارشی، معمولاً یک کلاس ایجاد میشود که دارای شرایط زیر است:
کلاس باید دارای یک متد به نام InvokeAsync باشد.
متد InvokeAsync باید دو پارامتر دریافت کند: HttpContext و RequestDelegate next.
کلاس Middleware میتواند از طریق سازنده (Constructor Injection) به سرویسهای مورد نیاز خود دسترسی پیدا کند.
مثال از یک Middleware سفارشی برای ثبت زمان پردازش درخواست:
public class RequestTimeMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public RequestTimeMiddleware(RequestDelegate next, ILogger logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var startTime = Stopwatch.StartNew();
await _next(context); // فراخوانی Middleware بعدی
startTime.Stop();
_logger.LogInformation($"Request to {context.Request.Path} took {startTime.ElapsedMilliseconds} ms");
}
}
برای استفاده از این Middleware سفارشی، باید آن را در متد Configure به Pipeline اضافه کنیم:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// سایر Middlewareها...
app.UseMiddleware(); // افزودن Middleware سفارشی
// سایر Middlewareها...
}
همچنین، میتوان یک Middleware سفارشی را به صورت یک Middleware درونخطی (Anonymous Middleware) تعریف کرد:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// سایر Middlewareها...
app.Use(async (context, next) => {
var startTime = Stopwatch.StartNew();
await next(); // فراخوانی Middleware بعدی
startTime.Stop();
Log.Information($"Request to {context.Request.Path} took {startTime.ElapsedMilliseconds} ms");
});
// سایر Middlewareها...
}
7. Middlewareهای رایج در ASP.NET Core:
ASP.NET Core دارای مجموعهای از Middlewareهای داخلی است که برای انجام وظایف رایج استفاده میشوند. در اینجا به برخی از مهمترین آنها اشاره میکنیم:
- StaticFilesMiddleware: این Middleware امکان ارائه فایلهای استاتیک مانند تصاویر، CSS و JavaScript را فراهم میکند.
- RoutingMiddleware: این Middleware مسئول تطبیق URL درخواست با یک Controller و Action Method است.
- AuthenticationMiddleware: این Middleware هویت کاربر را تأیید میکند.
- AuthorizationMiddleware: این Middleware تعیین میکند که آیا کاربر احراز هویت شده، اجازه دسترسی به منبع درخواستی را دارد یا خیر.
- SessionMiddleware: این Middleware امکان ایجاد و مدیریت Session کاربر را فراهم میکند.
- ExceptionHandlerMiddleware و DeveloperExceptionPageMiddleware: این Middlewareها خطاها را مدیریت میکنند. DeveloperExceptionPageMiddleware جزئیات کامل خطا را در محیط توسعه نمایش میدهد، در حالی که ExceptionHandlerMiddleware یک صفحه خطای کاربر پسند را در محیط تولید نمایش میدهد.
- HstsMiddleware: این Middleware هدر Strict-Transport-Security را اضافه میکند تا مرورگرها را مجبور به استفاده از HTTPS کند.
- HttpsRedirectionMiddleware: این Middleware درخواستهای HTTP را به HTTPS تغییر مسیر میدهد.
- CorsMiddleware: این Middleware امکان پیکربندی و فعالسازی Cross-Origin Resource Sharing (CORS) را فراهم میکند.
8. نقش Middleware در ASP.NET Core MVC:
Middlewareها نقش اساسی در معماری ASP.NET Core MVC ایفا میکنند و مزایای متعددی را برای توسعهدهندگان فراهم میکنند:
- ماژولار بودن: Middlewareها به توسعهدهندگان اجازه میدهند تا منطق برنامه را به اجزای کوچک و قابل استفاده مجدد تقسیم کنند.
- قابلیت استفاده مجدد: Middlewareها را میتوان در چندین برنامه مختلف استفاده کرد.
- انعطافپذیری: توسعهدهندگان میتوانند Middlewareهای سفارشی خود را برای انجام هرگونه منطق خاص ایجاد کنند.
- بهبود عملکرد: Middlewareها میتوانند با انجام وظایفی مانند فشردهسازی پاسخ و ذخیرهسازی در حافظه پنهان، عملکرد برنامه را بهبود بخشند.
- جداسازی مسئولیتها: Middlewareها به جداسازی مسئولیتهای مختلف در برنامه کمک میکنند و باعث میشوند کد تمیزتر و قابل نگهداریتر باشد.
- به طور خلاصه، Middlewareها به عنوان بلوکهای سازنده Pipeline عمل میکنند و به توسعهدهندگان این امکان را میدهند تا به صورت ماژولار و انعطافپذیر، قابلیتهای مختلفی را به برنامههای ASP.NET Core MVC خود اضافه کنند.
9. بهترین روشها برای استفاده از Middleware:
برای استفاده موثر از Middleware در ASP.NET Core، رعایت برخی از بهترین روشها توصیه میشود:
- هر Middleware یک وظیفه: هر Middleware باید فقط یک وظیفه خاص را انجام دهد. این باعث میشود کد تمیزتر و قابل نگهداریتر باشد.
- ترتیب مهم است: ترتیب افزودن Middlewareها به Pipeline بسیار مهم است. Middlewareها باید به ترتیبی اضافه شوند که منطقی باشد و نیازهای برنامه را برآورده کند.
- اجتناب از عملیات طولانی: Middlewareها نباید عملیات طولانی یا مسدود کننده را انجام دهند، زیرا این امر میتواند باعث کاهش عملکرد برنامه شود.
- مدیریت صحیح خطاها: Middlewareها باید خطاها را به درستی مدیریت کنند و پاسخ مناسب را به کاربر ارائه دهند.
10. نتیجهگیری:
Pipeline و Middleware مفاهیم اساسی در ASP.NET Core MVC هستند که نحوه پردازش درخواستهای HTTP را تعیین میکنند. Middlewareها اجزای قابل استفاده مجددی هستند که میتوانند برای افزودن قابلیتهای مختلف به Pipeline استفاده شوند. درک صحیح این مفاهیم برای هر توسعهدهنده ASP.NET Core ضروری است، زیرا به آنها امکان میدهد برنامههای وب ماژولار، انعطافپذیر و کارآمد را بسازند. با استفاده از Middlewareهای داخلی و سفارشی، توسعهدهندگان میتوانند به راحتی منطق مورد نیاز خود را به برنامههای خود اضافه کرده و عملکرد و امنیت آنها را بهبود بخشند.
2 نظر
علی نرگسی
۱۴۰۴/۰۲/۲۶ عالیکینگتو
۱۴۰۴/۰۲/۲۶ سپاس