Herhangi bir yazılım projesinde Exception alındığında bu exception'nın handle edilip belli başlı bazı süreçlerden geçirilip log atılmasına kadar geçen süreçler oldukça önemlidir ve enterprise bir projede development yapıyor isek ExceptionLog olmazsa olmazlardan biridir. Projeye yeni başlarken mimarisi ilk düşünülüp tasarlanması gerekir çünkü proje ilerledikçe log, exception handling veya cache gibi yapıları entegre etmek biraz daha zorlaşacaktır.
Web Api tarafında Exception handling ve log işlemleri yapmak biraz daha keyifli ve basit diyebiliriz çünkü Microsoft sağolsun bazı şeyleri bizim yerimize düşünüp kolaylaştırmış.
İlk olarak şöyle bir controller metodumuz olsun ve bu metoda requestte bulunduğumuzda ne gibi bir response ile karşılaşıyoruz onu görelim.
[HttpGet]
public IHttpActionResult CheckValue(int value)
{
if(value > 20)
{
throw new ArgumentOutOfRangeException();
}
return Ok(value);
}
Herhangi bir 3th party tool (DHC, Postman etc.) kullanarak ilgili metoda parametresi "10" olacak şekilde request attığımızda respose olarak göndermiş olduğumuz "10" değerini status code 200 - OK olacak şekilde döner.
Aynı requesti parametre "25" olacak şekilde attığımızda ise yukarıda fırlattığımız "ArgumentOutOfRangeException" hata açıklamasını status code 500 - Internal Server Error olacak şekilde döner.
Uygulamada controller seviyesinde bir exception aldığımızda olması gereken exception'nın handle edilip kullanıcıya doğrudan Exception class'ından fırlatılan hata mesajı değilde(ihtiyaca göre) ilgili daha anlamlandırılmış bir şekli response'a eklenip client'a dönüyor olması ve bu exception'nın log olarak bir yerde tutuluyor olması gerekir.
Yukarıda bahsettiğimiz gibi WebApi için Exception alındığında Log işleminin yapılmasını için kullanıma sunulan abstract class ve onun metodlarını inceleyeceğiz.
1.Logging ExceptionLogger class Log metodunu kullanarak uygulamadaki herhangi bir exception'nın loglanmasını sağlayabiliriz. Bunun için aşağıda UnhandledExceptionLogger isimli class'ımızı kullanarak ilerleyeceğiz.
public class UnhandledExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
var log = context.Exception.ToString();
//Loglama için ilgili ilemlerin yapıldığı yer (db log, file log vs gibi)
}
}
Üstte tanımladığımız UnhandledExceptionLogger class'ını Web Api projesinde kullanabilmek için register etmemiz gerekmekte. Register işlemi ile birlikte WebApi nin otomatik olarak default set ettiği ExceptionLogger'ı kendi yazdığımız UnhandledExceptionLogger class'ı ile değiştiriyoruz. Bu işlem için aşağıdaki kodu Global.asax.cs içerisindeki Application_Start metoduna yazıyoruz.
config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
Bu adımdan sonra uygulamada bir unhandled exception fırlatıldığı anda logger'ımız onu yakalayıp yazmak istediğimiz bir yere (db, file etc.) yazmamızı sağlayacaktır.
2.Excepiton Hander Bu kısımda uygulamamızda fırlatılmış olan exception'nı yakalayıp response da değiştirmek istediğimiz yerleri değiştirip client'a dönme işlemlerini yapacağız. Bunun için ExceptionHandler class'ından faydalanacağız. Bu class ExceptionLogger ve ExceptionFilter dan sonra eğer ilgili exception handle edilmediyse çağrılır. GlobalExceptionHandler ismindeki class'ımız aşağıdaki gibi olacaktır.
public class GlobalExceptionHandler : ExceptionHandler
{
/// <summary>
/// This function is used for to change the response when an exception occurs.
/// </summary>
/// <param name="context"></param>
public override void Handle(ExceptionHandlerContext context)
{
var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message),
};
context.Result = new ExceptionActionResult(result);
}
}
Yukarıda exception fırlatıldığında yakalaıp client'a dönen response'u modify ettik. Bunun için kendi custom yazdığımız ExceptionActionResult class'ını kullanacağız. O da aşağıdaki gibi olacaktır.
/// <summary>
/// This class is a kind of Custom Action Result. When we get any exception and want to handle the web api method that returns HttpActionResult, we can use this class and it's functions.
/// </summary>
public class ExceptionActionResult : IHttpActionResult
{
private HttpResponseMessage _httpResponseMessage;
public ExceptionActionResult(HttpResponseMessage httpResponseMessage)
{
_httpResponseMessage = httpResponseMessage;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_httpResponseMessage);
}
}
Şimdi sırada 1.Adımda da yaptığımız gibi yazış olduğumuz Handler'ı WebApi'nin default set ettiğiyle değiştirme işlemi var bunu da Global.asax.cs içerisindeki Application_Start metodunda aşağıdaki gibi yapıyoruz.
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
Uygulamamız hazır. Bu entegrasyondan sonra uygulamamıza 2 şey kazandırmış olduk.
- Exception alındığında Log atma işlemi
- Fırlatılan unhandled exception'ı yakalayıp kendi yazdığımız custom HttpActionResult ile değiştirip client'a giden respons'u daha anlamlı ve yönetilebilir bir hale getirmiş olduk.
Yazımızın en başında yazmış olduğumuz CheckValue metoduna veya uygulamada herhangi bir metoda request'te bulunup exception fırlatıldığında artık bütün response'lar artık şu şekilde olacaktır.
StatusCode : 500 Internal Server Error
Body : Specified argument was out of the range of valid values.
Gördüğünüz üzre projede exception alındığında log'umuzu atıp client'a dönen response'u da daha anlamlı bir hale getirmiş olduk.
Ben örnek uygulamada response dönerken statusCode HttpStatusCode.InternalServerError yani 500 set ettim ancak siz projenizde kullanırken daha farklı statusCode'lar da ihtiyaca göre client'a dönebilirsiniz.
=> http://www.exceptionnotfound.net/the-asp-net-web-api-exception-handling-pipeline-a-guided-tour/