درج await _next(context) را در میانافزارها (Middleware)، فراموش نکنید!
نویسنده: هادی مزارعی
تاریخ: ۱۴۰۴/۰۵/۰۱ ۱۲:۴۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
context در پاسخ بازگشتی از HttpClient کد وضعیت را StatusCode = 200 برگشت میداد و Content خالی بود. جالبتر اینکه Break Pointی که برای متد GET در Controller قرار داده بودم هرگز توسط Debugger فعال نمیشد و برایم خیلی عجیب بود.Invoke در Middleware را بررسی کردم و همه چیز درست بود. زمانیکه با حساب Developer وارد میشدم همان ابتدای کار درخواست با استفاده از await _next(context) به Middleware بعدی ارسال میشد و خط بعدی return بود. اما برای کاربر عادی باید تا انتهای کدهای Invoke اجرا میشد و هرجا که دسترسی وجود نداشت return میشد و این مورد هم درست کار میکرد چون نتیجه بررسیها، عدم دسترسی را نشان میداد. اما اشتباه من این بود که فکر میکردم اگر Invoke به انتها برسد، حتما Middleware بعدی اجرا میشود که هیچ وقت نشد که بعد صرف حدود نیم روز و اصلاح کلی کد متوجه شدم در انتها، اگر پارامتری، context را return نکرد باید در انتها next اجرا شود.Invoke تمام کدها را در بالای عبارت await _next(context) بنویسید تا همیشه این عبارت در انتها خط وجود داشته باشد مگر اینکه آگاهانه حذفش کنید.await _next(context): این دستور دقیقاً همان "دست به دست کردن" درخواست به حلقه بعدی زنجیر است. اگر این دستور در یک مسیر منطقی از کد شما فراخوانی نشود، زنجیره در همان نقطه متوقف (short-circuited) میشود.StatusCode 200 با محتوای خالی؟ چون Middleware ما به صراحت خطایی (مانند 401 یا 403) را به context.Response اضافه نکرده بود، ASP.NET Core فرض را بر این میگذاشت که پردازش با موفقیت به پایان رسیده است. اما چون درخواست هرگز به Controller نرسیده بود تا پاسخی تولید کند، Content خالی بازگردانده میشد. در واقع، Middleware ما بدون تولید پاسخ، مسئولیت را به پایان رساند.public async Task InvokeAsync(HttpContext context)
{
// اگر کاربر ادمین است، بدون بررسی به مرحله بعد برو
if (IsAdmin(context.User))
{
await _next(context);
return;
}
// در اینجا منطق بررسی دسترسی برای کاربر عادی قرار میگیرد
// اگر کاربر دسترسی نداشت، میتوانستید با تنظیم StatusCode و بازگشت، زنجیره را متوقف کنید
// if (!HasAccess(context.User))
// {
// context.Response.StatusCode = 403; // Forbidden
// return;
// }
// اگر تمام بررسیها برای کاربر عادی موفق بود، درخواست به مرحله بعد میرود
// این همان خطی بود که در کد ما برای کاربر عادی اجرا نمیشد
await _next(context);
}