تفاوت Re-execute و Redirect در asp.net core


خب سلام.

توی این مقاله میخوام یکم درباره error handling صحبت کنم. بصورت کلی در asp.net core دو تا میدلویر برای این منظور داریم . یکی DeveloperExceptionPage که در محیط develop ازش استفاده می کنیم چون اطلاعات بهمون درباره خطای که رخ داده میده. (Stack trace - query string - cookies - headers). و اصولا چه از نظر زیبایی و چه از نظر امنیتی درست نیست که اطلاعات خطای درون برنامه خودمون رو به کاربر نشون بدیم.

دومی UseExceptionHandler که از این طریق هم میتونیم که صفحه رو به کاربر برگردونیم و توی محیط production ازش استفاده میشه.

یک بحث فقط اینجا مطرح میشه و اونم اینه که این دو تا میدلویر ، کاری با status code ها ندارن و کلا روال کارشون ثابته و فرقی براشون بین استاتوس کد 400 و 500 (بطور مثال) وجود نداره.

برای حل مشکل بالا میتونیم از میدلویر StatusCodePages استفاده کنیم.

خب بطور مثال کد زیر رو در نظر بگیرید.

public class HomeController : Controller
{
    public IActionResult Problem()
    {
        return StatusCode(500);
    }  
}



توی این کد یک Action تعریف کردیم به نام problem که statusCode 500 رو برمیگردونه. این تابع statusCode داره یک statusCodeResult برمیگردونه و ورودیش یک int هست که همون statuscode هست .(البته میشه object ای هم بهش به عنوان پارامتر دوم پاس داد که اگر این کارو بکنیم نوع بازگشتی ObjectResult میشه). برای نوع بازگشتی این اکشن هم میشه از IActionResult استفاده کرد که والد همه این نوع هاست (حالا ن دقیقا خودش بلکه فرزند هاش ، مثلا StatusCodeResult داره ارثبری میکنه از کلاس ActionResult که خود ActionResult هم داره IActionResult رو پیاده سازی میکنه).

خب بریم سراغ ادامه بحث.

حالا توی متد Configure می خوایم بریم.

public void Configure(IApplicationBuilder app)
{
    app.UseStatusCodePages();

    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
   {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
   });
}  



خب چیز خاصی برای توضیح نیست. یک سری میدلویر قرار دادیم صرفا.

حالا اگر یک ریکوست به یک محل اشتباه بزنیم ، به صفحه زیر مواجه میشیم.

این خطا ، توسط میدلویر UseStatusCodePages ایجاد شده.

حالا اگر ریکوست خودمون رو به اکشن Problem ای که ایجاد کرده بودیم بزنیم ، با صفحه دگ ای مواجه میشیم که در زیر می بینید.

خب مشخصا می بینیم که این دو خطا متفاوت از هم نشون داده شدن.

خب ، الان مشکلی که توی دو تصویر بالا دیدیم چی هست؟

صفحه دیفالت ساخته میشه و قابلیت custom کردن رو نداریم. برای حل این مشکل می تونیم از دو تا میدلویر دگ استفاده کنیم. اولی UseStatusCodePagesWithRedirects و دومی UseStatusCodePagesWithReExecute هست. خروجی این دو تا متد تقریبا یکی هست و جفتشون بهمون این اجازه رو میدن که صفحات error شخصی سازی شده ای رو برای کاربر هامون ایجاد کنیم. (ولی بطور معمول از re-execute استفاده می کنیم که جلوتر دلیلش رو میگم).

تصویر زیر داخل UseStatusCodePagesWithRedirects اتفاق می افته.

ریکوست به یک محل ارسال میشه از سمت کاربر. اون اکشن ، اکسپشن صادر میکنه (status code 500). بعدش در زمان برگشت ، موقعی که دوباره به میدلویر UseStatusCodePagesWithRedirects می رسیم ، میاد و اون status code رو از 500 به 302 (ریدایرکت) تغییر میده و آدرس محلی که باید مرورگر کاربر به اون ریدایرکت کنه (یعنی اون صفحه ارور ما ) رو هم داخلش قرار میده. حالا توی مرحله بعدی ، مرورگر بصورت خودکار یک ریکوست به اون صفحه مربوطه میزنه و صفحه شخصی سازی شده ما با Status code 200 به کاربر برگشت داده میشه.

در حقیقت ما در روش بالا ، بار اول به کاربر ارور رو نمیدیم. کاربر رو مجبور میکنیم که یک ریکوست دگ هم به سایت بده و بعد ارور رو بهش نمایش میدیم.

خب حالا میخوایم بریم سراغ روش دوم یعنی Re-Execute. نحوه کارش در تصویر زیر قابل مشاهده هست.


خب توی این روش ، ریکوست از سمت کاربر میاد (به یک اکشنی که اکسپشن قراره صادر کنه برامون) ، بعدش از میدلویر ها میگذره و وارد اون اکشن میشه و اکسپشن صادر میشه . حالا توی مسیر برگشت وقتی به میدلویر UseStatusCodePagesWithReExecute رسید ، این میدلویر دوباره ریکوست رو به همون pipeline برمیگردونه ولی این بار مسیرش رو ، مسیر error ای که ما تنظیم کردیم میده. اون صفحه ارور به درستی ساخته میشه و به همراه status code 200 به کاربر برگشت داده میشه.

خب مشخصا این روش بهتره و این کاملا واضح هست.

نکته ای که درباره این میدلویر وجود داره اینه که باید ، اونو قبل از میدلویر UseRouting قرار بدید که وقتی ریکوست رو دوباره generate میکنه ، Route مربوط به ارور انتخاب بشه .

public void Configure(IApplicationBuilder app)
{
    app.UseStatusCodePagesWithReExecute(&quot/Home/Error&quot, &quot?statusCode={0}&quot);
    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
   {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
   });
}  

خب ، کد بالا فقط اون میدلویر اولی جای صحبت کردن داره . به عنوان اولین ورودی بهش محلی که باید بهش ریکوست ارسال بشه رو میدیم (توی مثال بالا کنترلر home و اکشن error) و بعدشم می تونیم بهش کوری استرینگ پاس بدیم. که اینجا ما statusCode رو پاس دادیم. بطور کلی داخل این میدلویر هر جا ما {0} placeHolder رو قرار بدیم، اون رو با StattusCode مربوطه جایگزین میکنه

کد زیر هم مربوط به اکشن error هست که ایجاد کردیم.

public class HomeController : Controller
{
    public IActionResult Error(int? statusCode = null)
    {
        if (statusCode.HasValue)
        {
            if (statusCode.Value == 404 || statusCode.Value == 500)
            {
                var viewName = statusCode.ToString();
                return View(viewName);
            }
        }
        return View();
    }
}



این مقاله ای که خوندید ترجمه (با مقداری تغییر و تحریف در اصل متن و اپدیت کردن بخش هاییش ) از سایت آقای andrewlock بود .

امیدوارم مفید براتون بوده باشه.


مقالات بیشتر در دات نت زوم

https://t.me/DotNetZoom