PDA

View Full Version : طریقه ی ایجاد Custom ErrorHandle در ASP.NET MVC



alishokr
چهارشنبه 03 آذر 1389, 19:17 عصر
در پستی با عنوان طریقه ی استفاده از فیلتر HandleError (http://barnamenevis.org/showthread.php?t=260102) استفاده از فیلتر HandleError رو بررسی کردیم .
در روش قبل ، امکان Log کردن خطاها وجود نداشت . در این پست قصد داریم طریقه ی پیاده سازی یک فیلتر Custom جهت کنترل exception ها و Log کردن اون ها رو بررسی کنیم .
ابتدا یک کلاس با نام CustomErrorHandle بسازید و و از کلاس FilterAttribute و اینترفیس IExceptionFilter ارث بری کنید و متد OnException اینترفیس رو پیاده سازی کنید. بشکل زیر:


public classCustomErrorHandle : FilterAttribute, IExceptionFilter






{


publicvoid OnException(ExceptionContext filterContext)
{
 
 
}
}




حالا ما میتونیم در داخل متد OnException بگیم که چطور خطا رو کنترل کنه .
کاری که ما میخوایم بکنیم این هست که :
ابتدا خطا رو در EventLog ویندوز ثبت کنیم
بعد صفحه ای رو با پیغام "An Exception occured" نمایش داده و در اون صفحه لینک بازگشت به صفحه ای که خطا در اون اتفاق افتاده رو قرار بدیم .
برای این کار در Solution Explorer ، در شاخه ی Views/Shared ، صفحه ای جدید با نام Message اضافه میکنیم.(در این مثال من از ASP.NET MVC 3 استفاده میکنم، شما میتونید از MVC2 استفاده کنید. اصل تفاوت در استفاده از Razor هست .)
http://up.iranblog.com/Files0/65e3d401bfad4ca3be3d.gif

حالا در شاخه ی Models ، کلاس جدیدی با نام Message اضافه کرده و پراپرتی های زیر رو به این کلاس اضافه میکنیم :





publicclassMessage






{


publicstring MessageContent { get; set; }


publicstring ActionName { get; set; }


publicstring ControllerName { get; set; }


publicstring AreaName { get; set; }
}




حالا صفحه ی Message رو بازکرده و کد زیر رو به صفحه اضافه کنید :


Razor view engine:
@model Mvc3.Models.Message


ASPX view engine:
<%@ Page Language="C#‎‎‎" Inherits="System.Web.Mvc.ViewPage<Mvc3.Models.Message>" %>

http://up.iranblog.com/Files0/ec9b4258ac17474b8c5d.gif

دقت کنید ، بجای Mvc3 شما میبایست نام پروژه خودتون رو قرار بدید .
حالا در قسمت Body کد زیر رو وارد کنید:


<div>
<p>Message: @Model.MessageContent</p>
@Html.ActionLink("Return", Model.ActionName,
Model.ControllerName,
new { area = Model.AreaName },
null);
</div>


http://up.iranblog.com/Files0/970a79e65a2f465dbde1.gif

حالا میمونه اصل کد ، که میبایست در داخل متد OnException قرار بدیم:


if (filterContext.ExceptionHandled) //1
return;
var actionName = filterContext.RouteData.Values["action"].ToString();//2
var controllerName = filterContext.RouteData.Values["controller"].ToString();//2
var areaName = filterContext.RouteData.DataTokens["area"] == null
? null
: filterContext.RouteData.DataTokens["area"].ToString(); //3

var eLog = new EventLog(string.Empty, ".") //4
{Source = "Application"};
eLog.WriteEntry(filterContext.Exception.Message, EventLogEntryType.Error);


filterContext.ExceptionHandled = true; //5
filterContext.Result = new ViewResult //6
{
ViewName = "Message",
ViewData = new ViewDataDictionary<Message>(new Message {
ActionName = actionName,
ControllerName = controllerName,
AreaName = areaName,
MessageContent = "An Exception Occured"})
};
filterContext.RequestContext.HttpContext.Response. ClearContent();//7

در آخر هر خط comment یی با یک شماره مشخص شده که در زیر در مورد هرکدوم توضیح میدم.
1. در این خط ما بررسی میکنیم که اگر exception توسط یک فیلتر دیگه Handle شده ، دیگه بررسی نکنه.
2. از مجموعه ی Values که در پراپرتی RouteData قرار داره مقدار action و controller رو بدست میاریم .
3. در صورتی که ما در پروژه مون از Area استفاده کرده باشیم ، نام Area در داخل DataTokens نگه داری میشه ، نه داخل Values .(همینطور نام Namespace هایی که ما برای route هامون تعیین میکنیم )
4. این قسمت هم که برای نوشتن خطا در EventLog قرار گرفته. شما میتونید بجای این دو خط ، کدی بنویسید تا بر فرض خطا رو برای ایمیلی ارسال کنه .
5. در این خط ما ExceptionHandled رو برابر با true قرار میدیم تا سایر فیلترهامون دیگه این خطا رو بررسی نکنن.
6. مقدار Result یی که میخوایم استفاده بشه رو تعیین میکنیم . در اینجا ما از ViewResult استفاده کردیم تا صفحه ی خطا رو نمایش بدیم . همونطور که در کد مشخص هست ، ما نام ViewName رو برابر با Message دادیم و ViewData رو از نوع Message گرفتیم (چون Model یی که برای صفحه Message انتخاب کردیم از نوع Message بود)
7. در این خط هم ، Response رو Clear کردیم تا در صورتی که چیزی برای خروجی رفته بود پاک بشه .

حالا برای تست ، ابتدا در web.config، قسمت customErrors رو قرار داده و mode رو برابر با On میکنیم.


<customErrors mode=”On” />

در Controllers یک کنترلر جدید با نام Default اضافه میکنیم .
در داخل اون دو Action Method با نام Index تعریف میکنیم ، به شکل زیر:


public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string buttonName)
{
throw new Exception("exception raised.");
}

حالا روی Index راست کلیک کرده و روی Add View کلیک میکنیم .
بعد از اضافه کردن View ، در داخل تگ Body کد زیر رو قرار میدیم.


Razor viewEngine:
@using (Html.BeginForm())
{


<inputtype="submit"value="Click me to raise an exception!"/>






}




ASPX View engine:

<% using(Html.BeginForm()) {%>


<inputtype="submit"value="Click me to raise an exception"/>






<% } %>




http://up.iranblog.com/Files0/a559cb1822424f8c9268.gif

حالا پروژه رو با CTRL + F5 اجرا میکنیم (یا در فایل web.config ، در قسمت compilation مقدار debug رو برابر با false قرار میدیم .)
حالا باید گفت ، آیا راه دیگه ای هم وجود داره ؟ بله .
کلاس Controller متدی داره با نام OnException که میتونیم overrideش کنیم و مثل همین فیلتر عمل میکنه .
اکثرا مواقعی استفاده میشه که بخواید برای Controllerیی منطق خاصی رو بکار ببرید که با سایر کنترلرهاتون متفاوت هست .
مثال زیر رو در نظر بگیرید:



public class DefaultController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
// place your logic.

}
}

البته شما میتونید یک کلاس Base تعریف کنید که از Controller ارث بری کنه و با override کردن متد OnException در کلاس Base ، سایر Controller هاتون رو از کلاس Base مشتق کنید و به نتیجه یکسانی برسید .

اینجا خوبه به یکی از ویژگی های جدید MVC3 اشاره کنم .
ممکنه شما پروژه ای رو به اتمام رسونده باشید و بخواید همچین روشی رو بروی پروژه تون اعمال کنید . یعنی یک فیلتر برای Handle کردن Exception ها بنویسید و بروی تمام Controller هاتون اعمال کنید .
مطابق با توضیحات بالا ، در حال حاضر دو روش داریم: یا روی تک تک کنترلرهامون این فیلتر رو اضافه کنیم یا یک کلاس پایه تعریف کنیم و بروی اون فیلتر رو اضافه کنیم و بعد تمام کنترلرهامون رو از اون مشتق کنیم .
در MVC3 روش جدید وجود داره . در داخل فایل global.asax ، تابع استاتیکی وجود داره با نام RegisterGlobalFilters که میتونیم در داخل اون ، فیلترهایی که بناست بروی تمام کنترلرها اعمال بشه قرار بدیم تا بصورت خودکار به تمامشون اعمال بشه .
یعنی برای اضافه کردن CustomErrorHandle خودمون ، بصورت زیر عمل میکنیم :


public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new Infrastructures.CustomErrorHandlerAttribute());
}


با آرزوی موفقیت ...

aserfg
یک شنبه 22 اسفند 1389, 09:03 صبح
دوست عزیز کدهات رو درست کن تا دوستان مشکلی در استفاده نداشته باشن
با تشکر