{"id":39246,"date":"2026-02-17T13:00:47","date_gmt":"2026-02-17T10:00:47","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/"},"modified":"2026-02-17T13:00:47","modified_gmt":"2026-02-17T10:00:47","slug":"asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/","title":{"rendered":"ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi"},"content":{"rendered":"<h2>ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi<\/h2>\n<p>Webhook&#8217;lar, modern da\u011f\u0131t\u0131k sistemlerin bel kemi\u011fini olu\u015fturan, uygulamalar aras\u0131 ger\u00e7ek zamanl\u0131 ileti\u015fimi sa\u011flayan g\u00fc\u00e7l\u00fc ara\u00e7lard\u0131r. Ancak, a\u011fdaki dalgalanmalar, g\u00f6nderici sistemin yeniden deneme mekanizmalar\u0131 veya di\u011fer beklenmedik durumlar nedeniyle ayn\u0131 webhook olay\u0131n\u0131n birden fazla kez al\u0131nmas\u0131 s\u0131k\u00e7a kar\u015f\u0131la\u015f\u0131lan bir sorundur. Bu durum, uygulaman\u0131zda istenmeyen yan etkilere, veri tutars\u0131zl\u0131klar\u0131na ve hatal\u0131 i\u015flem sonu\u00e7lar\u0131na yol a\u00e7abilir. Bu makalede, ASP.NET Core uygulamalar\u0131n\u0131zda tekrarlayan webhook olaylar\u0131n\u0131 nas\u0131l etkili bir \u015fekilde y\u00f6netece\u011finizi, &#8220;idempotens&#8221; kavram\u0131n\u0131 temel alarak detayl\u0131 stratejiler ve uygulama y\u00f6ntemleri ile ele alaca\u011f\u0131z.<\/p>\n<h3>Webhook Olay Tekrarlar\u0131n\u0131n Nedenleri<\/h3>\n<p>Webhook olaylar\u0131n\u0131n birden fazla kez g\u00f6nderilmesi, genellikle sistemlerin do\u011fas\u0131nda bulunan veya d\u0131\u015f etkenlerden kaynaklanan \u00e7e\u015fitli nedenlere dayan\u0131r. Bu nedenleri anlamak, do\u011fru idempotens stratejilerini geli\u015ftirmek i\u00e7in kritik \u00f6neme sahiptir.<\/p>\n<h4>A\u011f Gecikmeleri ve Kesintileri<\/h4>\n<p>\u0130nternet ba\u011flant\u0131s\u0131 veya sunucu aras\u0131ndaki a\u011fda meydana gelen k\u0131sa s\u00fcreli kesintiler veya y\u00fcksek gecikmeler, webhook g\u00f6ndericisinin yan\u0131t\u0131 alamamas\u0131na neden olabilir. G\u00f6nderici, yan\u0131t alamad\u0131\u011f\u0131 i\u00e7in olay\u0131n ba\u015far\u0131yla i\u015flenmedi\u011fini varsayarak ayn\u0131 olay\u0131 tekrar g\u00f6ndermeyi deneyebilir. Bu durum, \u00f6zellikle y\u00fcksek y\u00fckl\u00fc veya co\u011frafi olarak da\u011f\u0131n\u0131k sistemlerde s\u0131k\u00e7a ya\u015fan\u0131r.<\/p>\n<h4>G\u00f6nderici Taraf\u0131 Yeniden Deneme Mekanizmalar\u0131<\/h4>\n<p>\u00c7o\u011fu webhook sa\u011flay\u0131c\u0131s\u0131, olaylar\u0131n al\u0131c\u0131ya ba\u015far\u0131yla ula\u015ft\u0131\u011f\u0131ndan emin olmak i\u00e7in yerle\u015fik yeniden deneme (retry) mekanizmalar\u0131na sahiptir. Al\u0131c\u0131 uygulama bir hata kodu (\u00f6rne\u011fin, 5xx sunucu hatas\u0131) d\u00f6nd\u00fcrd\u00fc\u011f\u00fcnde veya belirli bir s\u00fcre i\u00e7inde yan\u0131t vermedi\u011finde, g\u00f6nderici olay\u0131 belirli aral\u0131klarla ve genellikle \u00fcstel geri \u00e7ekilme (exponential backoff) stratejisiyle yeniden dener. Bu, al\u0131c\u0131 taraf\u0131nda ge\u00e7ici bir sorun oldu\u011funda olay\u0131n ka\u00e7\u0131r\u0131lmamas\u0131n\u0131 sa\u011flasa da, al\u0131c\u0131n\u0131n asl\u0131nda olay\u0131 ba\u015far\u0131yla i\u015fledi\u011fi ancak yan\u0131t\u0131n g\u00f6ndericiye ula\u015fmad\u0131\u011f\u0131 senaryolarda tekrarlara yol a\u00e7ar.<\/p>\n<h4>Da\u011f\u0131t\u0131k Sistemlerin Do\u011fas\u0131<\/h4>\n<p>Mikroservis mimarileri veya di\u011fer da\u011f\u0131t\u0131k sistemlerde, bir i\u015flemin birden fazla bile\u015fen aras\u0131nda koordine edilmesi gerekebilir. Bu karma\u015f\u0131k etkile\u015fimler s\u0131ras\u0131nda, bir bile\u015fenin durumu yanl\u0131\u015f raporlamas\u0131 veya bir ileti\u015fimin kaybolmas\u0131, olay\u0131n birden fazla kez tetiklenmesine neden olabilir. \u00d6rne\u011fin, bir veritaban\u0131 i\u015flemi ba\u015far\u0131l\u0131 olsa bile, bu ba\u015far\u0131n\u0131n webhook g\u00f6ndericiye bildirilmesi ba\u015far\u0131s\u0131z olabilir ve g\u00f6nderici olay\u0131 tekrar tetikleyebilir.<\/p>\n<h4>Yanl\u0131\u015f Yap\u0131land\u0131r\u0131lm\u0131\u015f Webhook Kay\u0131tlar\u0131<\/h4>\n<p>Nadir durumlarda, bir geli\u015ftiricinin ayn\u0131 webhook URL&#8217;sini birden fazla kez kaydetmesi veya yanl\u0131\u015fl\u0131kla ayn\u0131 olay i\u00e7in birden fazla webhook tan\u0131m\u0131 olu\u015fturmas\u0131, sistemin ayn\u0131 olay\u0131 birden fazla kez g\u00f6ndermesine neden olabilir. Bu, genellikle yap\u0131land\u0131rma hatalar\u0131ndan kaynaklan\u0131r ve kolayca d\u00fczeltilebilir olsa da, ba\u015flang\u0131\u00e7ta tekrarlayan olaylara yol a\u00e7abilir.<\/p>\n<h3>\u0130dempotens Nedir ve Neden \u00d6nemlidir?<\/h3>\n<p>\u0130dempotens, da\u011f\u0131t\u0131k sistemlerde g\u00fcvenilirli\u011fi sa\u011flamak i\u00e7in temel bir kavramd\u0131r. Bir i\u015flemin veya iste\u011fin birden fazla kez uygulanmas\u0131n\u0131n, tek bir kez uygulanmas\u0131yla ayn\u0131 sonucu vermesi durumunu ifade eder.<\/p>\n<h4>\u0130dempotens Kavram\u0131n\u0131n Tan\u0131m\u0131<\/h4>\n<p>Matematikte, bir fonksiyonun kendi kendine uygulanmas\u0131yla ayn\u0131 sonucu vermesi durumudur (f(f(x)) = f(x)). Bilgisayar bilimlerinde ise, bir i\u015flemin birden fazla kez \u00e7a\u011fr\u0131lmas\u0131n\u0131n sistemin durumu \u00fczerinde tek bir \u00e7a\u011fr\u0131yla ayn\u0131 etkiye sahip olmas\u0131 anlam\u0131na gelir. \u00d6rne\u011fin, bir kullan\u0131c\u0131 hesab\u0131na 10 TL ekleme i\u015flemi idempotens de\u011fildir (iki kez \u00e7a\u011fr\u0131l\u0131rsa 20 TL ekler). Ancak, bir kullan\u0131c\u0131n\u0131n bakiyesini 100 TL olarak ayarlama i\u015flemi idempotenttir (iki kez \u00e7a\u011fr\u0131lsa da bakiye yine 100 TL olur). Webhook senaryosunda, bir &#8220;sipari\u015f olu\u015fturuldu&#8221; olay\u0131n\u0131 i\u015flemek, ilk seferinde sipari\u015fi olu\u015fturmal\u0131, sonraki seferlerde ise mevcut sipari\u015fi tekrar olu\u015fturmaya \u00e7al\u0131\u015fmamal\u0131 veya mevcut sipari\u015fi g\u00fcncellemelidir.<\/p>\n<h4>\u0130\u015f S\u00fcreklili\u011fi ve Veri B\u00fct\u00fcnl\u00fc\u011f\u00fc<\/h4>\n<p>\u0130dempotens, sisteminizin tekrarlayan olaylar kar\u015f\u0131s\u0131nda bile do\u011fru ve tutarl\u0131 \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar. Tekrarlayan olaylar\u0131n hatal\u0131 bir \u015fekilde i\u015flenmesi, \u00f6rne\u011fin bir sipari\u015fin iki kez olu\u015fturulmas\u0131, bir kullan\u0131c\u0131n\u0131n bakiyesinin yanl\u0131\u015f art\u0131r\u0131lmas\u0131 veya bir e-postan\u0131n birden fazla kez g\u00f6nderilmesi gibi ciddi veri tutars\u0131zl\u0131klar\u0131na ve i\u015f s\u00fcre\u00e7lerinde aksakl\u0131klara yol a\u00e7abilir. \u0130dempotens, bu t\u00fcr senaryolar\u0131 engelleyerek veri b\u00fct\u00fcnl\u00fc\u011f\u00fcn\u00fc korur ve i\u015f s\u00fcreklili\u011fini garanti alt\u0131na al\u0131r.<\/p>\n<h4>Kullan\u0131c\u0131 Deneyimi ve Sistem G\u00fcvenilirli\u011fi<\/h4>\n<p>Veri tutars\u0131zl\u0131klar\u0131 do\u011frudan k\u00f6t\u00fc bir kullan\u0131c\u0131 deneyimine yol a\u00e7ar. Bir kullan\u0131c\u0131, ayn\u0131 eylemin tekrar tekrar ger\u00e7ekle\u015ftirildi\u011fini veya yanl\u0131\u015f sonu\u00e7lar do\u011furdu\u011funu g\u00f6r\u00fcrse sisteme olan g\u00fcvenini kaybeder. \u0130dempotens, sisteminizin beklenmedik durumlar kar\u015f\u0131s\u0131nda bile g\u00fcvenilir bir \u015fekilde \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flayarak kullan\u0131c\u0131lar\u0131n olumlu bir deneyim ya\u015famas\u0131n\u0131 ve sistemin genel g\u00fcvenilirli\u011fini art\u0131r\u0131r.<\/p>\n<h3>\u0130dempotens \u0130\u00e7in Temel Stratejiler ve Yakla\u015f\u0131mlar<\/h3>\n<p>Webhook olaylar\u0131n\u0131 idempotent hale getirmek i\u00e7in \u00e7e\u015fitli stratejiler ve yakla\u015f\u0131mlar mevcuttur. Bu yakla\u015f\u0131mlar, olay\u0131n benzersizli\u011fini tan\u0131mlamak ve i\u015flenip i\u015flenmedi\u011fini takip etmek \u00fczerine kuruludur.<\/p>\n<h4>Benzersiz Kimlik Kullan\u0131m\u0131 (Idempotency Key)<\/h4>\n<p>En yayg\u0131n ve etkili stratejilerden biri, her webhook olay\u0131 i\u00e7in benzersiz bir kimlik (Idempotency Key) kullanmakt\u0131r. Bu kimlik genellikle webhook g\u00f6ndericisi taraf\u0131ndan sa\u011flan\u0131r ve HTTP ba\u015fl\u0131klar\u0131nda (\u00f6rne\u011fin, <code>Idempotency-Key<\/code> veya <code>X-Request-ID<\/code>) veya istek g\u00f6vdesinde yer al\u0131r. Al\u0131c\u0131 taraf\u0131nda, bu kimlik kullan\u0131larak olay\u0131n daha \u00f6nce i\u015flenip i\u015flenmedi\u011fi kontrol edilir.<\/p>\n<p>*   <strong>Nas\u0131l \u00c7al\u0131\u015f\u0131r:<\/strong><br \/>\n    1.  Webhook geldi\u011finde, <code>Idempotency-Key<\/code> de\u011feri al\u0131n\u0131r.<br \/>\n    2.  Bu anahtar, bir depolama biriminde (veritaban\u0131, \u00f6nbellek vb.) daha \u00f6nce g\u00f6r\u00fcl\u00fcp g\u00f6r\u00fclmedi\u011fi kontrol edilir.<br \/>\n    3.  E\u011fer anahtar daha \u00f6nce g\u00f6r\u00fclmediyse, olay i\u015flenir ve anahtar depolama birimine &#8220;i\u015flendi&#8221; durumuyla kaydedilir.<br \/>\n    4.  E\u011fer anahtar daha \u00f6nce g\u00f6r\u00fcld\u00fcyse, olay g\u00f6z ard\u0131 edilir veya \u00f6nceki i\u015flemin sonucu d\u00f6nd\u00fcr\u00fcl\u00fcr.<\/p>\n<h4>Durum Takibi ve \u0130\u015flem Atomisitesi<\/h4>\n<p>Baz\u0131 durumlarda, webhook olay\u0131n\u0131n kendisi i\u00e7inde benzersiz bir kimlik bulunmayabilir veya olay\u0131n i\u015flenmesi birden fazla ad\u0131mdan olu\u015fabilir. Bu senaryolarda, i\u015flenen varl\u0131klar\u0131n durumunu takip etmek ve t\u00fcm i\u015flemi atomik hale getirmek \u00f6nemlidir. \u00d6rne\u011fin, bir sipari\u015fin durumu &#8220;olu\u015fturuldu&#8221;dan &#8220;\u00f6dendi&#8221;ye ge\u00e7ti\u011finde, bu durumu veritaban\u0131nda g\u00fcncelleyerek tekrarlayan &#8220;\u00f6dendi&#8221; olaylar\u0131n\u0131n ayn\u0131 de\u011fi\u015fikli\u011fi tekrar yapmas\u0131n\u0131 engelleyebilirsiniz. \u0130\u015flemlerin atomik olmas\u0131, ya tamamen ba\u015far\u0131l\u0131 olmas\u0131 ya da tamamen ba\u015far\u0131s\u0131z olmas\u0131 anlam\u0131na gelir; yar\u0131m kalm\u0131\u015f i\u015flemlerin sistemde tutars\u0131zl\u0131k yaratmas\u0131n\u0131 engeller.<\/p>\n<h4>Mesaj Kuyruklar\u0131 ve T\u00fcketici Gruplar\u0131<\/h4>\n<p>Y\u00fcksek hacimli veya karma\u015f\u0131k webhook i\u015fleme senaryolar\u0131nda, do\u011frudan HTTP isteklerini i\u015flemek yerine bir mesaj kuyru\u011fu (\u00f6rne\u011fin, RabbitMQ, Kafka, Azure Service Bus) kullanmak faydal\u0131 olabilir. Webhook iste\u011fi geldi\u011finde, ASP.NET Core uygulamas\u0131 olay\u0131 h\u0131zl\u0131ca kuyru\u011fa atar ve 200 OK yan\u0131t\u0131 d\u00f6ner. Daha sonra, ayr\u0131 bir t\u00fcketici (consumer) servisi kuyruktaki mesajlar\u0131 i\u015fler.<\/p>\n<p>*   <strong>Avantajlar\u0131:<\/strong><br \/>\n    *   <strong>Asenkron \u0130\u015fleme:<\/strong> Webhook yan\u0131t s\u00fcresini k\u0131salt\u0131r.<br \/>\n    *   <strong>Y\u00fck Dengeleme:<\/strong> Birden fazla t\u00fcketici, kuyruktaki mesajlar\u0131 paralel olarak i\u015fleyebilir.<br \/>\n    *   <strong>Hata Tolerans\u0131:<\/strong> T\u00fcketici servisi \u00e7\u00f6kerse, mesajlar kuyrukta kal\u0131r ve servis yeniden ba\u015flad\u0131\u011f\u0131nda i\u015flenir.<br \/>\n    *   <strong>\u0130dempotens:<\/strong> Kuyruk sistemleri genellikle mesaj kimlikleri veya t\u00fcketici gruplar\u0131 arac\u0131l\u0131\u011f\u0131yla idempotens sa\u011flamaya yard\u0131mc\u0131 olur. Her mesaj\u0131n benzersiz bir kimli\u011fi varsa, t\u00fcketici bu kimli\u011fi kullanarak mesaj\u0131n daha \u00f6nce i\u015flenip i\u015flenmedi\u011fini kontrol edebilir.<\/p>\n<h3>ASP.NET Core&#8217;da \u0130dempotens Uygulama Y\u00f6ntemleri<\/h3>\n<p>ASP.NET Core uygulamalar\u0131nda idempotensi sa\u011flamak i\u00e7in \u00e7e\u015fitli teknikler ve ara\u00e7lar kullanabiliriz. Bu y\u00f6ntemler, genellikle bir <code>Idempotency-Key<\/code>&#8216;i depolama ve kontrol etme prensibine dayan\u0131r.<\/p>\n<h4>Webhook \u0130mza Do\u011frulamas\u0131 (G\u00fcvenlik \u00d6nceli\u011fi)<\/h4>\n<p>\u0130dempotens do\u011frudan tekrarlar\u0131 \u00f6nlemeye odaklan\u0131rken, webhook imza do\u011frulamas\u0131 gelen iste\u011fin ger\u00e7ekten beklenen g\u00f6ndericiden geldi\u011fini ve i\u00e7eri\u011finin de\u011fi\u015ftirilmedi\u011fini do\u011frular. Bu bir g\u00fcvenlik \u00f6nlemidir ve idempotens ile birlikte kullan\u0131lmal\u0131d\u0131r. \u00c7o\u011fu webhook sa\u011flay\u0131c\u0131s\u0131, g\u00f6nderilen her istekle birlikte bir imza (hash) g\u00f6nderir. Bu imza, gizli bir anahtar ve istek g\u00f6vdesi kullan\u0131larak olu\u015fturulur. Al\u0131c\u0131 taraf\u0131nda, ayn\u0131 algoritma ve anahtar kullan\u0131larak kendi imzan\u0131z olu\u015fturulur ve gelen imza ile kar\u015f\u0131la\u015ft\u0131r\u0131l\u0131r.<\/p>\n<pre><code class=\"language-csharp\">\/\/ \u00d6rnek: GitHub Webhook \u0130mza Do\u011frulamas\u0131\npublic class GitHubWebhookController : ControllerBase\n{\n    private readonly IConfiguration _configuration;\n\n    public GitHubWebhookController(IConfiguration configuration)\n    {\n        _configuration = configuration;\n    }\n\n    [HttpPost(\"github-webhook\")]\n    public async Task<IActionResult> HandleGitHubWebhook()\n    {\n        Request.EnableBuffering(); \/\/ \u0130stek g\u00f6vdesini birden fazla okumak i\u00e7in\n        using var reader = new StreamReader(Request.Body, leaveOpen: true);\n        var requestBody = await reader.ReadToEndAsync();\n        Request.Body.Position = 0; \/\/ G\u00f6vdeyi s\u0131f\u0131rla\n\n        var signatureHeader = Request.Headers[\"X-Hub-Signature-256\"].FirstOrDefault();\n        if (string.IsNullOrEmpty(signatureHeader))\n        {\n            return BadRequest(\"X-Hub-Signature-256 header missing.\");\n        }\n\n        var secret = _configuration[\"GitHub:WebhookSecret\"];\n        if (string.IsNullOrEmpty(secret))\n        {\n            throw new InvalidOperationException(\"GitHub Webhook Secret not configured.\");\n        }\n\n        var expectedSignature = $\"sha256={CalculateSignature(requestBody, secret)}\";\n\n        if (!signatureHeader.Equals(expectedSignature, StringComparison.OrdinalIgnoreCase))\n        {\n            return Unauthorized(\"Invalid GitHub Webhook signature.\");\n        }\n\n        \/\/ \u0130mza do\u011fruland\u0131, \u015fimdi Idempotency Key kontrol\u00fc ve i\u015fleme ge\u00e7ilebilir\n        \/\/ ...\n        return Ok();\n    }\n\n    private string CalculateSignature(string payload, string secret)\n    {\n        var secretBytes = Encoding.UTF8.GetBytes(secret);\n        var payloadBytes = Encoding.UTF8.GetBytes(payload);\n\n        using (var hmac = new HMACSHA256(secretBytes))\n        {\n            var hash = hmac.ComputeHash(payloadBytes);\n            return BitConverter.ToString(hash).Replace(\"-\", \"\").ToLowerInvariant();\n        }\n    }\n}<\/pre>\n<p><\/code><\/p>\n<h4>Veritaban\u0131 Tabanl\u0131 \u0130dempotens Kontrol\u00fc<\/h4>\n<p>En sa\u011flam ve g\u00fcvenilir idempotens y\u00f6ntemlerinden biri, gelen <code>Idempotency-Key<\/code>'leri bir veritaban\u0131nda depolamakt\u0131r. Bu y\u00f6ntem, uygulaman\u0131z\u0131n \u00f6l\u00e7eklenebilirli\u011fini ve kal\u0131c\u0131l\u0131\u011f\u0131n\u0131 sa\u011flar.<\/p>\n<p>*   <strong>Model:<\/strong><\/p>\n<pre><code class=\"language-csharp\">public class IdempotencyRecord\n    {\n        public string IdempotencyKey { get; set; } \/\/ Benzersiz anahtar\n        public DateTimeOffset ReceivedAt { get; set; }\n        public DateTimeOffset? ProcessedAt { get; set; }\n        public string RequestHash { get; set; } \/\/ \u0130ste\u011fin hash'i (opsiyonel, i\u00e7eri\u011fin de\u011fi\u015fmedi\u011fini do\u011frulamak i\u00e7in)\n        public string ResponseBody { get; set; } \/\/ \u0130lk i\u015flemin yan\u0131t\u0131 (opsiyonel)\n        public int StatusCode { get; set; } \/\/ \u0130lk i\u015flemin HTTP durumu (opsiyonel)\n        \/\/ Di\u011fer ilgili bilgiler\n    }<\/pre>\n<p><\/code><\/p>\n<p>*   <strong>Kontrol Mant\u0131\u011f\u0131:<\/strong><\/p>\n<pre><code class=\"language-csharp\">public async Task<IActionResult> HandleWebhookWithDbIdempotency([FromHeader(Name = \"Idempotency-Key\")] string idempotencyKey)\n    {\n        if (string.IsNullOrEmpty(idempotencyKey))\n        {\n            return BadRequest(\"Idempotency-Key header is required.\");\n        }\n\n        \/\/ Veritaban\u0131 ba\u011flam\u0131n\u0131z\u0131 veya repository'nizi enjekte edin\n        \/\/ _dbContext.IdempotencyRecords.AddAsync(...)\n        \/\/ _dbContext.SaveChangesAsync()\n\n        var existingRecord = await _dbContext.IdempotencyRecords\n                                             .FirstOrDefaultAsync(r => r.IdempotencyKey == idempotencyKey);\n\n        if (existingRecord != null)\n        {\n            \/\/ Olay daha \u00f6nce i\u015flenmi\u015f veya i\u015fleniyor.\n            \/\/ E\u011fer i\u015flem tamamlanm\u0131\u015fsa, \u00f6nceki yan\u0131t\u0131 d\u00f6nd\u00fcr\u00fcn (e\u011fer saklanm\u0131\u015fsa).\n            if (existingRecord.ProcessedAt.HasValue)\n            {\n                \/\/ \u00d6rne\u011fin, ilk i\u015flemin yan\u0131t\u0131n\u0131 saklad\u0131ysan\u0131z\n                \/\/ return StatusCode(existingRecord.StatusCode, existingRecord.ResponseBody);\n                return Ok(\"Webhook olay\u0131 daha \u00f6nce ba\u015far\u0131yla i\u015flendi.\");\n            }\n            else\n            {\n                \/\/ \u0130\u015flem hala devam ediyor olabilir (ayn\u0131 anda gelen \u00e7ift istek).\n                \/\/ Bu durumda bir \u00e7ak\u0131\u015fma hatas\u0131 d\u00f6nebilir veya bekleyebilirsiniz.\n                return Conflict(\"Webhook olay\u0131 \u015fu anda i\u015fleniyor.\");\n            }\n        }\n\n        \/\/ Yeni bir kay\u0131t olu\u015ftur ve veritaban\u0131na ekle (i\u015flemi ba\u015flatmadan \u00f6nce)\n        var newRecord = new IdempotencyRecord\n        {\n            IdempotencyKey = idempotencyKey,\n            ReceivedAt = DateTimeOffset.UtcNow,\n            \/\/ RequestHash = CalculateHash(Request.Body) \/\/ Opsiyonel\n        };\n\n        await _dbContext.IdempotencyRecords.AddAsync(newRecord);\n        await _dbContext.SaveChangesAsync();\n\n        try\n        {\n            \/\/ As\u0131l webhook i\u015fleme mant\u0131\u011f\u0131 burada\n            \/\/ ...\n            \/\/ \u00d6rnek: await _webhookProcessor.ProcessEventAsync(webhookPayload);\n\n            newRecord.ProcessedAt = DateTimeOffset.UtcNow;\n            newRecord.StatusCode = 200; \/\/ Ba\u015far\u0131l\u0131 durum kodu\n            \/\/ newRecord.ResponseBody = \"Ba\u015far\u0131l\u0131\"; \/\/ Yan\u0131t\u0131 sakla\n            await _dbContext.SaveChangesAsync();\n\n            return Ok(\"Webhook olay\u0131 ba\u015far\u0131yla i\u015flendi.\");\n        }\n        catch (Exception ex)\n        {\n            \/\/ Hata durumunda kayd\u0131 g\u00fcncelleyin veya silin\n            \/\/ \u00d6rne\u011fin, hata durumunda ProcessedAt'\u0131 null b\u0131rak\u0131p,\n            \/\/ bir hata mesaj\u0131 veya \u00f6zel bir durum kodu ekleyebilirsiniz.\n            _logger.LogError(ex, \"Webhook i\u015flenirken hata olu\u015ftu.\");\n            \/\/ newRecord.StatusCode = 500;\n            \/\/ newRecord.ResponseBody = ex.Message;\n            \/\/ await _dbContext.SaveChangesAsync();\n            return StatusCode(500, \"Webhook i\u015flenirken bir hata olu\u015ftu.\");\n        }\n    }<\/pre>\n<p><\/code><br \/>\n    Bu kod par\u00e7ac\u0131\u011f\u0131, <code>Idempotency-Key<\/code>'i HTTP ba\u015fl\u0131\u011f\u0131ndan al\u0131r, veritaban\u0131nda kontrol eder ve olay\u0131 i\u015fler. <code>ProcessedAt<\/code> alan\u0131, i\u015flemin tamamlan\u0131p tamamlanmad\u0131\u011f\u0131n\u0131 g\u00f6sterir.<\/p>\n<h4>Da\u011f\u0131t\u0131k \u00d6nbellek Kullan\u0131m\u0131 (Redis, Memcached)<\/h4>\n<p>Daha y\u00fcksek performans gerektiren senaryolarda veya veritaban\u0131 y\u00fck\u00fcn\u00fc azaltmak i\u00e7in da\u011f\u0131t\u0131k bir \u00f6nbellek (Redis, Memcached) kullan\u0131labilir. <code>Idempotency-Key<\/code>'ler, belirli bir ya\u015fam s\u00fcresi (TTL) ile \u00f6nbellekte saklan\u0131r.<\/p>\n<p>*   <strong>ASP.NET Core'da Kullan\u0131m:<\/strong> <code>Microsoft.Extensions.Caching.Distributed<\/code> paketi ile <code>IDistributedCache<\/code> aray\u00fcz\u00fcn\u00fc kullanabilirsiniz.<\/p>\n<pre><code class=\"language-csharp\">public class WebhookController : ControllerBase\n    {\n        private readonly IDistributedCache _cache;\n        private readonly ILogger<WebhookController> _logger;\n\n        public WebhookController(IDistributedCache cache, ILogger<WebhookController> logger)\n        {\n            _cache = cache;\n            _logger = logger;\n        }\n\n        [HttpPost(\"webhook-with-cache\")]\n        public async Task<IActionResult> HandleWebhookWithCacheIdempotency([FromHeader(Name = \"Idempotency-Key\")] string idempotencyKey)\n        {\n            if (string.IsNullOrEmpty(idempotencyKey))\n            {\n                return BadRequest(\"Idempotency-Key header is required.\");\n            }\n\n            var cacheKey = $\"idempotency:{idempotencyKey}\";\n            var cachedResult = await _cache.GetStringAsync(cacheKey);\n\n            if (!string.IsNullOrEmpty(cachedResult))\n            {\n                _logger.LogInformation($\"Idempotency key '{idempotencyKey}' already processed. Returning cached result.\");\n                \/\/ Burada \u00f6nbellekte saklanan \u00f6nceki yan\u0131t\u0131 d\u00f6nd\u00fcrebilirsiniz.\n                \/\/ \u00d6rne\u011fin, JSON olarak saklanm\u0131\u015f bir yan\u0131t\u0131 deserialize edip d\u00f6nd\u00fcrmek.\n                return Ok(cachedResult); \/\/ Basit\u00e7e string olarak d\u00f6nd\u00fcrelim\n            }\n\n            \/\/ Olay\u0131 i\u015fleme mant\u0131\u011f\u0131\n            try\n            {\n                _logger.LogInformation($\"Processing webhook with idempotency key: {idempotencyKey}\");\n                \/\/ As\u0131l webhook i\u015fleme mant\u0131\u011f\u0131 burada\n                \/\/ ...\n                await Task.Delay(100); \/\/ \u0130\u015flem sim\u00fclasyonu\n\n                var result = \"Webhook olay\u0131 ba\u015far\u0131yla i\u015flendi.\";\n\n                \/\/ \u0130\u015flem ba\u015far\u0131l\u0131 olduktan sonra Idempotency Key'i \u00f6nbelle\u011fe al\n                \/\/ Genellikle webhook tekrar deneme s\u00fcrelerinden daha uzun bir TTL ayarlan\u0131r.\n                var cacheEntryOptions = new DistributedCacheEntryOptions\n                {\n                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) \/\/ 30 dakika ge\u00e7erli\n                };\n                await _cache.SetStringAsync(cacheKey, result, cacheEntryOptions);\n\n                return Ok(result);\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, $\"Error processing webhook with idempotency key: {idempotencyKey}\");\n                return StatusCode(500, \"Webhook i\u015flenirken bir hata olu\u015ftu.\");\n            }\n        }\n    }<\/pre>\n<p><\/code><br \/>\n    <code>Startup.cs<\/code>'de Redis i\u00e7in yap\u0131land\u0131rma:<\/p>\n<pre><code class=\"language-csharp\">public void ConfigureServices(IServiceCollection services)\n    {\n        \/\/ ...\n        services.AddStackExchangeRedisCache(options =>\n        {\n            options.Configuration = Configuration.GetConnectionString(\"RedisCache\");\n            options.InstanceName = \"MyWebhookApp_\";\n        });\n        \/\/ ...\n    }<\/pre>\n<p><\/code><\/p>\n<h4>Middleware ile \u0130dempotens Kontrol\u00fc<\/h4>\n<p>\u0130dempotens kontrol mant\u0131\u011f\u0131n\u0131 her controller aksiyonuna tekrar tekrar yazmak yerine, bunu bir ASP.NET Core Middleware'i olarak uygulayabilirsiniz. Bu, kodu daha temiz ve yeniden kullan\u0131labilir hale getirir.<\/p>\n<pre><code class=\"language-csharp\">public class IdempotencyMiddleware\n{\n    private readonly RequestDelegate _next;\n    private readonly IDistributedCache _cache; \/\/ Veya IIdempotencyRepository\n\n    public IdempotencyMiddleware(RequestDelegate next, IDistributedCache cache)\n    {\n        _next = next;\n        _cache = cache;\n    }\n\n    public async Task InvokeAsync(HttpContext context)\n    {\n        if (!context.Request.Headers.TryGetValue(\"Idempotency-Key\", out var idempotencyKeyHeader))\n        {\n            await _next(context); \/\/ Idempotency-Key yoksa normal ak\u0131\u015fa devam et\n            return;\n        }\n\n        var idempotencyKey = idempotencyKeyHeader.ToString();\n        var cacheKey = $\"idempotency:{idempotencyKey}\";\n\n        var cachedResult = await _cache.GetStringAsync(cacheKey);\n\n        if (!string.IsNullOrEmpty(cachedResult))\n        {\n            context.Response.StatusCode = StatusCodes.Status200OK;\n            await context.Response.WriteAsync(cachedResult);\n            return;\n        }\n\n        \/\/ \u0130stek g\u00f6vdesini okuyabilmek i\u00e7in tamponlama\n        context.Request.EnableBuffering();\n        var originalBodyStream = context.Response.Body;\n        using var responseBody = new MemoryStream();\n        context.Response.Body = responseBody;\n\n        await _next(context); \/\/ \u0130stek i\u015flemeye devam et\n\n        \/\/ Yan\u0131t\u0131 yakala ve \u00f6nbelle\u011fe al\n        if (context.Response.StatusCode >= 200 && context.Response.StatusCode < 300)\n        {\n            responseBody.Seek(0, SeekOrigin.Begin);\n            var responseText = await new StreamReader(responseBody).ReadToEndAsync();\n\n            var cacheEntryOptions = new DistributedCacheEntryOptions\n            {\n                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)\n            };\n            await _cache.SetStringAsync(cacheKey, responseText, cacheEntryOptions);\n        }\n\n        responseBody.Seek(0, SeekOrigin.Begin);\n        await responseBody.CopyToAsync(originalBodyStream);\n    }\n}\n\n\/\/ Startup.cs'de middleware'i kaydetme\npublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n{\n    \/\/ ...\n    app.UseMiddleware<IdempotencyMiddleware>();\n    \/\/ ...\n}<\/pre>\n<p><\/code><br \/>\nBu middleware, <code>Idempotency-Key<\/code> ba\u015fl\u0131\u011f\u0131 olan istekleri yakalar, \u00f6nbelle\u011fi kontrol eder ve e\u011fer daha \u00f6nce i\u015flenmi\u015fse \u00f6nbellekten yan\u0131t\u0131 d\u00f6ner. Aksi takdirde, iste\u011fi i\u015fler ve ba\u015far\u0131l\u0131 yan\u0131t\u0131 \u00f6nbelle\u011fe al\u0131r.<\/p>\n<h3>Uygulama Detaylar\u0131 ve En \u0130yi Uygulamalar<\/h3>\n<p>\u0130dempotens uygularken dikkat edilmesi gereken baz\u0131 \u00f6nemli detaylar ve en iyi uygulamalar mevcuttur.<\/p>\n<h4>Idempotency Key'in Do\u011fru Kullan\u0131m\u0131 (Header vs. Body)<\/h4>\n<p><code>Idempotency-Key<\/code> genellikle HTTP ba\u015fl\u0131klar\u0131nda (<code>Idempotency-Key<\/code>, <code>X-Request-ID<\/code>) g\u00f6nderilir. Bu, ara katmanlar\u0131n (proxy, load balancer) anahtar\u0131 kolayca okuyup y\u00f6nlendirme veya \u00f6nbellekleme yapmas\u0131na olanak tan\u0131r. Baz\u0131 durumlarda, anahtar istek g\u00f6vdesinde de yer alabilir, ancak ba\u015fl\u0131klar genellikle daha pratik ve standart bir yakla\u015f\u0131md\u0131r. Anahtar\u0131n benzersiz ve yeterince rastgele oldu\u011fundan emin olun (\u00f6rne\u011fin, UUID\/GUID).<\/p>\n<h4>Hata Y\u00f6netimi ve Yeniden Denemeler (Al\u0131c\u0131 Taraf\u0131)<\/h4>\n<p>Al\u0131c\u0131 taraf\u0131nda, webhook i\u015flenirken bir hata olu\u015fursa, uygun bir HTTP durum kodu (\u00f6rne\u011fin, 500 Internal Server Error) d\u00f6nd\u00fcrmek \u00f6nemlidir. Bu, g\u00f6ndericinin yeniden deneme mekanizmas\u0131n\u0131 tetikler. Ancak, yeniden denemeler s\u0131ras\u0131nda ayn\u0131 <code>Idempotency-Key<\/code> ile gelen istekler, yukar\u0131da bahsedilen y\u00f6ntemlerle do\u011fru \u015fekilde ele al\u0131nmal\u0131d\u0131r. \u0130\u015flem s\u0131ras\u0131nda olu\u015fan hatalar\u0131 detayl\u0131 olarak g\u00fcnl\u00fcklemek, sorun giderme i\u00e7in hayati \u00f6nem ta\u015f\u0131r.<\/p>\n<h4>\u0130\u015flem S\u00fcresi ve Zaman A\u015f\u0131m\u0131 Y\u00f6netimi<\/h4>\n<p>Webhook i\u015fleme s\u00fcresi kritik olabilir. G\u00f6nderici sistemler genellikle belirli bir zaman a\u015f\u0131m\u0131 s\u00fcresi i\u00e7inde yan\u0131t bekler. E\u011fer i\u015fleminiz bu s\u00fcreyi a\u015farsa, g\u00f6nderici iste\u011fi zaman a\u015f\u0131m\u0131na u\u011frat\u0131p yeniden deneyebilir. Bu durumda, h\u0131zl\u0131ca bir 200 OK yan\u0131t\u0131 d\u00f6n\u00fcp as\u0131l i\u015fleme mant\u0131\u011f\u0131n\u0131 arka plan bir i\u015fe (mesaj kuyru\u011fu, background service) devretmek iyi bir stratejidir. \u0130dempotens kontrol\u00fc bu arka plan i\u015fi taraf\u0131ndan yap\u0131lmal\u0131d\u0131r.<\/p>\n<h4>\u0130zleme ve G\u00fcnl\u00fckleme (Monitoring & Logging)<\/h4>\n<p>\u0130dempotens mekanizman\u0131z\u0131n do\u011fru \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olmak i\u00e7in kapsaml\u0131 izleme ve g\u00fcnl\u00fckleme \u015fartt\u0131r.<br \/>\n*   Hangi <code>Idempotency-Key<\/code>'lerin geldi\u011fini, ne zaman i\u015flendi\u011fini ve ka\u00e7 kez tekrar geldi\u011fini g\u00fcnl\u00fckleyin.<br \/>\n*   Tekrarlayan olaylar\u0131n ba\u015far\u0131yla g\u00f6z ard\u0131 edildi\u011fini veya \u00f6nceki yan\u0131t\u0131n d\u00f6nd\u00fcr\u00fcld\u00fc\u011f\u00fcn\u00fc g\u00f6steren g\u00fcnl\u00fck mesajlar\u0131 ekleyin.<br \/>\n*   \u0130dempotens kontrol\u00fc s\u0131ras\u0131nda olu\u015fan hatalar\u0131 (\u00f6rne\u011fin, veritaban\u0131 ba\u011flant\u0131 sorunlar\u0131) izleyin.<\/p>\n<h3>G\u00fcvenlik ve Performans Hususlar\u0131<\/h3>\n<p>\u0130dempotens uygularken g\u00fcvenlik ve performans\u0131n da g\u00f6z \u00f6n\u00fcnde bulundurulmas\u0131 gerekir.<\/p>\n<h4>DDoS ve K\u00f6t\u00fc Niyetli Tekrarlar<\/h4>\n<p>K\u00f6t\u00fc niyetli akt\u00f6rler, sunucunuza ayn\u0131 <code>Idempotency-Key<\/code> ile binlerce istek g\u00f6ndererek kaynaklar\u0131n\u0131z\u0131 t\u00fcketmeye \u00e7al\u0131\u015fabilir. \u0130dempotens mekanizman\u0131z bu t\u00fcr sald\u0131r\u0131lar\u0131 do\u011frudan engellemese de, her iste\u011fin tam olarak i\u015flenmesini \u00f6nleyerek sistem \u00fczerindeki y\u00fck\u00fc azalt\u0131r. Ancak, yine de bir web uygulama g\u00fcvenlik duvar\u0131 (WAF) veya h\u0131z s\u0131n\u0131rlama (rate limiting) gibi ek g\u00fcvenlik \u00f6nlemleri alman\u0131z \u00f6nemlidir.<\/p>\n<h4>Veritaban\u0131 Y\u00fck\u00fc ve \u00d6l\u00e7eklenebilirlik<\/h4>\n<p>Veritaban\u0131 tabanl\u0131 idempotens kontrol\u00fc, her istek i\u00e7in veritaban\u0131 sorgusu gerektirdi\u011finden y\u00fcksek trafikli sistemlerde veritaban\u0131 \u00fczerinde ek y\u00fck olu\u015fturabilir. Bu y\u00fck\u00fc azaltmak i\u00e7in:<br \/>\n*   <code>IdempotencyRecord<\/code> tablosunda <code>IdempotencyKey<\/code> \u00fczerinde uygun bir indeks olu\u015fturun.<br \/>\n*   Eski kay\u0131tlar\u0131 d\u00fczenli olarak temizleyin (\u00f6rne\u011fin, 1-2 hafta sonra).<br \/>\n*   Y\u00fcksek hacimli senaryolarda da\u011f\u0131t\u0131k \u00f6nbellek (Redis) kullanmay\u0131 d\u00fc\u015f\u00fcn\u00fcn.<\/p>\n<h4>\u00d6nbellek Ge\u00e7ersiz K\u0131lma ve Tutarl\u0131l\u0131k<\/h4>\n<p>\u00d6nbellek tabanl\u0131 idempotens kullan\u0131rken, \u00f6nbelle\u011fin do\u011fru \u015fekilde ge\u00e7ersiz k\u0131l\u0131nd\u0131\u011f\u0131ndan ve veritaban\u0131 ile tutarl\u0131 oldu\u011fundan emin olun. \u00d6nbellekteki bir kayd\u0131n s\u00fcresi doldu\u011funda ve ayn\u0131 anahtar ile yeni bir istek geldi\u011finde, i\u015flemin yeniden do\u011fru bir \u015fekilde ger\u00e7ekle\u015ftirilmesi gerekir. \u00d6nbellek TTL'i, webhook sa\u011flay\u0131c\u0131s\u0131n\u0131n yeniden deneme penceresinden daha uzun olmal\u0131d\u0131r. E\u011fer bir i\u015flem ba\u015far\u0131s\u0131z olursa, \u00f6nbellekteki kayd\u0131 silmek veya durumu \"ba\u015far\u0131s\u0131z\" olarak i\u015faretlemek, sonraki denemelerin tekrar i\u015flenmesini sa\u011flayabilir.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Webhook'lar, modern uygulama mimarilerinin ayr\u0131lmaz bir par\u00e7as\u0131d\u0131r ve ger\u00e7ek zamanl\u0131 entegrasyonlar i\u00e7in hayati \u00f6nem ta\u015f\u0131r. Ancak, tekrarlayan olaylar, veri tutars\u0131zl\u0131klar\u0131 ve i\u015f s\u00fcre\u00e7lerinde aksakl\u0131klar gibi ciddi sorunlara yol a\u00e7abilir. Bu makalede ele ald\u0131\u011f\u0131m\u0131z idempotens prensipleri ve ASP.NET Core'da uygulama y\u00f6ntemleri, bu zorluklar\u0131n \u00fcstesinden gelmek i\u00e7in g\u00fc\u00e7l\u00fc bir \u00e7er\u00e7eve sunar.<\/p>\n<p>Benzersiz kimlikler (Idempotency Key) kullanarak, veritaban\u0131 veya da\u011f\u0131t\u0131k \u00f6nbellek tabanl\u0131 kontrol mekanizmalar\u0131 olu\u015fturarak ve bu mant\u0131\u011f\u0131 middleware gibi yeniden kullan\u0131labilir bile\u015fenler arac\u0131l\u0131\u011f\u0131yla uygulayarak, sistemlerinizin g\u00fcvenilirli\u011fini ve veri b\u00fct\u00fcnl\u00fc\u011f\u00fcn\u00fc \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131rabilirsiniz. G\u00fcvenlik, performans, hata y\u00f6netimi ve kapsaml\u0131 g\u00fcnl\u00fckleme gibi en iyi uygulamalar\u0131 benimsemek, sa\u011flam ve \u00f6l\u00e7eklenebilir bir webhook i\u015fleme altyap\u0131s\u0131 kurman\u0131z i\u00e7in kritik \u00f6neme sahiptir. \u0130dempotens, sadece bir teknik uygulama de\u011fil, ayn\u0131 zamanda da\u011f\u0131t\u0131k sistem tasar\u0131m\u0131nda g\u00fcvenilirli\u011fin temel bir felsefesidir.<\/p>\n<h3>SSS (S\u0131k Sorulan Sorular)<\/h3>\n<p><strong>1. \u0130dempotency key nedir?<\/strong><br \/>\n\u0130dempotency key, bir iste\u011fi veya olay\u0131 benzersiz bir \u015fekilde tan\u0131mlayan, genellikle GUID veya benzeri rastgele bir dize olan bir anahtard\u0131r. Al\u0131c\u0131 sistem, bu anahtar\u0131 kullanarak bir iste\u011fin daha \u00f6nce i\u015flenip i\u015flenmedi\u011fini kontrol eder ve ayn\u0131 anahtarla gelen tekrarlayan istekleri g\u00f6z ard\u0131 eder veya \u00f6nceki i\u015flemin sonucunu d\u00f6nd\u00fcr\u00fcr.<\/p>\n<p><strong>2. T\u00fcm webhook'lar idempotens olmal\u0131 m\u0131?<\/strong><br \/>\nGenel olarak evet. \u00d6zellikle sistemin durumunu de\u011fi\u015ftiren (veri olu\u015fturan, g\u00fcncelleyen, silen) t\u00fcm webhook olaylar\u0131 idempotent olmal\u0131d\u0131r. Durum de\u011fi\u015ftirmeyen, sadece bilgi sorgulayan (GET istekleri gibi) webhook'lar zaten do\u011fal olarak idempotenttir.<\/p>\n<p><strong>3. \u0130dempotens kontrol\u00fc performans\u0131 etkiler mi?<\/strong><br \/>\nEvet, idempotens kontrol\u00fc ek bir ad\u0131m (veritaban\u0131 veya \u00f6nbellek sorgusu) gerektirdi\u011finden performans\u0131 bir miktar etkileyebilir. Ancak, do\u011fru indeksleme, \u00f6nbellekleme ve optimize edilmi\u015f depolama \u00e7\u00f6z\u00fcmleri kullan\u0131larak bu etki minimize edilebilir. Veri tutarl\u0131l\u0131\u011f\u0131 ve sistem g\u00fcvenilirli\u011fi i\u00e7in bu ek maliyet genellikle kabul edilebilir d\u00fczeydedir.<\/p>\n<p><strong>4. Webhook imza do\u011frulamas\u0131 ile idempotens ayn\u0131 \u015fey mi?<\/strong><br \/>\nHay\u0131r, bunlar farkl\u0131 kavramlard\u0131r ancak birlikte kullan\u0131lmalar\u0131 \u015fiddetle tavsiye edilir. Webhook imza do\u011frulamas\u0131, gelen iste\u011fin yetkili bir kaynaktan geldi\u011fini ve i\u00e7eri\u011finin de\u011fi\u015ftirilmedi\u011fini garanti eden bir g\u00fcvenlik \u00f6nlemidir. \u0130dempotens ise, yetkili bir kaynaktan gelen bir iste\u011fin birden fazla kez i\u015flenmesi durumunda bile sistemin tut<\/p>\n","protected":false},"excerpt":{"rendered":"ASP.","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1340],"tags":[],"class_list":{"0":"post-39246","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-net","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>ASP.NET Core&#039;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ASP.NET Core&#039;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi\" \/>\n<meta property=\"og:description\" content=\"ASP.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-17T10:00:47+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi\",\"datePublished\":\"2026-02-17T10:00:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\"},\"wordCount\":2742,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\".NET\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#respond\"]}],\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\",\"name\":\"ASP.NET Core'da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2026-02-17T10:00:47+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"ASP.NET Core'da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/","og_locale":"tr_TR","og_type":"article","og_title":"ASP.NET Core'da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi","og_description":"ASP.","og_url":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2026-02-17T10:00:47+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"18 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi","datePublished":"2026-02-17T10:00:47+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/"},"wordCount":2742,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":[".NET"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#respond"]}],"copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/","url":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/","name":"ASP.NET Core'da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2026-02-17T10:00:47+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/asp-net-coreda-tekrarlayan-webhook-olaylarini-yonetme-idempotens-rehberi\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"ASP.NET Core&#8217;da Tekrarlayan Webhook Olaylar\u0131n\u0131 Y\u00f6netme: \u0130dempotens Rehberi"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/39246","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=39246"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/39246\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=39246"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=39246"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=39246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}