Middleware نویسی در ASP.NET Core: راهنمای پیشرفته برای توسعه‌دهندگان حرفه‌ای

Middleware نویسی در ASP.NET Core: راهنمای پیشرفته برای توسعه‌دهندگان حرفه‌ای

نوشته شده توسط: تیم فنی نیک آموز
تاریخ انتشار: ۱۳ اردیبهشت ۱۴۰۴
آخرین بروزرسانی: 13 اردیبهشت 1404
زمان مطالعه: 10 دقیقه
۰
(۰)

در معماری مدرن وب، مدیریت درخواست‌ها و پاسخ‌ها به صورت مؤثر و قابل توسعه اهمیت بالایی دارد. در ASP.NET Core، این وظیفه بر عهده Middlewares است. Middlewares اجزایی هستند که در مسیر پردازش درخواست‌ها قرار می‌گیرند و می‌توانند عملیات مختلفی مانند احراز هویت، لاگ‌گیری، مدیریت خطا و … را انجام دهند. در این مقاله، به بررسی عمیق Middlewares در ASP.NET Core می‌پردازیم و نحوه‌ی ایجاد، پیکربندی و استفاده از آن‌ها را با مثال‌های عملی و کدهای نمونه توضیح می‌دهیم.

Middleware چیست و چگونه کار می‌کند؟

Middleware در ASP.NET Core، کلاسی است که می‌تواند درخواست‌های HTTP را پردازش کرده و به Middleware بعدی در زنجیره منتقل کند یا زنجیره را متوقف کند. هر Middleware می‌تواند قبل و بعد از اجرای Middleware بعدی عملیات خاصی انجام دهد.

ساختار پایه یک Middleware

public class CustomMiddleware
{
    private readonly RequestDelegate _next;
    public CustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        // عملیات قبل از Middleware بعدی
        await _next(context);
        // عملیات بعد از Middleware بعدی
    }
}

 

برای استفاده از این Middleware در برنامه:

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<CustomMiddleware>();
}


برای تسلط بیشتر بر معماری و تکنیک‌های خاص، دوره آموزش پیشرفته ASP.NET Core، می‌تواند مسیر شما را برای تبدیل شدن به یک توسعه‌دهنده حرفه‌ای هموار کند.



نحوه ایجاد Middleware سفارشی

در این بخش از مقاله به نحوه ایجاد Middleware سفارشی خواهیم پرداخت. با ما همراه باشید:

روش‌های ایجاد Middleware سفارشی

استفاده از کلاس با متد InvokeAsync

روش متداول برای ایجاد Middleware، تعریف کلاسی با متد InvokeAsync است که یک شیء HttpContext را می‌پذیرد.

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
    public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation("درخواست وارد شد: {Path}", context.Request.Path);
        await _next(context);
        _logger.LogInformation("پاسخ ارسال شد: {StatusCode}", context.Response.StatusCode);
    }
}

استفاده از واسط IMiddleware

روش دیگر، پیاده‌سازی واسط IMiddleware است که امکان تزریق وابستگی‌ها از طریق DI را فراهم می‌کند.

{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        // عملیات قبل از Middleware بعدی
        await next(context);
        // عملیات بعد از Middleware بعدی
    }
}

در این روش، Middleware باید در متد ConfigureServices ثبت شود:

services.AddTransient<CustomMiddleware>();

و در متد Configure استفاده شود:

app.UseMiddleware<CustomMiddleware>();


اگر می‌خواهید کدهایی انعطاف‌پذیرتر و تست‌پذیرتر بنویسید، آشنایی عمیق‌تر با تزریق وابستگی در ASP.NET Core کاملاً ضروری است.



niddle ware in asp.net core

Middleware؛ دشمن پنهان اپلیکیشن شما!

Middlewares در ظاهر ساده و بی‌دردسر به نظر می‌رسند؛ چند خط کد که درخواست‌ها را پردازش می‌کنند و به مسیرشان ادامه می‌دهند؛ اما همین بخش ساده، زمانی که به درستی مدیریت نشود، می‌تواند کل اپلیکیشن را به چالش بکشد. یک Middleware بد نوشته‌شده ممکن است باعث شود:

  • درخواست‌ها بی‌دلیل معطل بمانند (Performance Bottlenecks)
  • اطلاعات حساس لو برود (Security Leaks)
  • مسیر اجرای درخواست‌ها غیرقابل پیش‌بینی شود (Unpredictable Behaviors)

مثال:
 فرض کنید یک Middleware نوشته‌اید که فقط در شرایط خاصی await next() را صدا می‌زند. این باعث می‌شود درخواست‌هایی که باید عبور کنند، در مسیر گیر کنند یا پاسخ نگیرند.

if (shouldContinue)
{
    await next();
}

اگر shouldContinue به‌اشتباه false شود، دیگر چیزی عبور نخواهد کرد — اینجا اپلیکیشن شما عملاً قفل می‌شود.

 رایج‌ترین اشتباهات Middleware نویسی که نباید مرتکب شوید

اشتباهات زیادی در پیاده‌سازی Middleware رخ می‌دهد، اما برخی از آن‌ها بسیار خطرناک‌تر هستند:

  • فراموش کردن فراخوانی await next() 

           باعث توقف کل مسیر پردازش درخواست می‌شود.

  • انجام عملیات زمان‌بر یا بلاک‌کننده (Blocking) در Middleware
    مثلاً دستورات Thread.Sleep یا خواندن/نوشتن سنکرون که باعث قفل شدن Threads می‌شود.
  • عدم مدیریت Exceptions در سطح Middleware
     بدون Try-Catch مناسب، خطاهای بالادستی کل Pipeline را خراب می‌کند.

مثال:

public async Task Invoke(HttpContext context)
{
    // Missing await next() 
    Console.WriteLine("Request reached here.");
}

در این مثال درخواست هرگز به مرحله بعد نمی‌رود.

ترتیب اجرای Middlewares

ترتیب ثبت Middlewares در متد Configure اهمیت بالایی دارد، زیرا درخواست‌ها به ترتیب از آن‌ها عبور می‌کنند و پاسخ‌ها به صورت معکوس بازمی‌گردند.

مثال:

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<Middleware1>();
    app.UseMiddleware<Middleware2>();
    app.UseMiddleware<Middleware3>();
}

در این حالت، ترتیب اجرای درخواست‌ها: Middleware 1 → Middleware 2 → Middleware 3

و ترتیب اجرای پاسخ‌ها: Middleware 3 → Middleware 2 → Middleware 1

مثال عملی: Middleware برای بررسی هدرهای سفارشی

فرض کنید می‌خواهیم یک Middleware ایجاد کنیم که بررسی کند آیا هدر خاصی در درخواست وجود دارد یا خیر.

public class HeaderValidationMiddleware
{
    private readonly RequestDelegate _next;
    public HeaderValidationMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.ContainsKey("X-Custom-Header"))
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
            await context.Response.WriteAsync("هدر مورد نیاز یافت نشد.");
            return;
        }
        await _next(context);
    }
}

 از فاجعه تا عملکرد ایده‌آل: اصول نوشتن Middleware تمیز

Middleware تمیز و حرفه‌ای باید:

✅ کوتاه و خوانا باشد
✅ مسئولیت محدود داشته باشد
✅ با Exception Handling مناسب نوشته شود
✅ Logging داشته باشد تا دیباگ ساده‌تر شود

مثال ساختاری مناسب:

public async Task Invoke(HttpContext context)
{
    try
    {
        // Logic before
        await _next(context);
        // Logic after
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Middleware error");
        throw;
    }
}

در اینجا:

  • درخواست حتماً عبور می‌کند.
  • خطاها لاگ می‌شوند.
  • ساختار قابل فهم است.

مدیریت صحیح خطاها بخش مهمی از معماری تمیز است؛ در مدیریت خطاها در ASP.NET Core با راهکارهای حرفه‌ای آن آشنا شوید.

الگوهای طلایی برای طراحی Middleware های مقیاس‌پذیر و قابل اعتماد

برای مقیاس‌پذیری و اطمینان بالا:

✅ Middlewares باید stateless باشند.
✅ از DI  – Dependency Injection برای دسترسی به سرویس‌ها استفاده کنند.
✅ از Task-based Asynchronous Pattern بهره بگیرند.
✅ قابل تست باشند.

مثال – استفاده صحیح از DI:

public class ExampleMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IService _service;
    public ExampleMiddleware(RequestDelegate next, IService service)
    {
        _next = next;
        _service = service;
    }
    public async Task Invoke(HttpContext context)
    {
        _service.DoWork();
        await _next(context);
    }
}

این باعث می‌شود Middleware شما وابستگی‌ها را به درستی مدیریت کرده و در تست‌ها Mock شوند.

asp.net core middleware

کدام Middleware ضروری است و کدام را باید کنار بگذارید؟

۱.ضروری‌ها:

  • Exception Handling Middleware (مانند UseExceptionHandler)
  • Authentication & Authorization Middleware
  • Logging Middleware
  • CORS Middleware

۲. غیرضروری‌ها یا خطرناک‌ها:

  • Middlewares که کارهای منطقی پیچیده یا Business Logic انجام می‌دهند.
  • Middlewares که بلاک‌کننده یا زمان‌بر هستند.
  • Middlewares که داده‌ها را تغییر می‌دهند (Manipulation Middleware)

مثال:
 Middleware که داده‌ها را به طور مستقیم تغییر دهد و ادامه مسیر را سخت کند، معمولاً ایده خوبی نیست.

context.Response.Body = ... // Avoid this in Middleware unless really needed

معماری تمیز در ASP.NET Core؛ جایگاه کلیدی Middleware ها در طراحی حرفه‌ای

در معماری تمیز، Middlewares وظیفه‌ی کنترل جریان درخواست‌ها و مدیریت concerns عمومی (مانند امنیت، لاگ‌ها، هندل خطاها) را دارند.

✅ نباید Business Logic در آن‌ها باشد.
✅ نباید با لایه‌های پایین‌تر (Repository, Service) درگیر شوند.
✅ فقط باید مسیر Request و Response را مدیریت کنند.

مثال نقش صحیح Middleware:

app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RequestLoggingMiddleware>();
app.UseEndpoints(...);

در اینجا هر Middleware وظیفه مشخص و دقیقی دارد و هیچکدام وارد حیطه‌ی دیگری نمی‌شود؛ این یعنی معماری تمیز.

استفاده از Middlewares داخلی ASP.NET Core

ASP.NET Core مجموعه‌ای از Middlewareهای داخلی را فراهم می‌کند که می‌توانند برای وظایف متداول استفاده شوند:

  • UseRouting: مسیردهی درخواست‌ها
  • UseAuthentication: احراز هویت کاربران
  • UseAuthorization: مجوزدهی به کاربران
  • UseStaticFiles: ارائه فایل‌های استاتیک
  • UseEndpoints: تعریف نقاط پایانی برای کنترلرها و Razor Pages

مثال:

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

سخن پایانی

Middlewares بخش حیاتی از معماری ASP.NET Core هستند که امکان کنترل دقیق بر روی پردازش درخواست‌ها و پاسخ‌ها را فراهم می‌کنند. با درک صحیح از نحوه‌ی کارکرد و ایجاد Middlewares، می‌توان برنامه‌هایی قابل توسعه، قابل نگهداری و با عملکرد بالا ایجاد کرد.

سوالات متداول

  1. تفاوت بین Middleware و فیلترها در ASP.NET Core چیست؟

Middlewares در سطح برنامه عمل می‌کنند و برای پردازش کلیه‌ی درخواست‌ها و پاسخ‌ها استفاده می‌شوند، در حالی که فیلترها در سطح کنترلرها و اکشن‌ها عمل می‌کنند و برای وظایف خاص مانند اعتبارسنجی مدل یا مدیریت استثناها استفاده می‌شوند.

  1. چگونه می‌توان Middleware را فقط برای مسیرهای خاصی اعمال کرد؟

می‌توان از متد MapWhen برای اعمال Middlewares بر اساس شرایط خاص استفاده کرد:

app.MapWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>
{
    appBuilder.UseMiddleware<CustomMiddleware>();
});
  1. آیا می‌توان از Middlewares برای مدیریت خطاها استفاده کرد؟

بله، می‌توان Middleware هایی ایجاد کرد که خطاها را مدیریت کرده و پاسخ‌های مناسب به کاربر ارائه دهند. همچنین؛ ASP.NET Core Middleware های داخلی مانند UseExceptionHandler را برای این منظور فراهم می‌کند.

 

  1. Middleware ها باید Business Logic را هم مدیریت کنند؟

خیر! 

  • یکی از اصول معماری تمیز این است که Middleware فقط باید مسئول مدیریت جریان درخواست‌ها (مانند اعتبارسنجی، لاگ‌ها، هندلینگ خطاها و…) باشد.
  •  ورود Business Logic به Middleware باعث می‌شود هم تست‌نویسی سخت شود و هم معماری
  • نرم‌افزار پیچیده و آسیب‌پذیر شود.
  •  Business Logic باید در لایه‌های مشخص مانند Service ها و Handler ها پیاده‌سازی شود.
  1. اگر Middleware ای await next() را فراخوانی نکند چه اتفاقی می‌افتد؟

 در این صورت اجرای Pipeline متوقف می‌شود و درخواست به Middleware های بعدی یا Endpoint نمی‌رسد. این کار معمولاً باعث بروز مشکلاتی مثل تایم‌اوت، پاسخ ندادن سرور یا رفتار غیرمنتظره می‌شود؛ فراخوانی await next() (مگر در موارد خاص مثل Short Circuit Middleware ها) ضروری است تا جریان درخواست کامل طی شود.

چه رتبه ای می‌دهید؟

میانگین ۰ / ۵. از مجموع ۰

اولین نفر باش

title sign
معرفی نویسنده
تیم فنی نیک آموز
مقالات
417 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
تیم فنی نیک آموز
title sign
معرفی محصول
title sign
دیدگاه کاربران