مدیریت و کنترل global exception با استفاده از C# web api

مدیریت و کنترل global exception با استفاده از C# web api

مدیریت استثناها (Exceptions) در سی‌شارپ یا زبان‌های برنامه‌نویسی دیگر یکی از وظایف مهم برنامه‌نویسان است. برنامه‌ای را تصور کنید که در آن کاربران با خطاهای عجیب و غریبی روبرو می‌شوند یا برنامه به دلیل وجود خطاها متوقف می‌شود. این مشکل به این دلیل به وجود می‌آید که برنامه‌نویس در زمان نوشتن برنامه فراموش کرده استثناها را بررسی کند. 

به‌طور معمول، کاربران در هنگام کار با برنامه‌های کاربردی، اگر با خطاهای مختلفی روبرو شوند، برنامه را کنار می‌گذارند و به سراغ نمونه‌های مشابه می‌روند. رویکردی که باعث می‌شود برنامه‌ی شما با شکست روبرو شود. خوشبختانه، برنامه‌نویسان به راهکار قدرتمند مدیریت استثناها دسترسی دارند که مانع از آن می‌شود تا خطاها باعث خاتمه‌ی ناگهانی برنامه‌های کاربردی شوند. در این مقاله، قصد داریم نحوه‌ی مدیریت استثناها در برنامه‌های سی‌شارپ را با استفاده از مکانیزم کنترل global exception  یا به عبارت دقیق‌تر واسط برنامه‌نویسی کاربردی وب سی‌شارپ (C# Web API) بررسی کنیم و همچنین به بررسی این موضوع می‌پردازیم که استثناها و خطاها در سی‌شارپ چه مفاهیمی هستند و راههای رسیدگی به استثناها چیست. 

خطا در مقابل استثناها در سی شارپ

خطاها (Errors) و استثناها (Expiations) مفاهیمی هستند که برخی توسعه‌دهندگان به عنوان مترادف از آن‌ها استفاده می‌کنند، با این‌حال، این دو مفهوم تفاوت‌های مشخصی دارند. یک خطا زمانی اتفاق می‌افتد که منابع سیستم کم یا در دسترس نیستند. استثناها به دلیل مشکل داخلی در برنامه ایجاد می‌شوند، به‌طور مثال، فرض کنید در یک فیلد ورودی که قرار است مقدار عددی در آن وارد شود، یک مقدار رشته‌ای توسط کاربر وارد شود و برنامه پردازش را روی آن رشته انجام دهد. در چنین شرایطی اگر برنامه‌نویس، پیش‌بینی‌های لازم را انجام نداده باشد، برنامه با نمایش پیغام خطایی متوقف می‌شود. برای رفع هر گونه ابهام، بهتر است، هر یک از این مفاهیم و تفاوت‌های آن‌ها را به دقت بررسی کنیم. 

خطاها در سی‌شارپ

خطاها در سی‌شارپ مشکلات یا به عبارت دقیق‌تر خرابی‌های (Failures) پیچیدهای هستند که خارج از توانایی‌های یک برنامه‌نویس هستند، زیرا به دلیل کمبود یا در دسترس نبودن منابع، کمبود حافظه‌ی اصلی، سرریز پشته (stack overflow) و موارد مشابه به وجود می‌آیند. از آن‌جایی که برنامه‌نویسان نمی‌توانند با استفاده از راهکارهای رایج سی‌شارپ به مقابله با خطاها بپردازند، این خطاها، غیرقابل حل توصیف می‌شوند. 

به‌طور مثال، شما یک برنامه‌ی کاربردی نوشته‌اید که آزمایش‌‌های مختلف را با موفقیت پشت سر گذاشته و روی سیستم‌های مختلف به خوبی اجرا شده است. با این‌حال، هنگامی که برنامه به شکل سراسری توزیع می‌شود، کاربری روی یک سیستم قدیمی آن‌را اجرا می‌کند یا وابستگی‌های (Dependencies) برنامه روی سیستم نصب نیست و برنامه با نمایش پیغام خطایی متوقف می‌شود یا گاهی اوقات نسخه‌های جدیدی از کیت توسعه (SDK) منتشر می‌شوند که برخی قابلیت‌های قدیمی را حذف یا تغییراتی در آن‌ها اعمال کرده‌اند. در چنین شرایطی اگر برنامه‌ی شما به‌روز نشده باشد، با پیغام خطایی متوقف می‌شود. 

مدیریت استثنا در سیشارپ

به طور معمول، استثناها به دلیل کدنویسی غیر دقیق در سی‌شارپ به وجود می‌آیند. به‌طور مثال، در بخشی از برنامه قرار است فایلی باز شود، در صورتی که فایل روی دیسک وجود ندارد. در این حالت، برنامه استثنایی تولید می‌کند که اشاره به این موضوع دارد که فایل وجود ندارد. بر خلاف خطاها، استثناها قابل بازیابی هستند، به این معنا که امکان مدیریت آن‌ها وجود داردو می‌توان جریان برنامه را به گونه‌ای مدیریت کرد تا به کار خود ادامه دهد. در مدیریت استثناها در سی‌شارپ، برنامه‌نویسان از روش try، catch و block استفاده می‌کنند.

چگونه استثناها در زبان برنامه‌نویسی سی‌شارپ را مدیریت کنیم؟ 

اکنون که تفاوت میان خطاها و استثناها را بررسی کردیم، وقت آن رسیده است تا ببینیم چگونه باید استثناها را مدیریت کنیم. برای مدیریت استثنا اجازه دهید روی ASP.NET Web API تمرکز کنیم. ASP.NET که توسط مایکروسافت برای ساخت برنامه های کاربردی وب یا وب سایتهای پویا توسعه یافته است، یک فریمورک وب منبع باز است. این فریمورک با استفاده از زبان برنامه‌نویسی سی‌شارپ اجرا می‌شود.

هنگامی که یک استثنا در یک Web API دریافت می‌شود، استثنا به یک پاسخ HTTP ترجمه می‌شود که کد وضعیت 500 به معنای «خطای سرور داخلی» را نشان می‌دهد. اکنون که اطلاعات کلی در این زمینه به دست آوردیم، به چه صورتی باید استثنای فوق را مدیریت کنیم؟

ASP.NET Web API چیست؟

ASP.NET Web API چارچوبی است که فرآیند ساخت سرویسهای HTTP که امکان استفاده از آن‌ها توسط طیف گسترده‌ای از کلاینت‌ها مثل مرورگرها و دستگاه‌های موبایل وجود دارد را ساده می‌کند. ASP.NET Web API یک پلتفرم ایدهآل برای ساخت برنامه‌های RESTful بر روی فریم‌ورک دات‌نت است. یکی از قابلیت‌های کاربردی ASP.NET Web API در ارتباط با مدیریت خطاها است. 

HTTP Exception

شی HttpError راهکاری در اختیار برنامه‌نویسان قرار می‌دهد تا اطلاعات دقیقی در ارتباط با خطاها به دست آورند. برای پیادهسازی مکانیزم فوق، باید از تابع CreateErrorResponseکه یک متد توسعه یافته (Extension Method) است، استفاده کنید. کاری که تابع فوق انجام می‌دهد، این است که نمونه‌ای از شی HttpError را ایجاد کرده و در ادامه شی بازگشتی HttpResponseMessageرا باز می‌گرداند. قطعه کد زیر نحوه‌ی انجام این‌کار را نشان می‌دهد.

public HttpResponseMessage Get([FromODataUri] int key)
{
    Product data = context.Product.Where(k => k.Id == key).FirstOrDefault();
    if (data == null)
    {
        string message = string.Format("No Product found with ID = {0}", key);
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
    }
    return Request.CreateResponse(HttpStatusCode.OK, data); 
}

در قطعه کد بالا، اگر در دستور شرطی مقدار data غیر تهی باشد، متد Request.CreateResponse مقداری در قالب پاسخ HTTP باز می‌گرداند، در غیر این صورت، پاسخ HTTP در قالب شی HttpError که بیان‌گر اطلاعات خطا (No Product found with ID) است، بازگردانده می‌شود.

HttpResponseException

اگر تجربه‌ی برنامه‌نویسی به زبان سی‌شارپ را داشته باشید، به خوبی از این نکته اطلاع دارید که در شبه کد بالا،  متد HttpResponseException یک action controller از نوع HttpResponseMessage  که دربرگیرنده شی HttpError است را باز می‌گرداند، اما برنامه‌نویسان سی‌شارپ می‌توانند با استفاده از HttpResponseMessage استثنایی تولید کنند که حالت HttpStatusCode در سازنده استثنا را بازگرداند.

throw new HttpResponseException(HttpStatusCode.NotFound);

اگر به دنبال کنترل بهتر و دقیق‌تری روی پاسخ هستید، بهتر است از مکانیزم ساخت پیام کامل به شرح زیر استفاده کنید:

public Product Get([FromODataUri] int key)
{
    Product data = context.Product.Where(k => k.Id == key).FirstOrDefault();
 
    if (data == null)
    {
        var response = newHttpResponseMessage(HttpStatusCode.NotFound)
        {
            Content = newStringContent(string.Format("No Product found with ID = {0}", key)),
                ReasonPhrase = "Product Not Found"
        };
         throw new HttpResponseException(response);
    }
    return data;
}

فیلترهای سراسری استثنا - Global Exception Filters

فیلترهای استثنا این امکان را فراهم می‌کنند تا نحوه‌ی مدیریت Web API را با نوشتن کلاس فیلتر استثنا، سفارشی کنید. در این حالت، فیلترهای فوق، استثناهای کنترل نشده در Web API را دریافت می‌کنند. هنگامی که متدی یک استثنای کنترل نشده ایجاد می‌کند، به طور خودکار فیلتر فوق اجرا می‌شود. با این حال، فیلتر exception توانایی رسیدگی به استثنا HttpresponseExecutionرا ندارد، زیرا استثنا HttpresponseExecution  با هدف بازگرداندن شی HttpResponse طراحی شده است.

شما می‌توانید از فیلتر exception، زمانی استفاده کنید، که کنترلر متد یک استثنای کنترل نشده‌ای تولید می‌کند که از نوع HttpResponseExeption نیست. قطعه کد زیر نحوه‌ی مدیریت این استثنا را نشان می‌دهد. 

namespace WebAPITest
{
    using System.Net;
    using System.Net.Http;
    using System.Web.Http.Filters;
 
    public class CustomExceptionFilter: ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContextactionExecutedContext)
        {
            string exceptionMessage = string.Empty;
            if (actionExecutedContext.Exception.InnerException == null)
            {
                exceptionMessage = actionExecutedContext.Exception.Message;
            }
            else
            {
                exceptionMessage = actionExecutedContext.Exception.InnerException.Message;
            }
            //We can log this exception message to the file or database.
            var response = newHttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = newStringContent(“An unhandled exception was thrown by service.”),
                    ReasonPhrase = "Internal Server Error.Please Contact your Administrator."
            };
            actionExecutedContext.Response = response;
        }
    }
}

همان‌گونه که مشاهده می‌کنید، فیلتر Exception به برنامه‌نویسان سی‌شارپ اجازه می‌دهد، به سفارشی‌سازی مدیریت خطاها برای کنترلرها پرداخته و کدهای خاصی را برای مدیریت خطاها بنویسند. 

کنترل‌کننده/اداره‌کننده استثنای سراسری (Global Exception Handler)

اکنون از این نکته اطلاع داریم که فیلتر استثنا (Exception filter) نمی‌تواند استثناهای کنترل نشده را مدیریت کند. در این‌جا، استثناهایی وجود دارند که خارج از action هستند که از آن جمله باید به Error در exception filter، Exception مرتبط با مسیریابی، Exception درون کلاس Message handler و Exception در سازنده‌ی کنترلر اشاره کرد. 

هنگامی که با چنین حالت‌های خاصی روبرو می‌شوید، به اداره ‌کننده‌های، استثنا نیاز داریم. خوشبختانه Web API 2 می‌تواند یک کنترل‌کننده‌ی استثنای سراسری در C# Web API پیادهسازی کند. به بیان دقیق‌تر، واسط‌ برنامه‌نویسی کاربردی وب، ExceptionHandler را ارائه می‌دهد که IExceptionHandler را پیادهسازی می کند. برای پیادهسازی ExceptionHandler می ‌توانید از قطعه کد زیر استفاده کنید:

namespace WebAPITest
{
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http.ExceptionHandling;
    using System.Web.Http.Results;
    public class GlobalExceptionHandler: ExceptionHandler
    {
        public async override TaskHandleAsync(ExceptionHandlerContext context, CancellationTokencancellationToken)
        {
            // Access Exception using context.Exception;
            const string errorMessage = "An unexpected error occured";
            var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError,
                new
                {
                    Message = errorMessage
                });
            response.Headers.Add("X-Error", errorMessage);
            context.Result = new ResponseMessageResult(response);
        }
    }
}

نکته‌ی مهمی که باید به آن دقت کنید این است که کنترل ‌کننده یا همان اداره‌ کننده استثنا باید ثبت شده باشد. واسط‌های برنامه‌نویسی کاربردی وب دارای یک کلاس اداره‌ کننده استثنا هستند، اما از رویکرد چند اداره ‌کننده استثنا (multiple exception handlers) پشتیبانی نمی‌کنند. بنابراین، باید کلاس موجود را با کلاس اداره‌کننده استثنای سفارشی خود جایگزین کنید.

Retrace اجازه می‌دهد استثناهای سی‌شارپ را پیدا کرده و مدیریت کنید.

Retrace یک راه‌حل نظارتی جامع بر عملکرد برنامه‌ی کاربردی (APM) مخفف application performance monitoring ارائه می‌دهد. به بیان دقیق‌‌تر، چند ابزار را در قالب یک ابزار ترکیب می‌کند تا امکان نظارت بر سرور در سطح کد، پروفایل عملکرد، نظارت بر برنامه، ردیابی خطا و موارد دیگر وجود داشته باشد.

لازم به توضیح است که به طور سنتی، ابزارهای APM، مثل بیشتر برنامه‌های کاربردی قبل از ظهور راه‌حل های SaaS (نرم‌افزار به عنوان یک راه‌حل)، بر روی سرورها و ماشینهای توسعه‌دهندگان نصب می‌شوند. با این حال، با محبوبیت بیشتر راه‌حل‌های SaaS، این ابزارها به فضای ابری انتقال پیدا کرده‌اند.

یکی از ویژگی‌های منحصر به فرد، Retrace نظارت بر خطا است. با استفاده از Retrace، می‌توانید استثناهای سی شارپ را در برنامه خود بدون آن‌که کدها با مشکل جدی روبرو شوند، جمع‌آوری کنید. بله درست خواندید. شما می‌توانید استثناها را بدون اعمال تغییر در کد‌ها دریافت کنید.

اگر کافی نیست، باید بگوییم که Retrace با تمام برنامه‌های ASP.NET کار می‌کند و از این‌رو امکان استفاده از آن با MVC، WCF، Web API، NET Core و غیره وجود دارد. 

Retrace از مکانیزم ورود به سیستم از طریق زبان نشانه‌گذاری اثبات امنیتی SAML مخفف Security Assertion Markup Language و احراز هویت دو مرحله‌ای پشتیبانی می‌کند و به نقش‌های امنیتی (security roles) جزیی اجازه می‌دهد از برنامه‌های کاربردی شما محافظت کنند. برای بهره‌مندی از قابلیت‌های Retrace، باید APM+ agent را روی سروری که برنامه‌ی شما را میزبانی می‌کند، نصب کنید. پس از نصب APM+ agent بر روی سرور و فعال شدن آن، داده‌های پروفایل برنامه برای ابزار فوق ارسال می‌شود. برای اطلاعات بیشتر در ارتباط با ابزار Retrace به این آدرس مراجعه کنید. 

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس