مدیریت خطاها (Exception) در ASP.Net MVC

دوشنبه 27 مهر 1394

دراین مقاله ، مدیریت خطاها در MVC را خواهیم آ موخت که احتمال به وجود آمدن خطا در اجرای یک برنامه همیشه است.مدیریت خطا یه روند پاسخگو است که در زمان وقوع شرایط خاص، نیازمند پردازش خاص می باشد.

مدیریت خطاها (Exception) در ASP.Net MVC

مدیریت خطا و استثنا (Exception) در هر برنامه مهم است. در ASP.Net ما می توانیم خطاها را به دو روش زیر مدیریت کنیم:

-بلاک های try-catch-finally

-استفاده از Application_Error

در ASP.Net MVC راه های بیشتری برای مدیریت خطاها داریم:

- Try-catch-finally

- دوباره نویسی (override)متد OnException

- استفاده از ویژگی HandleError در اکشن ها(action) و کنترل ها(controller)

- Setting a global exception handling filter

- رویداد مدیریت Application_Error

-گسترش ویژگی HandleError

برای شروع ، یک برنامه empty ASP.Net ایجاد کنید. و یک کنترلر (controller) به عنوان "Exception TestingController" اضافه کنید. یک View برای Index و یکی هم در "View\Shared" به عنوان "Error.cshtml" اضافه کنید.

برای تست کردن هدف، ما به تعدادی استثنا نیاز داریم. 

try-catch-finally

قسمت کد زیر را در متد اکشن Index اضافه کنید:

public ActionResult Index()  
{  
    int a = 1;  
    int b = 0;  
    int c = 0;  
    try  
    {  
        c = a / b; //it would cause exception.  
    }  
    catch (Exception ex)  
    {  
        return View("Error");  
    }  
    finally  
    {   
    }  
    return View();  
}  

در اینجا کدهایی که احتمال دارد خطا تولید کنند و موجب بروز استثنا شوند ";c=a / b" در داخل بلوک try قرار می دهیم و نوع برخورد با هر نوع خطا را در بلوک catch مشخص می کنیم که View پیغام "Error" را برمی گرداند که اگر برنامه را اجرا کنید، می توانید یک صفحه خطا را در مرورگر دریافت کنید. همچنین درپروژه های واقعی ما می توانیم از بلوک catch برای اطلاعات گزارش گیری خطا استفاده کنیم.برای لذا پس از هر بلوک try می تواند یک یا چند بلوک catch قرار بگیرد. هر بلوک catch میتواند حاوی پردازشگر استثنا باشد که اگر استثنا با یکی از پارامترهای مورد استفاده در بلوک catch مطابقت داشته باشد هنگام بروز خطا، برنامه به طور خودکار کدهای بلوک catch را اجرا می کند. اگر خطایی در بلوک try رخ ندهد، هیچ بلوک catch اجرا نخواهد شد. بلوک finally قسمتی است که کدهای ادامه دهنده، برنامه را می توان در آن نوشت که معمولا برای پاکسازی و آزاد کردن حافظه به کار میرود.

دوباره نویسی (override)متدOnException:

در اینجا برای حذف بلوک try از کد قبلی ما نیاز به بازنویسی OnException داریم که توسط رویداد OnException میتوانیم به خطاهای تولیدشده در سطح یک کنترلر دسترسی داشته باشیم و آن را مدیریت کنیم.

public ActionResult Index()  
{  
    int a = 1;  
    int b = 0;  
    int c = 0;  
    c = a / b; //it would cause exception.             
    return View();  
}  
  
protected override void OnException(ExceptionContext filterContext)  
{  
    string action = filterContext.RouteData.Values["action"].ToString();   
    Exception e = filterContext.Exception;  
    filterContext.ExceptionHandled = true;  
    filterContext.Result = new ViewResult()  
    {  
        ViewName = "Error"  
    };  
} 

OnException متد تهی که یک آرگومان را به عنوان یک شی از ExceptionContext می گیرد و تمام اطلاعات مورد استثنا را برای گزارش گیری استفاده می کند. برای تنظیم شی ExceptionContext باید ExceptionHandled=true قرار دهیم. گرفتن نام action از ExceptionContext در کد زیر :

string action = filterContext.RouteData.Values["action"].ToString();   

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

استفاده از ویژگی HandleError:

این روش یک راه ساده برای مدیریت استثنا در MVC است. اجرای OnException از کد قبلی حذف شد که در واقع برای انجام این کار از روش زیر استفاده می کنیم:

مرحله اول :

در web.config زیر<system.web> کد <customErrors mode="on> را اضافه کنید.

مرحله دوم :

اضافه کردن action با [HandleError] :

[HandleError]  
public ActionResult Index()  
{  
   int a = 1;  
   int b = 0;  
   int c = 0;  
   c = a / b; //it would cause exception.   
   return View();  
}  

ما می توانیم خطاهای مختلف را برای View های مختلف با استفاده از [HandleError] مدیریت کنیم.

[HandleError]  
[HandleError(ExceptionType = typeof(DivideByZeroException), View = "Error1")]  
[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "Error2")]  
public ActionResult Index()  
 {  
     int a = 1;  
     int b = 0;  
     int c = 0;  
     c = a / b; //it would cause exception.             
     return View();  
 }  

در اینجا ما باید یک HandleError خاص در پایین قرار دهیم، اگر ما به سفارش یکی از ویژگی HandleError معکوس پیش برویم Error.cshtml همیشه نمایش داده خواهد شد.

در این راه ما می توانیم Controller خود را با handleError بسازیم، این استثنای تولید شده مسئولیت رسیدگی به تمام اقدامات از یک Controller خاص است.

محدودیت ها :

1-یک Exception ورود به سایت را پشتیبانی نمی کند.

2-یک Exception, بیش از 500 نمی گیرد.

3-Exception خارج از controllers نمی گیرند

4-بازگرداندن یک نمایش خطا برای مطرح شدن Exception در صدا زدن Ajax

Setting a global exception handling filter

برای اطمینان بیشتر ما نیاز داریم که ویژگی HandleError را به RegisterGlobalFilter اضافه نماییم ،فایل  FilterConfig در App_start که در Application_Start ثبت شده است، بنابر این نیازی نیست که در Action ,Controllerبا یک HandleError باشد.

گسترش ویژگی HandleError :

در کد زیر مدیریت استثنا راکه از HandleErrorAttribute ارث میبرد ،ایجاد کنید.

public class MyExceptionHandler : HandleErrorAttribute  
{  
     public override void OnException(ExceptionContext filterContext)  
     {  
          if (filterContext.ExceptionHandled ||filterContext.HttpContext.IsCustomErrorEnabled)  
           {  
               return;  
           }  
           Exception e = filterContext.Exception;  
           filterContext.ExceptionHandled = true;  
           filterContext.Result = new ViewResult()  
           {  
               ViewName = "Error2"  
           };  
    }  
} 

ما نیاز به تنظیم ExceptionHandled واقعی برای شی ExceptionContext داریم.ما می توانیم تمام Exception های تولید شده از تمام Action  ها از یک Controller خاص اداره کنیم.ما می توانیم هم چنین از Action ExceptionContext به صورت زیر استفاده کنیم:

string action = filterContext.RouteData.Values["action"].ToString();   

حالا ما می توانیم Action/Controller را با My ExceptionHandler به صورت زیر استفاده کنیم:

[MyExceptionHandler]  
public ActionResult Index()  
{  
    int a = 1;  
    int b = 0;  
    int c = 0;  
    c = a / b; //it would cause exception.             
    return View();  
}  

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

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

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید