﻿
{"id":21386,"date":"2021-04-01T01:24:31","date_gmt":"2021-04-01T01:24:31","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=21386"},"modified":"2021-04-01T01:24:31","modified_gmt":"2021-04-01T01:24:31","slug":"asp-net-coreda-ki-exceptionlari-otomatik-olarak-yonetin","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-coreda-ki-exceptionlari-otomatik-olarak-yonetin\/","title":{"rendered":"Asp.NET Core&#8217;da ki Exception&#8217;lar\u0131 Otomatik Olarak Y\u00f6netin"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Asp.NET Core&#8217;da API geli\u015ftiriyorsan\u0131z e\u011fer a\u015fa\u011f\u0131daki yap\u0131lanman\u0131n size olduk\u00e7a tan\u0131d\u0131k geldi\u011finden eminim:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public IActionResult Get(int id)\r\n        {\r\n            var product = _productService.GetById(id);\r\n            if (product == null)\r\n                return NotFound();\r\n            return Ok(product);\r\n        }\r\n<\/pre>\n<p>Bu koda \u015f\u00f6yle bir g\u00f6z att\u0131\u011f\u0131n\u0131zda yanl\u0131\u015f bir \u015fey g\u00f6rebiliyor musunuz? Pek de\u011fil dimi? Sadece id baz\u0131nda bir product&#8217;\u0131 sorgulayan ve ilgili nesne geldi\u011fi taktirde geriye d\u00f6nd\u00fcren aksi taktirde &#8216;NotFound&#8217; ile hata d\u00f6nd\u00fcren bir action g\u00f6rmekteyiz. Bu gayet do\u011fal bir kodlama gibi g\u00f6z\u00fckebilir. Keza \u00f6yledir. Lakin, her bir action&#8217;da bu ve bunun gibi nesnelerin olmad\u0131\u011f\u0131 durumlar\u0131 kontrol etmek ve bu kontrol neticesine g\u00f6re kodumuzu in\u015fa etmek esas\u0131nda s\u00fcrekli kendimizi tekrar etmemiz anlam\u0131na gelmeyecek mi? Ayr\u0131ca bu tarz bir durumda, nesnenin null geldi\u011fi anlarda loglama yapmak istersek, her operasyonda ayr\u0131 ayr\u0131 ama ayn\u0131 kodlar\u0131 yazmam\u0131z gerekmeyecek mi?<\/p>\n<p>Bununla birlikte, buradaki operasyonda i\u015f katman\u0131 olarak sorumluluk \u00fcstlenen servisin ilgili id&#8217;ye kar\u015f\u0131l\u0131k sorgulama neticesinde herhangi bir nesnenin gelmedi\u011fi durumlarda buradaki problem kontrol\u00fcn\u00fc farkl\u0131 bir katman olan controller&#8217;a ta\u015f\u0131mas\u0131 yersiz ve sa\u00e7ma bir i\u015fleyi\u015f olmayacak m\u0131? Nihayetinde i\u015f mant\u0131\u011f\u0131n\u0131 y\u00fcr\u00fcten katman, gelen id&#8217;ye kar\u015f\u0131l\u0131k bir nesne bulunmad\u0131\u011f\u0131 taktirde bir exception f\u0131rlatarak mimariyi uyarmas\u0131 daha cazip olacakt\u0131r, \u00f6yle de\u011fil mi? \ud83d\ude42<\/p>\n<p>\u00d6yleyse bu koddan nesne kontrol\u00fcn\u00fc kald\u0131rmay\u0131 ve ayn\u0131 zamanda kendimizi tekrar ettirecek olan bu tarz durumlar\u0131 daha merkezi hale getirmeyi sorgulamal\u0131y\u0131z&#8230; Peki bunu nas\u0131l yapaca\u011f\u0131z? Cevap : Asp.NET Core mimarisinin damar yollar\u0131ndan biri olan, Action Filter&#8217;lard\u0131r&#8230;<\/p>\n<h3>Asp.NET Core&#8217;da &#8216;Filter&#8217; Tam Olarak Nedir?<\/h3>\n<p>Asp.NET Core&#8217;da &#8216;Filter&#8217;lar, request pipeline&#8217;\u0131n\u0131n belirli a\u015famalar\u0131ndan \u00f6nce veya sonra herhangi bir kodu \u00e7al\u0131\u015ft\u0131rman\u0131n yollar\u0131ndan biridir. C# dilinde bu filter&#8217;lar attribute olarak tasarlanmaktad\u0131r. Asp.NET Core&#8217;da bir\u00e7ok filter olmas\u0131na ra\u011fmen yukar\u0131da belirtildi\u011fi gibi, at\u0131lan exception&#8217;a g\u00f6re tetiklenecek olan filter <code style=\"color:red;font-size:11px;\">ExceptionFilterAttribute<\/code>&#8216;d\u0131r.<\/p>\n<p>\u015eimdi gelin, h\u0131zl\u0131 bir \u015fekilde basit bir \u00f6rnek ger\u00e7ekle\u015ftirelim.<\/p>\n<p>&#8216;Product&#8217; entity&#8217;si:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Product\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n    }\r\n<\/pre>\n<p>&#8216;ProductService&#8217; s\u0131n\u0131f\u0131 ve &#8216;IProductService&#8217; aray\u00fcz\u00fc:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public interface IProductService\r\n    {\r\n        Product GetById(int id);\r\n    }\r\n    public class ProductService : IProductService\r\n    {\r\n        List&lt;Product&gt; _products = new()\r\n        {\r\n            new() { Id = 1, Name = &quot;Book&quot; },\r\n            new() { Id = 2, Name = &quot;Pencil&quot; }\r\n        };\r\n        public Product GetById(int id)\r\n        {\r\n            var product = _products.FirstOrDefault(p =&gt; p.Id == id);\r\n            return product;\r\n        }\r\n    }\r\n<\/pre>\n<p>\u015eimdiye kadar ihtiyac\u0131m\u0131z olan tek \u015fey, &#8216;ProductService&#8217; i\u00e7erisindeki &#8216;GetById&#8217; metodunda ilgili id&#8217;ye kar\u015f\u0131l\u0131k herhangi bir nesnenin gelip gelmedi\u011fini kontrol etmek ve gelmedi\u011fi taktirde hata f\u0131rlatmakt\u0131r. Bunun i\u00e7in f\u0131rlat\u0131lacak exception&#8217;\u0131 custom olarak tasarlamakta fayda vard\u0131r.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class DataNotFoundException : Exception\r\n    {\r\n        public DataNotFoundException(string type, object id)\r\n            : base($&quot;{type} t\u00fcr\u00fcndeki {id} id de\u011ferine sahip olan obje bulunamad\u0131! &quot;) { }\r\n    }\r\n<\/pre>\n<p>Ve art\u0131k bahsedilen kontrol\u00fc &#8216;GetById&#8217; fonksiyonunda ger\u00e7ekle\u015ftirebiliriz:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public Product GetById(int id)\r\n        {\r\n            var product = _products.FirstOrDefault(p =&gt; p.Id == id);\r\n            if (product == null)\r\n                throw new DataNotFoundException(nameof(Product), id);\r\n            return product;\r\n        }\r\n<\/pre>\n<h3>Custom ExceptionFilterAttribute Olu\u015fturma<\/h3>\n<p>Yukar\u0131da tasarland\u0131\u011f\u0131 gibi id&#8217;ye kar\u015f\u0131l\u0131k herhangi bir nesne olmad\u0131\u011f\u0131 taktirde hata f\u0131rlat\u0131lacakt\u0131r. Dolay\u0131s\u0131yla bu hataya kar\u015f\u0131l\u0131k devreye girecek filtreyi custom olarak olu\u015fturmam\u0131z gerekmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]\r\n    public class ExceptionFilter : ExceptionFilterAttribute\r\n    {\r\n        public async override Task OnExceptionAsync(ExceptionContext context)\r\n        {\r\n            \/\/F\u0131rlat\u0131lan exception'\u0131n status code'unu bilemedi\u011fimiz durumda \r\n            \/\/default olarak '500 Internal Server Error'\u0131 belirliyoruz.\r\n            var statusCode = HttpStatusCode.InternalServerError;\r\n\r\n            \/\/F\u0131rlat\u0131lan exception DataNotFoundException ise\r\n            \/\/status code'u '404 Not Found' yap\u0131yoruz.\r\n            if (context.Exception is DataNotFoundException)\r\n                statusCode = HttpStatusCode.NotFound;\r\n\r\n            \/\/Bu request'e kar\u015f\u0131l\u0131k verilecek response'a status code'u ve\r\n            \/\/result'u de\u011fi\u015ftirerek d\u00f6nebiliriz.\r\n            context.HttpContext.Response.ContentType = &quot;application\/json&quot;;\r\n            context.HttpContext.Response.StatusCode = (int)statusCode;\r\n\r\n            context.Result = new JsonResult(new\r\n            {\r\n                error = new&#x5B;] { context.Exception.Message },\r\n                statusCode = (int)statusCode,\r\n                stackTrace = context.Exception.StackTrace\r\n            });\r\n        }\r\n    }\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere, hata esnas\u0131nda devreye girecek action filter&#8217;\u0131m\u0131z yukar\u0131daki gibidir. Tabi bu daha da \u00f6zelle\u015ftirilebilir lakin bizler \u015fimdilik bu kadarla yetinece\u011fiz. \u015eimdi geriye kalan tek \u015fey Asp.NET Core mimarisini olu\u015fturulan bu filtre hakk\u0131nda bilgilendirmektir. Bunun i\u00e7in iki farkl\u0131 y\u00f6ntem se\u00e7ebiliriz.<\/p>\n<ul>\n<li><strong><em>1. Y\u00f6ntem &#8211; Filter Olarak Global Ekleme<\/em><\/strong><br \/>\nBir filter&#8217;\u0131 global olarak ekleyebilmek i\u00e7in &#8216;Startup.cs&#8217; dosyas\u0131 i\u00e7erisindeki &#8216;AddControllers&#8217; servisinde a\u015fa\u011f\u0131daki gibi bildirmek yeterlidir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Startup\r\n    {\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddControllers(options =&gt; options.Filters.Add(typeof(ExceptionFilter)));\r\n            .\r\n            .\r\n            .\r\n        }\r\n        .\r\n        .\r\n        .\r\n    }\r\n<\/pre>\n<p>Global olarak eklenen filter&#8217;lar t\u00fcr\u00fcne \u00f6zg\u00fc t\u00fcm eylem durumlar\u0131nda tetiklenmektedirler. Dolay\u0131s\u0131yla bir filter&#8217;\u0131 sadece \u00f6zelle\u015ftirilmi\u015f durumlarda kullanmak istiyorsan\u0131z 2. y\u00f6ntem&#8217;i tercih etmeniz gerekmektedir.\n<\/li>\n<li><strong><em>2. Y\u00f6ntem &#8211; Attribute Olarak Controller yahut Action Bazl\u0131 Ekleme<\/em><\/strong><br \/>\nOlu\u015fturulan filter \u00f6z\u00fcnde bir attribute oldu\u011fu i\u00e7in bu \u015fekilde de kullan\u0131labilmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        &#x5B;HttpGet(&quot;{id}&quot;)]\r\n        &#x5B;ExceptionFilter]\r\n        public IActionResult Get(int id)\r\n        {\r\n            var product = _productService.GetById(id);\r\n            return Ok(product);\r\n        }\r\n<\/pre>\n<p>Bu kullan\u0131m, yap\u0131sal olarak daha tercih edilebilir bir davran\u0131\u015f sergilememizi sa\u011flamakta ve gereksiz yerlerden ilgili filtrenin tetiklenmesini ar\u0131nd\u0131rmaktad\u0131r.\n<\/li>\n<\/ul>\n<h3>Test Edelim<\/h3>\n<p>\u0130\u015fte bu kadar&#8230; \u015eimdi tek yapmam\u0131z gereken bu API&#8217;ye istek g\u00f6ndererek test etmek.<\/p>\n<table>\n<thead>\n<tr style=\"color:red;\">\n<th width=\"50%\">\/api\/Products\/1 <span style=\"color:black;\">ya da<\/span> \/api\/Products\/2\n<\/th>\n<th>\n\/api\/Products\/3<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin.png\" alt=\"Asp.NET Core&#039;da ki Exception&#039;lar\u0131 Otomatik Olarak Y\u00f6netin\" width=\"419\" height=\"203\" class=\"aligncenter size-full wp-image-21399\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin.png 419w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin-300x145.png 300w\" sizes=\"auto, (max-width: 419px) 100vw, 419px\" \/><\/a><\/td>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin-1.png\" alt=\"Asp.NET Core&#039;da ki Exception&#039;lar\u0131 Otomatik Olarak Y\u00f6netin\" width=\"758\" height=\"406\" class=\"aligncenter size-full wp-image-21400\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin-1.png 758w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Asp.NET-Coreda-ki-Exceptionlari-Otomatik-Olarak-Yonetin-1-300x161.png 300w\" sizes=\"auto, (max-width: 758px) 100vw, 758px\" \/><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere i\u015f mant\u0131\u011f\u0131nda \u00fcretilecek olan datan\u0131n kontrol sorumlulu\u011funu bir filter arac\u0131l\u0131\u011f\u0131yla merkezi hale getirip sonraki action&#8217;lar da ki ihtiyaca istinaden \u00e7\u0131kabilecek kod israf\u0131n\u0131 \u00f6nlemi\u015f olduk&#8230;<\/p>\n<p>Ve tabi daha profesyonel bir yakla\u015f\u0131m oldu\u011fu da a\u015fikar \ud83d\ude09<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek projeyi indirebilmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/AutomaticallyExceptionsExample.zip\" rel=\"noopener noreferrer\" target=\"_blank\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Asp.NET Core&#8217;da API geli\u015ftiriyorsan\u0131z e\u011fer a\u015fa\u011f\u0131daki yap\u0131lanman\u0131n size olduk\u00e7a tan\u0131d\u0131k geldi\u011finden eminim: public IActionResult Get(int id) { var product = _productService.GetById(id); if (product == null) return NotFound(); return Ok(product); } Bu koda \u015f\u00f6yle&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":3014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2739,3033,3101],"tags":[4213,4214,4215,4216],"class_list":["post-21386","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-net-core-3-0","category-net-core-3-1","tag-action-filter","tag-asp-net-core-action-filter","tag-asp-net-core-filters","tag-exceptionfilterattribute"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21386","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=21386"}],"version-history":[{"count":16,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21386\/revisions"}],"predecessor-version":[{"id":21405,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21386\/revisions\/21405"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/3014"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=21386"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=21386"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=21386"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}