ASP.NET Core Middleware 🧩
ءMiddleware نرمافزاری است که در یک pipeline برنامه کنار هم قرار میگیرد تا درخواستها و پاسخها را مدیریت کند. هر کامپوننت:
تصمیم میگیرد که آیا درخواست را به کامپوننت بعدی در pipeline ارسال کند یا نه. 🔀
میتواند قبل و بعد از کامپوننت بعدی، پردازش انجام دهد. ⏱️
برای ساختن request pipeline از Request Delegateها استفاده میشود. این delegateها هر درخواست HTTP را مدیریت میکنند.
ءRequest delegateها با استفاده از متدهای extension زیر پیکربندی میشوند:
• Run
• Map
• Use
یک request delegate میتواند:
• بهصورت in-line و با یک متد anonymous تعریف شود (که به آن in-line middleware میگویند)،
• یا در قالب یک کلاس قابل استفاده مجدد تعریف شود.
این کلاسهای reusable و متدهای anonymous در واقع همان middleware یا middleware component هستند.
هر middleware در pipeline مسئول است یا کامپوننت بعدی را فراخوانی کند، یا pipeline را short-circuit کند.
وقتی یک middleware pipeline را short-circuit میکند، به آن terminal middleware گفته میشود،
چون جلوی ادامهی پردازش توسط middlewareهای بعدی را میگیرد.
ساخت middleware pipeline با WebApplication 🛠
ءrequest pipeline در ASP.NET Core شامل یک دنباله از request delegateها است که یکی پس از دیگری فراخوانی میشوند.
⚡️ ASP.NET Core Request Delegates و Pipeline
هر delegate میتواند قبل و بعد از delegate بعدی عملیات انجام دهد.
توصیه: exception-handling delegateها را اوایل pipeline قرار دهید تا بتوانند خطاهای رخ داده در مراحل بعدی را بگیرند.
سادهترین اپلیکیشن ASP.NET Core 🟢
در سادهترین حالت، یک single request delegate تعریف میشود که همه درخواستها را هندل میکند.
در این حالت، pipeline واقعی وجود ندارد.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
زنجیره کردن چند delegate با Use 🔗
ءnext نمایانگر delegate بعدی در pipeline است.
میتوان pipeline را با عدم فراخوانی next کوتاه کرد (Short-circuit).
معمولاً میتوان کارها را قبل و بعد از next انجام داد:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// کاری که میتواند Response بنویسد
await next.Invoke();
// کارهای logging یا دیگر عملیات غیر از نوشتن Response
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Short-Circuiting Pipeline ⚡️
اگر یک delegate درخواست را به delegate بعدی ندهد، pipeline short-circuit میشود.
کاربرد: جلوگیری از کار غیرضروری
مثال: Static File Middleware میتواند terminal middleware باشد و پس از پردازش فایل، pipeline را کوتاه کند.
توجه: Middlewareهایی که قبل از terminal middleware آمدهاند، هنوز بعد از next.Invoke کد اجرا میکنند.
⚠️ هشدار مهم
بعد یا هنگام ارسال Response به کلاینت، next.Invoke را فراخوانی نکنید!
تغییر header یا status code بعد از شروع Response → Exception
نوشتن به body بعد از next ممکن است:
باعث violation پروتکل شود (مثلاً نوشتن بیشتر از Content-Length)
فرمت body خراب شود (مثلاً HTML footer در فایل CSS)
نکته: HasStarted میتواند کمک کند بررسی کنید که آیا headers یا body قبلاً ارسال شدهاند یا نه.
Run delegates🏁
ءRun delegateها پارامتر next دریافت نمیکنند.
اولین Run delegate همیشه terminal است و pipeline را خاتمه میدهد.
ءRun یک convention است. بعضی از middleware componentها ممکن است متدهایی مثل Run[Middleware] ارائه دهند که در انتهای pipeline اجرا میشوند:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
در مثال بالا، Run delegate عبارت "Hello from 2nd delegate." را در response مینویسد و سپس pipeline را خاتمه میدهد.
اگر بعد از Run delegate، یک Use یا Run دیگر اضافه شود، دیگر فراخوانی نخواهد شد. 🛑