<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Samet UCA on Medium]]></title>
        <description><![CDATA[Stories by Samet UCA on Medium]]></description>
        <link>https://medium.com/@sametuca?source=rss-d063cdda3fa------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*l_Wy-Lrv7zGBbh2WMn-SQA.png</url>
            <title>Stories by Samet UCA on Medium</title>
            <link>https://medium.com/@sametuca?source=rss-d063cdda3fa------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 16 May 2026 19:31:35 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sametuca/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[.NET ve Angular Birlikteliği: Signal ile Full Stack Uygulamalarınızı Modernleştirin]]></title>
            <link>https://sametuca.medium.com/net-ve-angular-birlikteli%C4%9Fi-signal-ile-full-stack-uygulamalar%C4%B1n%C4%B1z%C4%B1-modernle%C5%9Ftirin-f1d69cdbc5a1?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/f1d69cdbc5a1</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[c-sharp-programming]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[full-stack-development]]></category>
            <category><![CDATA[dotnet]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Sat, 09 Aug 2025 09:14:49 GMT</pubDate>
            <atom:updated>2025-08-09T09:14:49.846Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*eHiEW9e8A8UXBDeX.jpg" /></figure><p>Bir Full Stack Developer olarak, uygulamalarımızın hem arka ucunda hem de ön ucunda en etkili çözümleri bulmaya çalışıyoruz. Genellikle arka uçta <strong>ASP.NET Core</strong> ile güçlü, tipli ve ölçeklenebilir API’lar inşa ederken, ön uçta ise <strong>Angular</strong>’ın dinamik ve bileşen tabanlı dünyasından faydalanıyoruz.</p><p>Ancak, bu iki güçlü teknolojiyi bir araya getirmek, özellikle veri akışını yönetme konusunda bazı zorlukları beraberinde getirebiliyor. Angular’ın geleneksel reaktif programlama yaklaşımı olan <strong>RxJS</strong>, güçlü olsa da, basit senaryolar için bile abonelik yönetimi gibi ek karmaşıklıklar sunabiliyordu.</p><p>İşte tam da bu noktada, Angular dünyasına yeni bir soluk getiren <strong>Signal</strong>’dan bahsedeceğiz. Bu makalede, bir .NET geliştiricisinin gözünden, arka uçta hazırladığımız veriyi Angular’da Signal ile nasıl daha basit ve performanslı bir şekilde yöneteceğimizi göstereceğim.</p><h3>1. Veri Kaynağımız: ASP.NET Core API</h3><p>Her şey, Angular’ın tüketeceği bir veri kaynağı oluşturmakla başlar. Gelin, C# ile basit bir Product modeli ve bu ürünleri döndüren bir API endpoint’i oluşturalım.</p><h4>Ürün Modeli (Product.cs)</h4><p>Bu basit C# sınıfı, veritabanından veya herhangi bir kaynaktan gelecek ürün verisini temsil ediyor.</p><pre>namespace FullStackApp.Models<br>{<br>    public class Product<br>    {<br>        public int Id { get; set; }<br>        public string Name { get; set; }<br>        public decimal Price { get; set; }<br>    }<br>}</pre><h4>Ürünleri Döndüren API EndPoint’i (ProductsController.cs)</h4><p>[ApiController] ve [Route(&quot;api/[controller]&quot;)] gibi niteliklerle standart bir HTTP API&#39;si oluşturuyoruz. [HttpGet] metodu ise ürün listesini JSON formatında döndürecektir.</p><pre>using Microsoft.AspNetCore.Mvc;<br>using FullStackApp.Models;<br><br>namespace FullStackApp.Controllers<br>{<br>    [Route(&quot;api/[controller]&quot;)]<br>    [ApiController]<br>    public class ProductsController : ControllerBase<br>    {<br>        private static readonly List&lt;Product&gt; Products = new List&lt;Product&gt;<br>        {<br>            new Product { Id = 1, Name = &quot;Laptop&quot;, Price = 25000.50m },<br>            new Product { Id = 2, Name = &quot;Mouse&quot;, Price = 450.00m },<br>            new Product { Id = 3, Name = &quot;Keyboard&quot;, Price = 800.75m },<br>            new Product { Id = 4, Name = &quot;Monitor&quot;, Price = 6500.00m }<br>        };<br><br>        [HttpGet]<br>        public ActionResult&lt;IEnumerable&lt;Product&gt;&gt; Get()<br>        {<br>            return Ok(Products);<br>        }<br>    }<br>}</pre><p>Bu ApiController ile, http://localhost:5000/api/products adresinden çağrıldığında bir ürün listesi döndüren hazır bir API endpoint’imiz var. Şimdi bu veriyi Angular tarafında nasıl tüketeceğimize bakalım.</p><h3>2. Ön Uçta Veri Akışı Yönetimi: Signal ile Yeni Yaklaşım</h3><p>Geleneksel Angular yaklaşımında, bu API endpoint’ini çağırmak ve gelen veriyi yönetmek için HttpClient&#39;ın döndürdüğü Observable&#39;a manuel olarak subscribe olmamız gerekirdi. Bu yaklaşım, abonelikleri ngOnDestroy yaşam döngüsü kancasında manuel olarak sonlandırma yükünü de beraberinde getiriyordu.</p><p><strong>Geleneksel (RxJS) Yaklaşım:</strong></p><pre>import { Component, OnInit, OnDestroy } from &#39;@angular/core&#39;;<br>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { Subscription } from &#39;rxjs&#39;;<br><br>// Product modeli<br>interface Product {<br>  id: number;<br>  name: string;<br>  price: number;<br>}<br><br>@Component({ ... })<br>export class ProductListComponent implements OnInit, OnDestroy {<br>  products: Product[] = [];<br>  private subscription: Subscription;<br><br>  constructor(private http: HttpClient) { }<br><br>  ngOnInit() {<br>    this.subscription = this.http.get&lt;Product[]&gt;(&#39;/api/products&#39;).subscribe(data =&gt; {<br>      this.products = data;<br>    });<br>  }<br><br>  ngOnDestroy() {<br>    this.subscription.unsubscribe(); // Manuel abonelik yönetimi zorunluluğu<br>  }<br>}</pre><h4>Signal ile Yeni ve Güvenli Yaklaşım</h4><p>Signal, bu süreci önemli ölçüde basitleştiriyor. Angular’ın <strong>rxjs-interop</strong> paketi sayesinde, bir Observable&#39;ı doğrudan bir <strong>Signal</strong>&#39;e dönüştürebiliriz. Bu sayede subscribe ve unsubscribe işlemleri otomatik olarak yönetilir.</p><pre>import { Component } from &#39;@angular/core&#39;;<br>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { toSignal } from &#39;@angular/core/rxjs-interop&#39;;<br><br>// Product modeli<br>interface Product {<br>  id: number;<br>  name: string;<br>  price: number;<br>}<br><br>@Component({<br>  selector: &#39;app-product-list&#39;,<br>  standalone: true,<br>  template: `<br>    &lt;h2&gt;Ürünler&lt;/h2&gt;<br>    @if (products()) {<br>      &lt;ul&gt;<br>        @for (product of products(); track product.id) {<br>          &lt;li&gt;{{ product.name }} - {{ product.price | currency:&#39;₺&#39; }}&lt;/li&gt;<br>        }<br>      &lt;/ul&gt;<br>    } @else {<br>      &lt;p&gt;Ürünler yükleniyor...&lt;/p&gt;<br>    }<br>  `,<br>  imports: [CommonModule, HttpClientModule]<br>})<br>export class ProductListComponent {<br>  // ASP.NET Core API&#39;mizden gelen veri otomatik olarak Signal&#39;e dönüştürülür.<br>  // toSignal, arka planda aboneliği yönetir ve bileşen yıkıldığında sonlandırır.<br>  products = toSignal(this.http.get&lt;Product[]&gt;(&#39;/api/products&#39;));<br><br>  constructor(private http: HttpClient) {}<br>}</pre><p>Bir .NET geliştiricisi olarak arka uçta async/await ile yaptığımız sade kodlama deneyiminin, ön uca da taşındığını gösteriyor.</p><h3>3. Dinamik Filtreleme: computed()&#39;ın Gücü</h3><p>API’den çektiğimiz veriyi ön uçta filtrelemek, yaygın bir senaryodur. Signal ve <strong>computed()</strong> ikilisi, bu işlemi performanslı ve deklaratif bir şekilde yapmamızı sağlar. Kullanıcı her tuşa bastığında API’ye yeni bir istek atmak yerine, elimizdeki veriyi anlık olarak filtreleyebiliriz.</p><pre>import { Component, signal, computed } from &#39;@angular/core&#39;;<br>// ... diğer import&#39;lar<br><br>@Component({<br>  selector: &#39;app-product-list&#39;,<br>  standalone: true,<br>  template: `<br>    &lt;h2&gt;Ürünler&lt;/h2&gt;<br>    &lt;input type=&quot;text&quot; [(ngModel)]=&quot;searchQuery&quot; placeholder=&quot;Ürün ara...&quot;&gt;<br>    <br>    @if (filteredProducts().length &gt; 0) {<br>      &lt;ul&gt;<br>        @for (product of filteredProducts(); track product.id) {<br>          &lt;li&gt;{{ product.name }} - {{ product.price | currency:&#39;₺&#39; }}&lt;/li&gt;<br>        }<br>      &lt;/ul&gt;<br>    } @else {<br>      &lt;p&gt;Ürün bulunamadı.&lt;/p&gt;<br>    }<br>  `,<br>  imports: [CommonModule, HttpClientModule, FormsModule]<br>})<br>export class ProductListComponent {<br>  products = toSignal(this.http.get&lt;Product[]&gt;(&#39;/api/products&#39;));<br>  <br>  searchQuery = signal(&#39;&#39;);<br>  <br>  // products veya searchQuery değiştiğinde yeniden hesaplanacak liste<br>  filteredProducts = computed(() =&gt; {<br>    const query = this.searchQuery().toLowerCase();<br>    const allProducts = this.products() || [];<br>    <br>    // products() bir Signal olduğu için .NET API&#39;den gelen veriye böyle ulaşıyoruz.<br>    return allProducts.filter(p =&gt; p.name.toLowerCase().includes(query));<br>  });<br><br>  constructor(private http: HttpClient) {}<br>}</pre><blockquote>computed() fonksiyonu, <strong>memoization</strong> (önbellekleme) yaparak performansı artırır. Yani, searchQuery veya products değişmedikçe, filteredProducts tekrar hesaplanmaz.</blockquote><h3>Sonuç: Bir .NET Geliştiricisinin Gözünden Angular</h3><p>Arka uçta <strong>ASP.NET Core</strong>’un güçlü ve tipli dünyasında yazdığımız temiz kodu, ön uçta Signal’ın getirdiği basit ve reaktif veri yönetimiyle tamamlayabiliriz.</p><p>Bu yenilikler, Angular’ı sadece hızlı değil, aynı zamanda geliştirici dostu ve bakımı kolay bir çerçeve haline getiriyor. Artık karmaşık RxJS operatörleri veya manuel abonelik yönetimi gibi zorluklar olmadan, kullanıcı deneyimine odaklanmak çok daha kolay.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1d69cdbc5a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular Signal: Bileşen Durum Yönetimi]]></title>
            <link>https://sametuca.medium.com/angular-signal-bile%C5%9Fen-durum-y%C3%B6netimi-e0d8a3c67925?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/e0d8a3c67925</guid>
            <category><![CDATA[signal]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[angular-20]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Sat, 09 Aug 2025 09:02:43 GMT</pubDate>
            <atom:updated>2025-08-09T09:02:43.454Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9x8ZMlskxtRoWt9K.jpg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gy4s53GrG-o_G-ue.png" /></figure><h3>Biraz Signal</h3><p>Angular, başlangıcından bu yana veri ve durum yönetimini ele alma biçimini sürekli olarak geliştiriyor. İlk versiyonlardaki $scope ve ng-change ikilisinden, hayatımıza giren güçlü <strong>RxJS</strong> kütüphanesine kadar, her zaman daha iyi bir reaktiflik deneyimi arayışı içinde oldu.</p><p>Ancak, RxJS’in getirdiği güçlü operatörler ve asenkron veri akışını yönetme yeteneği, özellikle yeni başlayanlar için dik bir öğrenme eğrisi sunabiliyordu. “Subscription cehennemi :D” tabiri, her geliştiricinin bir noktada karşılaştığı bir durumdu. İşte tam bu noktada, Angular ekibi yeni bir çözümle karşımıza çıktı: <strong>Angular Signal</strong>.</p><p>Peki, Signal tam olarak nedir ve neden Angular’ın geleceği için bu kadar önemli?</p><h3>Neden Önemli Bu Signal?</h3><p>Basitçe ifade etmek gerekirse, <strong>Signal</strong>, değerleri güncellendiğinde bunu otomatik olarak dinleyicilere bildiren bir “sarmalayıcı”dır. Bir kutu hayal edin. Bu kutunun içine bir değer koyuyorsunuz. Kutuya ne zaman yeni bir değer koysanız, kutuya bağlı olan herkes bundan haberdar oluyor. İşte Signal tam olarak bu mantıkla çalışır.</p><p>Signal’in en önemli avantajı, <strong>declarative</strong> (bildirimsel) olmasıdır. Yani “ne yapacağını” değil, “ne olacağını” söylersiniz. RxJS’deki gibi veri akışlarını yönetmek için karmaşık operatör zincirleri kurmak yerine, sadece değerin değiştiğini belirtirsiniz.</p><p>Bu yaklaşım, üç temel fayda sağlar:</p><ol><li><strong>Daha Az Kod:</strong> Daha az “boilerplate” (kalıp) kod yazarak aynı reaktifliği elde edersiniz.</li><li><strong>Kolay Öğrenme:</strong> Konsept olarak RxJS’in karmaşık operatörlerinden çok daha basittir.</li><li><strong>Performans:</strong> <strong>zone.js</strong> bağımlılığını azaltarak veya tamamen ortadan kaldırarak daha performanslı ve parçalı (granular) değişiklik algılama imkanı sunar.</li></ol><h3>Temel Bileşenler</h3><p>Angular Signal, reaktif bir sistem oluşturmak için üç ana fonksiyon üzerine kurulmuştur: signal(), computed() ve effect().</p><h4>1. signal(): Temel Reaktif Değer</h4><p>Bu, bir reaktif değer oluşturmak için kullandığımız ana fonksiyondur. Bir değerle başlatılır ve bu değeri okumak ve güncellemek için iki farklı yöntem sunar.</p><p><strong>Okuma:</strong> Değeri okumak için Signal değişkenini bir fonksiyon gibi çağırmanız gerekir. Yani counter değil, counter() şeklinde kullanılır. Bu parantezler, Angular&#39;a bu değerin bir Signal olduğunu ve reaktif bir bağlamda takip edilmesi gerektiğini söyler. <strong>Yazma:</strong> Değeri güncellemek için set() veya update() metodunu kullanırız.</p><pre>import { Component, signal } from &#39;@angular/core&#39;;<br><br>@Component({<br>  selector: &#39;app-counter&#39;,<br>  standalone: true,<br>  template: `<br>    &lt;p&gt;Sayı: {{ count() }}&lt;/p&gt;<br>    &lt;button (click)=&quot;increment()&quot;&gt;Arttır&lt;/button&gt;<br>  `,<br>})<br>export class CounterComponent {<br>  // 0 değeriyle başlatılan bir Signal<br>  count = signal(0);<br><br>  increment() {<br>    // set() metodu ile değeri doğrudan değiştirebiliriz<br>    // this.count.set(10);<br><br>    // update() metodu ile mevcut değer üzerinden işlem yapabiliriz<br>    this.count.update(currentValue =&gt; currentValue + 1);<br>  }<br>}</pre><p>Bu örnekte, increment() metodu tetiklendiğinde count Signal&#39;i güncellenir. Angular, {{ count() }} ifadesinin bir Signal olduğunu anlar ve değer değiştiğinde DOM&#39;u otomatik olarak günceller.</p><h4>2. computed(): Otomatik Hesaplanan Değerler</h4><p>Bazen, bir veya daha fazla Signal’in değerine bağlı olarak otomatik olarak güncellenen yeni bir değere ihtiyacınız olur. İşte computed() fonksiyonu tam da bu işe yarar. computed()&#39;ın değeri, kendisine bağlı olan Signal&#39;lerden biri değiştiğinde yeniden hesaplanır.</p><pre>import { Component, signal, computed } from &#39;@angular/core&#39;;<br><br>@Component({<br>  selector: &#39;app-computed-example&#39;,<br>  standalone: true,<br>  template: `<br>    &lt;p&gt;Sayı: {{ count() }}&lt;/p&gt;<br>    &lt;p&gt;Sayının iki katı: {{ doubleCount() }}&lt;/p&gt;<br>    &lt;button (click)=&quot;increment()&quot;&gt;Arttır&lt;/button&gt;<br>  `,<br>})<br>export class ComputedExampleComponent {<br>  count = signal(1);<br><br>  // count Signal&#39;ine bağlı olarak otomatik güncellenen bir değer<br>  doubleCount = computed(() =&gt; this.count() * 2);<br><br>  increment() {<br>    this.count.update(value =&gt; value + 1);<br>  }<br>}</pre><p>Yukarıdaki kodda count Signal&#39;i her değiştiğinde, doubleCount Signal&#39;i otomatik olarak yeniden hesaplanır ve computed() fonksiyonu içinde bir değişiklik olduğu için şablon güncellenir.</p><h4>3. effect(): Yan Etkileri (Side-effects) Tetiklemek</h4><p>effect() fonksiyonu, bir veya birden fazla Signal değiştiğinde bir yan etki (side-effect) tetiklemek için kullanılır. Bu yan etkiler; loglama, bir API&#39;ye istek atma veya DOM&#39;u doğrudan manipüle etme gibi işlemler olabilir. effect() fonksiyonu, reaktif sistemin en temel parçası olmasına rağmen, mümkün olduğunca az kullanılması önerilir. Çünkü bileşenlerin reaktifliği genellikle HTML şablonu üzerinden sağlanır.</p><pre>import { Component, signal, effect } from &#39;@angular/core&#39;;<br><br>@Component({<br>  selector: &#39;app-effect-example&#39;,<br>  standalone: true,<br>  template: `<br>    &lt;p&gt;Sayı: {{ count() }}&lt;/p&gt;<br>    &lt;button (click)=&quot;increment()&quot;&gt;Arttır&lt;/button&gt;<br>  `,<br>})<br>export class EffectExampleComponent {<br>  count = signal(0);<br><br>  constructor() {<br>    // count Signal&#39;i her değiştiğinde çalışacak bir effect<br>    effect(() =&gt; {<br>      console.log(&#39;Sayı değişti. Yeni değer:&#39;, this.count());<br>    });<br>  }<br><br>  increment() {<br>    this.count.update(value =&gt; value + 1);<br>  }<br>}</pre><p>Bu örnekte, increment() metodu çağrıldığında count Signal&#39;i güncellenir ve effect() içinde tanımladığımız konsol çıktısı otomatik olarak tetiklenir.</p><p>Angular’a yeni başlayanlar için akla gelen ilk soru şu olabilir: “Artık RxJS’e ihtiyacım kalmadı mı?”</p><p>Cevap oldukça net: <strong>RxJS ve Signal birbirinin alternatifi değil, tamamlayıcısıdır.</strong></p><ul><li><strong>Signal</strong>, genellikle bileşen içi durum yönetimi için mükemmeldir. Kullanıcının bir butona tıklamasıyla değişen sayacı, bir formun geçerliliğini veya bir açılır menünün durumunu yönetmek gibi basit reaktiflik ihtiyaçlarını kolayca çözer.</li><li><strong>RxJS</strong> ise, asenkron olay akışlarını yönetme konusunda hala bir numaradır. HTTP istekleri, WebSocket bağlantıları, kullanıcı girdilerinden oluşan karmaşık akışlar (debounce, throttle) ve stream’leri birleştirme/dönüştürme gibi işlemler için RxJS’in güçlü operatörleri vazgeçilmezdir.</li></ul><p>Aslında, ikisini bir arada kullanmak en güçlü yaklaşımdır. Örneğin, bir API’den gelen veriyi önce RxJS ile yönetip, gelen veriyi bir Signal’e atayarak bileşen içinde reaktif bir şekilde kullanabilirsiniz:</p><pre>import { Component, OnInit, signal } from &#39;@angular/core&#39;;<br>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { toSignal } from &#39;@angular/core/rxjs-interop&#39;;<br><br>@Component({<br>  selector: &#39;app-data&#39;,<br>  standalone: true,<br>  template: `<br>    @if (data()) {<br>      &lt;p&gt;Kullanıcı Adı: {{ data()?.name }}&lt;/p&gt;<br>    } @else {<br>      &lt;p&gt;Veri yükleniyor...&lt;/p&gt;<br>    }<br>  `,<br>})<br>export class DataComponent implements OnInit {<br>  // toSignal ile Observable&#39;ı Signal&#39;e dönüştürüyoruz<br>  data = toSignal(this.http.get&lt;{ name: string }&gt;(&#39;https://jsonplaceholder.typicode.com/users/1&#39;));<br><br>  constructor(private http: HttpClient) {}<br><br>  ngOnInit() {<br>    // API isteği otomatik olarak yapılır ve gelen veri `data` Signal&#39;ine atanır.<br>  }<br>}</pre><p>Angular Signal, geliştiricilere <strong>zone.js&#39;den bağımsız</strong>, daha basit ve daha performanslı bir reaktiflik modeli sunarak Angular&#39;ın geleceğini şekillendiriyor. Bileşen içi durum yönetimini kökten sadeleştirirken, RxJS&#39;in gücünden vazgeçmeye gerek kalmıyor.</p><p>Angular ekibinin uzun vadeli hedefi, Signal’i Angular’ın çekirdeğine daha da entegre ederek, gelecekte tamamen “Zoneless” (zone.js’siz) bir Angular dünyasının kapılarını aralamak.</p><p>Eğer hala Signal’ı denemediyseniz, Angular 17 ve sonrası projelerinizde kullanmaya başlamak için harika bir zaman. Sadece birkaç satır kodla, uygulamalarınızın ne kadar daha temiz ve okunabilir hale geldiğini göreceksiniz.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0d8a3c67925" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TypeScript 5.7 Yayınlandı: Öne Çıkan Yenilikler]]></title>
            <link>https://sametuca.medium.com/typescript-5-7-yay%C4%B1nland%C4%B1-%C3%B6ne-%C3%A7%C4%B1kan-yenilikler-eb3e77bfb809?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/eb3e77bfb809</guid>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Mon, 30 Dec 2024 23:52:22 GMT</pubDate>
            <atom:updated>2024-12-30T23:58:48.724Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kH4cVj3esH2SWGMv.png" /></figure><p>TypeScript 5.7, geliştiricilere hızlı, güçlü ve esnek bir kod yazma deneyimi sunmak için bir dizi yenilikle yayınlandı. JavaScript’e eklediği tipi belirteçleri ve hata yakalama desteği sayesinde yazılımcıların hayatını kolaylaştıran TypeScript, bu sürümde özellikle performans ve esneklik konularında önemli geliştirmeler sunuyor.</p><h3>Neden TypeScript?</h3><p>TypeScript, JavaScript kodlarınızı daha okunabilir ve daha az hata yapmaya yönelik bir hale getiren, JavaScript’in bir üst kümesidir. Kendi yazılım geliştirme sürecinizde TypeScript kullanarak otomatik tamamlama, refaktoring ve hata ayıklama gibi işlevlerden faydalanabilirsiniz. TypeScript’in özelliği, derleme süreci sonunda temiz ve performanslı JavaScript kodu üretmesidir.</p><h3>Sürümde Neler Yeni?</h3><h3>Daha Hızlı Hata Yakalama</h3><p>Bu sürüm, başlatılmamış değişkenlerin kullanımında hata algılamayı geliştiriyor. Daha önce özel fonksiyon yapılarında yakalanamayan bu tür hatalar artık kolayca tespit ediliyor.</p><h4>Kod Örneği:</h4><pre>function foo() {<br>    let result: number<br><br>    function printResult() {<br>        console.log(result); // Hata: Değişken &#39;result&#39; başlatılmadan kullanılmış.<br>    }<br>}</pre><h3>Uzantıları Otomatik Dönüştürme</h3><p>Artık TypeScript, çıktı dosyalar oluştururken çok daha esnek. --rewriteRelativeImportExtensions bayrağı sayesinde .ts uzantıları doğrudan .js’e dönüştürülüyor. Bu, çoklu dosya yapıları için büyük kolaylık sağlıyor.</p><pre>// TypeScript dosyasında:<br>import * as foo from &quot;./foo.ts&quot;;</pre><pre>// JavaScript dosyasında:<br>import * as foo from &quot;./foo.js&quot;;</pre><h3>ES2024 Desteği</h3><p>Yeni ES2024 hedefiyle, TypeScript kütüphanelerinin yeni özelliklerini kullanabilirsiniz. SharedArrayBuffer ve ArrayBuffer gibi yapıların geliştirilmiş hallerini destekleyen bu sürüm, TypedArray türlerini de generic yapıya kavuşturdu.</p><h4>Kod Örneği:</h4><pre>interface Uint8Array&lt;TArrayBuffer extends ArrayBufferLike = ArrayBufferLike&gt; {<br>    // ...<br>}</pre><h3>JSON Doğrulamaları</h3><p>JSON dosyalarını import ederken type: &quot;json&quot; belirteci zorunlu hale geldi. Bu, çalışma zamanında yaşanabilecek hataları önceden engelliyor.</p><h4>Kod Örneği:</h4><pre>import myConfig from &quot;./myConfig.json&quot; with { type: &quot;json&quot; };<br>console.log(myConfig.property);</pre><h3>TSServer’da Daha Akıllı Konfigürasyon</h3><p>Bir dosyanın hangi tsconfig.json dosyasına ait olduğunu belirlemek artık daha kolay. Çoklu proje yapılarında bu geliştirme, esneklik ve performans artışı sağlıyor.</p><h3>Performans ve Verimlilik</h3><p>Node.js 22’nin yeni module.enableCompileCache() API&#39;si sayesinde TypeScript 5.7 ile derleme süreleri çarpıcı şekilde azaldı. Yapılan testlerde, bu yeni özellik derleme hızında 2.5 katına kadar bir artış gösterdi.</p><h3>Geçiş Sürecindeki Notlar</h3><p>Bu sürümde, TypedArray’ler ve DOM yapılarındaki değişiklikler nedeniyle bazı eski projelerde ufak uyumluluk sorunları yaşanabilir. Ancak bu sorunlar, kütüphane güncellemeleriyle kolayca giderilebilir.</p><h3>Son Söz</h3><p>TypeScript 5.7, geliştiricilere daha akıllı ve verimli bir çalışma ortamı sunuyor. Performans iyileştirmeleri ve yeni özellikleriyle bu sürümü denemek için harika bir zaman! Daha fazla bilgi için <a href="https://www.typescriptlang.org">TypeScript resmi sitesi</a> adresini ziyaret edebilirsiniz.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb3e77bfb809" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular’da BehaviorSubject ve Observable]]></title>
            <link>https://sametuca.medium.com/angularda-behaviorsubject-ve-observable-e7c148b7e1d8?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/e7c148b7e1d8</guid>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[observables]]></category>
            <category><![CDATA[rxjs]]></category>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Fri, 20 Sep 2024 20:04:30 GMT</pubDate>
            <atom:updated>2024-09-20T20:04:30.718Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r0ZRHykTQ15Di6JM" /></figure><p>Angular uygulamalarında veri akışını yönetmek için sıklıkla kullanılan iki önemli kavram vardır: <strong>Observable</strong> ve <strong>BehaviorSubject</strong>. Bu kavramlar, uygulamalarımızda gerçek zamanlı güncellemeler, veri paylaşımı ve karmaşık durum yönetimi gibi senaryoları ele almamıza olanak tanır. Bu makalede, <strong>Observable </strong>ve <strong>BehaviorSubject</strong>’ın ne olduğunu, aralarındaki farkları ve hangi durumlarda hangisini kullanmanız gerektiğini detaylı bir şekilde inceleyeceğiz.</p><h4>Observable Nedir?</h4><p><strong>Observable</strong>, zaman içinde birden fazla değer yayımlayan bir nesnedir. Bu değerler, herhangi bir olay (tıklama, veri alımı vb.) veya belirli bir zaman aralığında tetiklenebilir. <strong>Observable</strong>’lar, veri akışını temsil etmenin güçlü bir yoludur ve genellikle asenkron işlemlerle birlikte kullanılır.</p><p><strong>Örnek:</strong> Bir HTTP isteği ile sunucudan veri çekmek istediğimizi düşünelim. Bu istek, bir <strong>Observable </strong>olarak temsil edilebilir. İstek tamamlandığında, <strong>Observable </strong>bize bir cevap döndürür ve bu cevap, abone olan bileşenler tarafından işlenir.</p><p>Aşağıdaki kodda kullanım örneğini görebiliriz.</p><pre>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { Observable } from &#39;rxjs&#39;;<br><br>// rxjs kütüphanesinden Observable&#39;ı içe aktarırız. Observable, zaman içerisinde değişebilen değerleri temsil eder.<br>// Bu sayede, HTTP isteklerinin sonuçlarını yönetebiliriz.<br><br>@Injectable({ providedIn: &#39;root&#39; })<br><br>export class DataService {<br>  constructor(private http: HttpClient) {}<br><br>  getData(): Observable&lt;any&gt; {<br>    // getData metodu, bir Observable döndürür. Bu Observable, HTTP isteğinin sonucunu temsil eder.<br>    return this.http.get(&#39;https://api.sam.com/data&#39;);<br>    // Bu satır, belirtilen URL&#39;ye bir HTTP GET isteği gönderir.<br>    // İsteğin sonucu, Observable aracılığıyla geri döndürülür.<br>  }<br>}</pre><pre>import { Component } from &#39;@angular/core&#39;;<br>import { DataService } from &#39;./data.service&#39;;<br><br>@Component({<br>  selector: &#39;app-my-component&#39;, <br>  templateUrl: &#39;./my-component.component.html&#39;,<br>  styleUrls: [&#39;./my-component.component.css&#39;] <br>})<br>export class MyComponent {<br>  // data değişkeni, sunucudan alınan veriyi tutacak<br>  data: any;<br><br>  constructor(private dataService: DataService) {}<br>  // Bileşenin constructor&#39;ı, DataService servisini enjekte eder.<br><br>  ngOnInit() {<br>    // ngOnInit yaşam döngüsü kancası, bileşen ilk kez oluşturulduğunda çağrılır.<br>    this.dataService.getData()<br>      .subscribe(response =&gt; {<br>        this.data = response;  // Sunucudan gelen veriyi data değişkenine atarız.<br>      });<br>  }<br>}</pre><h4>BehaviorSubject Nedir?</h4><p>BehaviorSubject, Observable’ın özel bir türüdür. Diğer Observable’lardan farklı olarak, BehaviorSubject’ın başlangıç değeri vardır ve bu değeri abone olan her gözlemciye hemen gönderir. Ayrıca, yeni bir değer yayımlandığında, bu değer tüm abone olan gözlemcilere iletilir.</p><p><strong>Örnek:</strong> Bir sayfada kullanıcı adı bilgisini saklamak istediğimizi düşünelim. Bu bilgiyi bir BehaviorSubject içinde tutabilir ve bu şekilde farklı bileşenler arasında paylaşabiliriz.</p><pre>import { BehaviorSubject } from &#39;rxjs&#39;; // BehaviorSubject sınıfını rxjs kütüphanesinden içe aktarır<br><br>@Injectable({ providedIn: &#39;root&#39; })<br>export class AuthService {<br>  private userSubject: BehaviorSubject&lt;string&gt;(&#39;&#39;);<br>  private userSubject = new BehaviorSubject&lt;string&gt;(&#39;&#39;); // Bir BehaviorSubject nesnesi oluşturulur. Bu nesne, kullanıcı adı bilgisini tutar.<br><br>  public user$ = this.userSubject.asObservable(); // BehaviorSubject&#39;ın observable&#39;ına erişim için bir property tanımlanır.<br><br>  setUser(username: string) {<br>    this.userSubject.next(username); // Yeni kullanıcı adı, BehaviorSubject&#39;a gönderilir.<br>  }<br>}</pre><pre><br>import { Component } from &#39;@angular/core&#39;;<br>import { AuthService } from &#39;./auth.service&#39;;<br><br><br>@Component({<br>  selector: &#39;app-login&#39;, <br>  templateUrl: &#39;./login.component.html&#39;, <br>  styleUrls: [&#39;./login.component.css&#39;] <br>})<br>export class LoginComponent {<br>  // username değişkeni, kullanıcının girdiği kullanıcı adını tutar<br>  username: string = &#39;&#39;;<br><br>  constructor(private authService: AuthService) {}<br>  // Bileşenin constructor&#39;ı, AuthService servisini enjekte eder.<br><br>  onSubmit() {<br>    // Burada, kullanıcı adı ve şifre doğrulaması gibi işlemler yapılabilir.<br>    // Örneğin, bir HTTP isteği göndererek sunucuya kullanıcı bilgilerini gönderebilirsiniz.<br><br>    this.authService.setUser(this.username);<br>    // Kullanıcı adı doğrulama işlemlerinden sonra, AuthService&#39;in setUser metodu çağrılır.<br>    // Bu metot, kullanıcı adını AuthService&#39;e iletir ve AuthService bu kullanıcı adını kullanarak oturum açma işlemlerini gerçekleştirir.<br>  }<br>}</pre><p>LoginComponent içerisinde, onSubmit metodu kullanıcının giriş bilgilerini onaylar ve ardından authService.setUser(username) methodunu çağırır. Bu method, kullanıcı adını userSubject isimli BehaviorSubject&#39;a iletir.</p><h4><strong>Kullanıcı Bilgisini Abone Olma</strong></h4><p>Başka bir bileşende, userSubject tarafından yayınlanan değerlere abone olabilirsiniz. Örneğin, bir HeaderComponent içerisinde oturum açmış kullanıcıyı görüntülemek isteyebilirsiniz:</p><pre>import { Component, OnInit } from &#39;@angular/core&#39;;<br>import { AuthService } from &#39;./auth.service&#39;;<br><br><br>@Component({<br>  selector: &#39;app-header&#39;,<br>  templateUrl: &#39;./header.component.html&#39;,<br>  styleUrls: [&#39;./header.component.css&#39;] <br>})<br>export class HeaderComponent implements OnInit {<br>  // currentUser değişkeni, oturum açmış kullanıcının adını tutar<br>  currentUser: string = &#39;&#39;;<br><br>  constructor(private authService: AuthService) {}<br>  // Bileşenin constructor&#39;ı, AuthService servisini enjekte eder.<br><br>  ngOnInit() {<br>    // ngOnInit yaşam döngüsü kancası, bileşen ilk kez oluşturulduğunda çağrılır.<br>    this.authService.user$.subscribe(user =&gt; {<br>      this.currentUser = user;<br>    });<br>  }<br>}</pre><h4><strong>Abonelikten Çıkma</strong></h4><p>Bellek sızıntılarını önlemek için, bileşen yok edilirken user$&#39;a abonelikten çıkılması önemlidir. Bunu ngOnDestroy yaşam döngüsü kancası içerisinde yapabilirsiniz:</p><pre>ngOnDestroy() {<br>  // Aboneliği iptal edin<br>  this.subscription?.unsubscribe();<br>}</pre><h4>Observable ve BehaviorSubject Arasındaki Farklar</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*ahw8pZi6quvDcn8ECOWDpw.png" /></figure><h4>Hangi Durumda Hangi Kavram Kullanılmalı?</h4><p><strong>Observable</strong></p><ul><li>HTTP istekleri</li><li>Web Sockets</li><li>Timer’lar</li><li>Event’ler (tıklama, mouse hareketleri vb.)</li></ul><p><strong>BehaviorSubject</strong></p><ul><li>Form verileri</li><li>Kullanıcı oturum bilgileri</li><li>Bileşenler arasında veri paylaşımı</li><li>Uygulama durumu</li></ul><h4>Pratik Örnek: Form Yönetimi</h4><pre>import { Component } from &#39;@angular/core&#39;;<br>import { BehaviorSubject } from &#39;rxjs&#39;;<br><br>@Component({<br>  selector: &#39;app-my-form&#39;,<br>  templateUrl: &#39;./my-form.component.html&#39;, <br>  styleUrls: [&#39;./my-form.component.css&#39;] <br>})<br>export class MyFormComponent {<br>  // private formValueSubject = new BehaviorSubject&lt;string&gt;(&#39;&#39;);<br>  private formValueSubject = new BehaviorSubject&lt;string&gt;(&#39;&#39;); // Bir BehaviorSubject nesnesi oluşturulur. Bu nesne, form değerini tutar.<br><br>  public formValue$ = this.formValueSubject.asObservable(); // BehaviorSubject&#39;ın observable&#39;ına erişim için bir property tanımlanır.<br><br>  onFormSubmit(value: string) {<br>    this.formValueSubject.next(value); // Yeni form değeri BehaviorSubject&#39;a gönderilir.<br>  }<br>}</pre><p>Bu örnekte, form verileri bir <strong>BehaviorSubject </strong>ile yönetilmektedir. Formdaki herhangi bir değişiklik, <strong>BehaviorSubject’ı</strong> günceller ve bu sayede diğer bileşenler de bu değişiklikten haberdar olur.</p><p><strong>Observable </strong>ve <strong>BehaviorSubject</strong>, Angular uygulamalarında veri akışını yönetmek için güçlü araçlardır. Doğru kavramı doğru yerde kullanmak, uygulamanızın daha okunaklı, daha bakımı kolay ve daha performanslı olmasını sağlar. Bu makalede, bu iki kavramı temel düzeyde inceledik. Daha derinlemesine bilgi edinmek için <a href="https://rxjs.dev/guide/observable">RxJS</a> belgelerini inceleyebilirsiniz.</p><ul><li><strong>Observable</strong>, zaman içinde birden fazla değer yayımlayan bir nesnedir.</li><li><strong>BehaviorSubject</strong>, <strong>Observable’ın </strong>özel bir türüdür ve başlangıç değeri vardır.</li><li>Hangi kavramı kullanacağınız, uygulamanızın gereksinimlerine bağlıdır.</li></ul><p>Umarım bu makale, Angular’da <strong>Observable </strong>ve <strong>BehaviorSubject </strong>konularını anlamanıza yardımcı olmuştur. Bir sonraki makalede görüşmek dileğiyle :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7c148b7e1d8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advanced Query Techniques and Performance Improvements with Entity Framework Core]]></title>
            <link>https://sametuca.medium.com/advanced-query-techniques-and-performance-improvements-with-entity-framework-core-2ebca1aca91d?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/2ebca1aca91d</guid>
            <category><![CDATA[entity-framework-core]]></category>
            <category><![CDATA[dotnet]]></category>
            <category><![CDATA[csharp]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Thu, 20 Jun 2024 13:26:05 GMT</pubDate>
            <atom:updated>2024-06-20T13:26:05.904Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/894/0*l9LoKkUx1TtAES16.png" /></figure><p>Entity Framework Core (EF Core) is a powerful object-relational mapper (ORM) for .NET. While it simplifies database interactions, advanced query techniques and performance optimizations are crucial for efficient and scalable applications. In this article, we’ll explore advanced EF Core querying techniques and performance improvements that mid to senior level developers can leverage.</p><h3>Advanced Query Techniques</h3><h4>1. Eager Loading vs. Lazy Loading vs. Explicit Loading</h4><p><strong>Eager Loading</strong>: This technique loads related entities as part of the initial query. It’s useful when you know you’ll need related data. Use the Include and ThenInclude methods.</p><pre>var orders = context.Orders<br>    .Include(o =&gt; o.Customer)<br>    .Include(o =&gt; o.OrderItems)<br>    .ThenInclude(oi =&gt; oi.Product)<br>    .ToList();</pre><p><strong>Lazy Loading</strong>: Entities are loaded on demand. This can be efficient for small data sets but may lead to multiple database calls for larger sets. Enable lazy loading by installing the Microsoft.EntityFrameworkCore.Proxies package and configuring it.</p><pre>services.AddDbContext&lt;YourDbContext&gt;(options =&gt;<br>    options.UseLazyLoadingProxies().UseSqlServer(Configuration.GetConnectionString(&quot;DefaultConnection&quot;)));</pre><p><strong>Explicit Loading</strong>: This technique loads related entities manually after the initial query. It offers more control over when related data is fetched.</p><pre>var order = context.Orders.Find(orderId);<br>context.Entry(order).Collection(o =&gt; o.OrderItems).Load();</pre><h4>2. Filtering and Sorting</h4><p>Filtering and sorting data directly in queries can significantly improve performance by reducing the amount of data processed.</p><pre>var filteredOrders = context.Orders<br>    .Where(o =&gt; o.Status == OrderStatus.Completed)<br>    .OrderBy(o =&gt; o.OrderDate)<br>    .ToList();</pre><h4>3. Projections with Select</h4><p>Using the Select method to project data into a specific shape reduces the amount of data retrieved and can improve performance.</p><pre>var orderSummaries = context.Orders<br>    .Where(o =&gt; o.Status == OrderStatus.Completed)<br>    .Select(o =&gt; new<br>    {<br>        o.OrderId,<br>        o.OrderDate,<br>        CustomerName = o.Customer.Name,<br>        TotalAmount = o.OrderItems.Sum(oi =&gt; oi.Quantity * oi.UnitPrice)<br>    })<br>    .ToList();</pre><h3>Performance Improvements</h3><h4>1. Indexing</h4><p>Proper indexing can significantly improve query performance. Use the HasIndex method in the OnModelCreating method to define indexes.</p><pre>modelBuilder.Entity&lt;Order&gt;()<br>    .HasIndex(o =&gt; o.OrderDate);</pre><h4>2. Compiled Queries</h4><p>EF Core allows you to compile queries for reuse, which can reduce the overhead of query compilation.</p><pre>var compiledQuery = EF.CompileQuery((YourDbContext context, DateTime startDate) =&gt;<br>    context.Orders.Where(o =&gt; o.OrderDate &gt;= startDate));<br><br>var orders = compiledQuery(context, new DateTime(2023, 1, 1)).ToList();</pre><h4>3. No-Tracking Queries</h4><p>For read-only operations, use no-tracking queries to improve performance by disabling change tracking.</p><pre>var orders = context.Orders.AsNoTracking().ToList();</pre><h4>4. Batching and Transactions</h4><p>Batching multiple operations into a single transaction can reduce the number of database round-trips and improve performance.</p><pre>using (var transaction = context.Database.BeginTransaction())<br>{<br>    context.Add(new Order { /* ... */ });<br>    context.SaveChanges();<br><br>    context.Add(new OrderItem { /* ... */ });<br>    context.SaveChanges();<br><br>    transaction.Commit();<br>}</pre><h4>5. Caching</h4><p>Implementing caching strategies can reduce the load on your database and improve application performance. Consider using in-memory caching or distributed caching solutions like Redis.</p><pre>services.AddMemoryCache();</pre><h3>Conclusion</h3><p>Mastering advanced querying techniques and performance optimizations with Entity Framework Core can lead to significant improvements in application efficiency and scalability. By leveraging these techniques, developers can ensure their applications are not only functional but also performant and robust.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2ebca1aca91d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[.Net Core Api Gateway Ocelot Kullanımı: API Yönlendirme ve Yönetimi]]></title>
            <link>https://sametuca.medium.com/tw-net-core-api-gateway-ocelot-kullan%C4%B1m%C4%B1-api-y%C3%B6nlendirme-ve-y%C3%B6netimi-74701d571891?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/74701d571891</guid>
            <category><![CDATA[dotnet-core]]></category>
            <category><![CDATA[c-sharp-programming]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[ocelots]]></category>
            <category><![CDATA[api-development]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Tue, 13 Feb 2024 17:22:10 GMT</pubDate>
            <atom:updated>2024-02-13T17:22:24.826Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OVrcgZUlSQiFeRnH.png" /><figcaption>Referans: <a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/implement-api-gateways-with-ocelot">Implementing API Gateways with Ocelot — .NET | Microsoft Learn</a></figcaption></figure><p>Günümüzün yazılım geliştirme dünyasında, mikro servis mimarisi giderek daha popüler hale geliyor. Ancak, birden fazla mikro servisi yönetmek ve bunlar arasında istekleri yönlendirmek karmaşık bir süreç olabilir. İşte burada, C# geliştiricilerinin imdadına yetişen bir araç olan Ocelot devreye giriyor. Bu makalede, Ocelot’un ne olduğunu, nasıl kullanıldığını ve neden önemli olduğunu öğreneceksiniz.</p><h4>Ocelot Nedir?</h4><p>Ocelot, .NET ekosisteminde API ağ geçidi işlevselliği sağlamak için kullanılan bir kütüphanedir. Basitçe söylemek gerekirse, Ocelot gelen istekleri alır, bunları işler ve ardından belirli mikro servislere yönlendirir. Bu, birden fazla mikro servis kullanıldığında, istekleri yönetmeyi ve dağıtmayı kolaylaştırır.</p><h4>Neden Ocelot Kullanmalıyız?</h4><ol><li><strong>API Yönlendirme ve Yönetimi</strong>: Ocelot, gelen istekleri yönlendirmek ve farklı mikro servisler arasında trafiği dağıtmak için kullanılabilir. Bu, karmaşık mikro servis mimarilerini daha kolay yönetilebilir hale getirir.</li><li><strong>Filtreleme ve Düzenleme</strong>: Ocelot, gelen istekleri filtreleyebilir ve düzenleyebilir. Örneğin, istekleri kimlik doğrulama veya yetkilendirme için kontrol edebilir ve isteği değiştirebilir.</li><li><strong>Yük Dengeleme</strong>: Ocelot, gelen istekleri belirli mikro servisler arasında yük dengelemesi yaparak dağıtabilir. Bu, servislerin daha verimli ve dengeli bir şekilde çalışmasını sağlar.</li></ol><h4>Nerede Kullanabilirim?</h4><ol><li><strong>Mikro Servis Yönetimi</strong>: Bir e-ticaret uygulaması düşünün. Bu uygulama, kullanıcıların alışveriş yapmasını sağlayan bir arayüze ve stok yönetimini sağlayan bir mikro servise sahip olabilir. Ocelot, kullanıcıların gelen isteklerini doğru mikro servise yönlendirerek bu işlemi kolaylaştırır.</li><li><strong>Kimlik Doğrulama ve Yetkilendirme</strong>: Bir sosyal medya uygulaması için Ocelot, kullanıcıların giriş yaparken kimlik doğrulamasını ve yetkilendirme işlemlerini yönetebilir. Böylece, kullanıcılar doğru bir şekilde yetkilendirilmeden önce istekleri işleyebilir.</li><li><strong>API Sürüm Yönetimi</strong>: Ocelot, farklı API sürümlerine sahip bir uygulamanın trafiğini yönetebilir. Bu, yeni bir API sürümüne geçiş yaparken mevcut kullanıcıları etkilemeden bu geçişi sağlar.</li></ol><p>Örnek olarak visual studio üzerinden 3 farklı proje oluşturalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/481/1*DQW8_pfffpKRRRjVSbc_1g.png" /></figure><p>Burada first api ve second api projeleri için gateway kullanacağız.</p><p>Öncelikle Gateway olarak kullanılacak projeye gerekli paketi kuralım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rh2fqH2EKA4pyJyHfEz8ow.png" /></figure><p>Paket kurulumundan sonra sıra servislerin eklenmesinde.</p><p>Program.cs altında gerekli ayarlamaları yapalım. Ayarlarda biraz sonra oluşturacağımız ocelot.json dosyasının gösterilmesi, ocelot servisine konfigurasyonun verilmesi ve alt satırlarda bulunan ocelot kullanma komutu ile işlemi tamamlayacağımızı görebilirsiniz.</p><pre>public class Program<br>{<br>    public static void Main(string[] args)<br>    {<br>        var builder = WebApplication.CreateBuilder(args);<br><br><br>        builder.Services.AddControllers();<br>        builder.Services.AddEndpointsApiExplorer();<br>        builder.Services.AddSwaggerGen();<br>        builder.Configuration.AddJsonFile($&quot;ocelot.json&quot;, false, true);<br>        builder.Services.AddOcelot(builder.Configuration);<br><br>        var app = builder.Build();<br><br>        if (app.Environment.IsDevelopment())<br>        {<br>            app.UseSwagger();<br>            app.UseSwaggerUI();<br>        }<br>        app.UseOcelot().Wait();<br><br>        app.UseHttpsRedirection();<br><br>        app.UseAuthorization();<br><br><br>        app.MapControllers();<br><br>        app.Run();<br>    }<br>}</pre><p>Controller içerisinde bir metot ekleyelim. Bu metot her çağırdığımızda aslında o apinin çalıştığını bize söylemesi gerekiyor. Bu örnekte yeterli.</p><pre>    [ApiController]<br>    [Route(&quot;api/[controller]&quot;)]<br>    public class FirstController : Controller<br>    {<br><br>        [HttpGet(&quot;Get&quot;)]<br><br>        public string Get()<br>        {<br>            return &quot;First Api Work&quot;;<br>        }<br><br>    }</pre><p>Aynı controller örneğini oluşturulan diğer api projesi içinde uygulayabilirsiniz.</p><pre>    [ApiController]<br>    [Route(&quot;api/[controller]&quot;)]<br>    public class SecondController : Controller<br>    {<br><br>        [HttpGet(&quot;Get&quot;)]<br>        public string Get()<br>        {<br>            return &quot;Second Api Work&quot;;<br>        }<br>    }</pre><p>Şimdi Ocelot için en önemli adım olan konfigurasyon dosyasını oluşturup düzenlemeye geldik.</p><p>Bu dosya içerisinde gerekli tüm yönlendirmeleri ve sınırlandırmaları yapabiliriz.</p><p>Gateway projesinin hemen altına ocelot.json adlı bir dosya oluşturun.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/262/1*wvMwpzICmc_LIM14i-WdHQ.png" /></figure><pre>{<br>  &quot;Routes&quot;: [<br>    {<br>      &quot;DownstreamPathTemplate&quot;: &quot;/api/first/get&quot;,<br>      &quot;DownstreamScheme&quot;: &quot;https&quot;,<br>      &quot;DownstreamHostAndPorts&quot;: [<br>        {<br>          &quot;Host&quot;: &quot;localhost&quot;,<br>          &quot;Port&quot;: 7079<br>        }<br>      ],<br>      &quot;UpstreamPathTemplate&quot;: &quot;/services/{everything}&quot;,<br>      &quot;UpstreamHttpMethod&quot;: [ &quot;Get&quot;, &quot;Post&quot;, &quot;Put&quot;, &quot;Delete&quot; ]<br>    }<br>  ],<br>  &quot;GlobalConfiguration&quot;: {<br>    &quot;BaseUrl&quot;: &quot;https://localhost:7015&quot;<br>  }<br>}</pre><p>Burada incelememiz gereken noktalar şöyle;</p><p><strong>DownstreamPathTemplate</strong></p><p>Gelen istekler hangi adrese yönlendirilecek?</p><p><strong>DownstreamScheme</strong></p><p>Gelen isteklerden hangi protokol kabul edilecek?</p><p><strong>DownstreamHostAndPorts</strong></p><p>Yönlendirdiğimiz projenin host ve port bilgileri. Burada ben gelen isteği birinci api adresime yönlendireceğim için onun bilgilerini verdim.</p><p>Kafa karıştırıcı bir tarafıda dosyanın sanki tersten yazılmış gibi olması. İlk bakışta bana biraz tuhaf gelsede anlaşılması kolay.</p><p>Dolasıyla ilk konfigurasyonlar aslında nereye yönlendireceğimiz üzerine yapılıyor. Bir sonraki adımda ise hangi istekleri yönlendireceğiz şeklinde.</p><p><strong>UpstreamPathTemplate</strong></p><p>Burada artık hangi istekleri yönlendireceğimizi konfigure etmeye başlıyoruz. Ben ”/services/{everything}”, şeklinde giriş yaptım. Bu şu demek oluyor: <a href="https://localhost:port/services/herhangibirsey">https://localhost:port/services/<strong>herhangibirsey</strong></a><strong> </strong>yazdığımda bu adres beni otomatik olarak yukarıda konfigure ettiğimiz api adresine yönlendirecek.</p><p><strong>UpstreamHttpMethod</strong></p><p>Hangi istek tiplerini kabul edeceğimizi belirtiyoruz.</p><p><strong>BaseUrl</strong></p><p>Gateway projemizin host ve port bilgisi.</p><p>Şimdi projelerimizi multiple olarak ayağa kaldırarak postman üzerinden test edelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/505/1*Zupe-01c1Ji1DZaEZzfUyQ.png" /></figure><p>Görüldüğü üzere konfigurasyon dosyasında belirttiğimiz gibi gelen her isteği ilk apimize yönlendirdik. Şimdi ikinci apimiz içinde yönlendirme işlemi yapabiliriz. Bunun için tekrar json dosyasına dönüp gerekli alanları yazıyoruz.</p><pre>{<br>  &quot;Routes&quot;: [<br>    {<br>      &quot;DownstreamPathTemplate&quot;: &quot;/api/first/get&quot;,<br>      &quot;DownstreamScheme&quot;: &quot;https&quot;,<br>      &quot;DownstreamHostAndPorts&quot;: [<br>        {<br>          &quot;Host&quot;: &quot;localhost&quot;,<br>          &quot;Port&quot;: 7079<br>        }<br>      ],<br>      &quot;UpstreamPathTemplate&quot;: &quot;/services/{everything}&quot;,<br>      &quot;UpstreamHttpMethod&quot;: [ &quot;Get&quot;, &quot;Post&quot;, &quot;Put&quot;, &quot;Delete&quot; ]<br>    },<br>{<br>      &quot;DownstreamPathTemplate&quot;: &quot;/api/second/get&quot;,<br>      &quot;DownstreamScheme&quot;: &quot;https&quot;,<br>      &quot;DownstreamHostAndPorts&quot;: [<br>        {<br>          &quot;Host&quot;: &quot;localhost&quot;,<br>          &quot;Port&quot;: 7080<br>        }<br>      ],<br>      &quot;UpstreamPathTemplate&quot;: &quot;/services-second/{everything}&quot;,<br>      &quot;UpstreamHttpMethod&quot;: [ &quot;Get&quot;, &quot;Post&quot;, &quot;Put&quot;, &quot;Delete&quot; ]<br>    }<br>  ],<br>  &quot;GlobalConfiguration&quot;: {<br>    &quot;BaseUrl&quot;: &quot;https://localhost:7015&quot;<br>  }<br>}</pre><p>Görüldüğü üzere Routes objesinin içerisine yapılan yeni bir tanımlama ile bu işi halledebiliyoruz. Testi bu url üzerinden gerçekleştirirsek ikinci apimizin dönüş yaptığınız görebiliriz.</p><p>Ocelotun konfigurasyon dosyası sadece bunlarla sınırlı değil. Bu makalede sadece routing konusunu işlediğimiz için bununla sınırlı bıraktım. Ocelotun başka ne gibi yetenekleri olduğuna resmi web sayfası üzerindeki okunuşu rahat olan dökümanından öğrenebilirsiniz.</p><p><a href="https://ocelot.readthedocs.io/en/latest/introduction/gettingstarted.html">Getting Started — Ocelot 22.0 documentation</a></p><p>Projenin kaynak adresi -&gt;</p><p><a href="https://github.com/sametuca/NetCoreOcelot">https://github.com/sametuca/NetCoreOcelot</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=74701d571891" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular’da HTTP Interceptor Kullanımı: Veri İsteklerini Kotrol Altına Alma Rehberi]]></title>
            <link>https://sametuca.medium.com/angularda-http-interceptor-kullan%C4%B1m%C4%B1-veri-i%CC%87steklerini-kotrol-alt%C4%B1na-alma-rehberi-77e73db50a36?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/77e73db50a36</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[interceptors]]></category>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[angularjs]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Sat, 10 Feb 2024 15:11:15 GMT</pubDate>
            <atom:updated>2024-02-10T15:11:15.802Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JPn-oMFs_MY1OPDh.png" /></figure><p>Angular, modern web uygulamaları geliştirmek için güçlü bir platformdur. Bununla birlikte, büyük ve karmaşık uygulamaları geliştirirken, dış API’lerle iletişim kurarken veya sunucudan veri alırken bazı zorluklarla karşılaşabiliriz. Bu noktada Angular’ın bize sunduğu HTTP Interceptor’lar devreye girer. Bu makalede, Angular’da interceptor’ların ne olduğunu, neden kullanıldığını ve nasıl uygulandığını öğreneceksiniz.</p><h4>Interceptor Nedir?</h4><p>Angular’da interceptor, HTTP isteklerini ve yanıtlarını ele almak için kullanılan bir araçtır. Bir HTTP isteği gönderilmeden önce veya yanıt alındıktan sonra bu isteği değiştirmemize veya manipüle etmemize olanak tanır. Örneğin, her isteğe otomatik olarak bir başlık eklemek veya hata durumunda özel bir işlem yapmak gibi işlevleri gerçekleştirebilir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/0*6tvD6xuYj8L9PSSj.png" /></figure><h4>Neden Interceptor Kullanılır?</h4><ul><li><strong>Tek Bir Noktadan Kontrol</strong>: Interceptor’lar, uygulamanın farklı yerlerinde yapılan tüm HTTP isteklerini merkezi bir noktada ele almayı sağlar. Bu, kod tekrarını azaltır ve koddaki düzeni artırır.</li><li><strong>Güvenlik ve Yetkilendirme</strong>: İsteklerinizi güvenli hale getirmek ve yetkilendirme kontrolleri eklemek için interceptor’lar kullanabilirsiniz.</li><li><strong>Hata İşleme</strong>: Sunucudan hata yanıtları aldığınızda otomatik olarak özel işlemler gerçekleştirmenizi sağlar.</li><li><strong>Performans İyileştirmeleri</strong>: Önbellekleme gibi performans iyileştirmeleri için kullanılabilirler.</li></ul><h4>Nasıl Kullanılır?</h4><p>Angular’da bir interceptor oluşturmak için öncelikle bir sınıf oluşturmanız gerekir. Bu sınıf, HttpInterceptor arayüzünü uygulamalı ve intercept metodunu içermelidir. Daha sonra, interceptor&#39;ı sağladığınız HTTP istemci servisine eklemeniz gerekir.</p><pre>import { Injectable } from &#39;@angular/core&#39;;<br>import {<br>  HttpEvent,<br>  HttpInterceptor,<br>  HttpHandler,<br>  HttpRequest,<br>} from &#39;@angular/common/http&#39;;<br>import { Observable } from &#39;rxjs&#39;;<br><br>@Injectable()<br>export class MyInterceptor implements HttpInterceptor {<br>  intercept(<br>    req: HttpRequest&lt;any&gt;,<br>    next: HttpHandler<br>  ): Observable&lt;HttpEvent&lt;any&gt;&gt; {<br>    // Burada isteği manipüle edebiliriz<br>    const modifiedReq = req.clone({<br>      headers: req.headers.set(&#39;Authorization&#39;, &#39;Bearer token&#39;),<br>    });<br>    return next.handle(modifiedReq);<br>  }<br>}</pre><p>Yukarıdaki kodu inceleyelim.</p><pre>@Injectable()<br>export class MyInterceptor implements HttpInterceptor {</pre><p>Bu kısım, MyInterceptor adında bir sınıf tanımlar. @Injectable() dekoratörü, sınıfın Angular enjeksiyon sistemine dahil edilebilir olduğunu belirtir. HttpInterceptor arayüzünü uygulayan bir sınıf olduğu için, interceptor&#39;ın temel işlevselliğini sağlar.</p><pre>intercept(<br>  req: HttpRequest&lt;any&gt;,<br>  next: HttpHandler<br>): Observable&lt;HttpEvent&lt;any&gt;&gt; {</pre><p>Bu metod, HttpInterceptor arayüzünden gelir ve bir HTTP isteğini ele almak için kullanılır. İki parametre alır: req, işlenmesi gereken HTTP isteği ve next, işlenmiş isteği devretmek için kullanılan bir HttpHandler. Bu metodun dönüş değeri Observable&lt;HttpEvent&lt;any&gt;&gt;&#39;dir, çünkü isteklerin sonuçlarını işlemek ve devretmek için RxJS&#39;in Observable sınıfını kullanır.</p><pre>// Burada isteği manipüle edebiliriz<br>const modifiedReq = req.clone({<br>  headers: req.headers.set(&#39;Authorization&#39;, &#39;Bearer token&#39;),<br>});</pre><p>Bu bölüm, HTTP isteğini manipüle eder. req.clone() metodu, orijinal isteği kopyalar. Ardından, bu kopyalanan isteğin başlıklarına bir Authorization başlığı ekler. Bu örnekte, bir örnek olarak &quot;Bearer token&quot; bir kimlik doğrulama belirtir. Bu kısmı isteğinizi isteğe göre değiştirmek için kullanabilirsiniz.</p><pre>return next.handle(modifiedReq);</pre><p>Bu satır, değiştirilmiş isteği next nesnesine yönlendirir. next.handle() metodu, isteği gerçekleştirmek ve yanıtı almak için kullanılır. Bu, interceptor&#39;ın isteği değiştirmesine ve ardından değiştirilmiş isteği gerçekleştirmesine olanak tanır.</p><p>Bu şekilde, bu interceptor sınıfı, herhangi bir HTTP isteği gönderilmeden önce “Authorization” başlığını otomatik olarak ekleyecektir.</p><p>Interceptor’ı kullanmak için, providers dizininde interceptor sınıfınızı sağlamanız gerekir:</p><pre>import { NgModule } from &#39;@angular/core&#39;;<br>import { HTTP_INTERCEPTORS } from &#39;@angular/common/http&#39;;<br>import { MyInterceptor } from &#39;./my-interceptor&#39;;<br><br>@NgModule({<br>  providers: [<br>    {<br>      provide: HTTP_INTERCEPTORS,<br>      useClass: MyInterceptor,<br>      multi: true,<br>    },<br>  ],<br>})<br>export class InterceptorModule {}</pre><p>Bu şekilde, interceptor’ınız tüm HTTP isteklerini ele alacaktır.</p><p>Angular’da interceptor kullanmak, HTTP isteklerinizi ve yanıtlarınızı kontrol altına almanın güçlü bir yoludur. Güvenlik, performans, hata işleme ve daha fazlası için interceptor’lar kullanabilir ve uygulamanızın gücünü artırabilirsiniz.</p><p>Bu makalede, interceptor’ların ne olduğunu, neden kullanıldığını ve nasıl uygulandığını öğrendiniz. Artık Angular uygulamanızda interceptor’ları kullanarak daha güvenli, daha hızlı ve daha sağlam bir kod yazabilirsiniz.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=77e73db50a36" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular Server Side Pagination]]></title>
            <link>https://sametuca.medium.com/angular-server-side-pagination-2ccb3bd4a1af?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/2ccb3bd4a1af</guid>
            <category><![CDATA[angular-js-development]]></category>
            <category><![CDATA[materials]]></category>
            <category><![CDATA[server-side-pagination]]></category>
            <category><![CDATA[material-ui]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Sun, 26 Nov 2023 17:33:22 GMT</pubDate>
            <atom:updated>2023-11-26T17:33:22.826Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*a7RyMMckDf2tfoTR.png" /><figcaption><a href="https://cshark.com/wp-content/uploads/2022/02/pagination-comparing-blog-1600x588-1.png">https://cshark.com/wp-content/uploads/2022/02/pagination-comparing-blog-1600x588-1.png</a></figcaption></figure><p>Veri setleri büyüdükçe, tüm verileri bir seferde yüklemek yerine sayfa sayfa yüklemek, yani “<strong>Server Side Pagination</strong>” yani “<strong>Sunucu Taraflı Sayfalama</strong>” kullanmak, performansı ve kullanıcı deneyimini optimize etmek açısından önemli bir rol oynar.</p><h4><strong>Server Side Pagination Nedir?</strong></h4><p>Bu yöntemde, sayfalama işlemi sunucu tarafında gerçekleştirilir ve sadece mevcut sayfa için gerekli olan veriler istemciye gönderilir. Bu, kullanıcının sadece ihtiyaç duyduğu verilere odaklanmasını sağlar ve sayfa yükleme sürelerini önemli ölçüde azaltır.</p><blockquote>Neden Server Side Pagination Kullanmalıyız?</blockquote><h4>Performans:</h4><ul><li>Büyük veri setlerini bir seferde yüklemek, hem sunucu hem de istemci tarafında performans sorunlarına yol açabilir.</li><li>Server Side Pagination, yalnızca görüntülenen veri miktarını minimize ederek daha hızlı sayfa yüklemeleri sağlar.</li></ul><h4>Veri Güncelliği:</h4><ul><li>Server Side Pagination, veritabanındaki değişikliklere anında tepki gösterme yeteneği ile güncel verilerin kullanıcıya sunulmasını sağlar.</li></ul><h4>Veri Güvenliği:</h4><ul><li>Özellikle hassas verilerle çalışıyorsanız, tüm verileri istemci tarayıcısına göndermek yerine sadece gerekli olan verileri almak, güvenlik açısından daha sağlam bir yaklaşımdır.</li></ul><h4>Angular ile Server Side Pagination Nasıl Gerçekleştirilir?</h4><p>Angular, güçlü bir web uygulama çerçevesi olup, Server Side Pagination uygulamak için bir dizi araç ve yöntem sunar. Angular’ın sunduğu bileşenler, servisler ve HTTP istekleri üzerinden Server Side Pagination’ı etkili bir şekilde uygulamayı göreceğiz.</p><p>Adım adım Server Side Pagination’ı uygulamaya başlayacağız. İlk adım olarak, Angular projesinin temelini oluşturmak için gereken adımları göreceğiz.</p><p>Öncelikle server side pagination için API hizmetinin bize sunması gereken bazı özellikler olmalıdır.</p><p>Temelde bize lazım olan özelliklerin şunlar olduklarını söyleyebiliriz.</p><ul><li><strong>data</strong>: Sayfanın içeriğini temsil eder.</li><li><strong>totalCount</strong>: Toplam öğe sayısını belirtir.</li><li><strong>page</strong>: Şu anki sayfa numarasını belirtir.</li><li><strong>pageSize</strong>: Her sayfada kaç öğe olması gerektiğini belirtir.</li></ul><p>Bu özellikler tarafımıza sunan bir API servisini kullanarak başarılı bir şekilde server side pagination yapabiliyoruz.</p><p>Başlangıç olarak bir Angular projesi üretelim.</p><pre>npm install -g @angular/cli</pre><pre>ng new angular-pagination-demo</pre><pre>cd angular-pagination-demo</pre><pre>ng serve</pre><p>Bu komut, geliştirme sunucusunu başlatacak ve varsayılan olarak http://localhost:4200/ adresinde çalışan bir uygulama sunacaktır.</p><p>Projemizde sınıflarımızı oluşturmadan önce API hizmetine bir bakalım.</p><p>Burada konuyu çok dağıtmamak adına hali hazırda bize dummy data sunan bir api adresi kullanacağız.</p><p>Aşağıdaki sitede işimize yarayabilecek endpointler bulunmakta.</p><p><a href="https://reqres.in/">Reqres - A hosted REST-API ready to respond to your AJAX requests</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/959/1*vIzdSWnJrJcdx0VD_EZL6g.png" /></figure><p>Görüldüğü üzere <strong>LIST USERS</strong>’a bir <strong>GET </strong>isteği yaptığımızda bize lazım olan özelliklerle birlikte bir dönüş yapılmakta.</p><p>Bu adrese bir <strong>GET </strong>isteği yapabilmek ve bu isteği yaparken hangi modeli kullanacağımıza geçebiliriz.</p><p>Angular projemize geri dönelim ve bu isteği karşılayacak bir interface üretelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/311/1*3w3vSXQnAo1gGqe4HP_elA.png" /></figure><pre>export interface User {<br>    id: number;<br>    first_name: string;<br>    last_name: string;<br>    email: string;<br>    avatar: string;<br>}<br><br>export interface PagedUserData{<br>    data: User[];<br>    page: number;<br>    per_page: number;<br>    total: number;<br>    total_pages: number;<br>}<br><br>export interface Project {<br>    name: string;<br>    id: number;<br>}</pre><p>Endpointin bize dönüş değerlerine baktığımızda yukarıdaki modeller buna uygun görünmekte. Ana model olarak <strong>PagedUserData</strong> kullanacağız.</p><p>Şimdi <strong>API</strong> hizmetine ulaşacak olan servisimizi yazalım.</p><pre>ng g s user</pre><p>komutu ile projemizde yeni bir servis sınıfı tanımlayabiliriz.</p><pre>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { Injectable } from &#39;@angular/core&#39;;<br>import { Observable } from &#39;rxjs&#39;;<br>import { PagedUserData } from &#39;./app/interfaces/user.interface&#39;;<br><br>@Injectable({<br>  providedIn: &#39;root&#39;<br>})<br>export class UserService {<br><br>  constructor(private http: HttpClient) { }<br><br>  getUserList(pageNumber: Number, pageSize: Number): Observable&lt;PagedUserData&gt; {<br>    const url = `https://reqres.in/api/users?page=${pageNumber}&amp;per_page=${pageSize}`;<br>    return this.http.get&lt;PagedUserData&gt;(url);<br>  }<br>}</pre><p>Sınıfımızı detaylı bir şekilde inceleyelim.</p><h4>Modül ve Kütüphaneler:</h4><pre>import { HttpClient } from &#39;@angular/common/http&#39;;<br>import { Injectable } from &#39;@angular/core&#39;;<br>import { Observable } from &#39;rxjs&#39;;<br>import { PagedUserData } from &#39;./app/interfaces/user.interface&#39;;</pre><ul><li>HttpClient: Angular uygulamalarında HTTP isteklerini yönetmek için kullanılan bir modüldür.</li><li>Injectable: Bu dekoratör, servis sınıfının bir bağımlılık olarak enjekte edilebilir olduğunu belirtir.</li><li>Observable: RxJS kütüphanesinden gelir ve asenkron veri akışını temsil eder.</li><li>PagedUserData: Önceki cevapta oluşturduğunuz kullanıcı verilerini ve sayfalama bilgilerini içeren arayüz.</li></ul><h4>Servis Sınıfı Tanımlama:</h4><pre>@Injectable({<br>  providedIn: &#39;root&#39;<br>})</pre><p>@Injectable dekoratörü, servis sınıfının Angular enjeksiyon sistemi tarafından yönetileceğini belirtir. providedIn: &#39;root&#39; ifadesi, servisin uygulama genelinde paylaşılacağını gösterir.</p><h4>Constructor ve HttpClient Enjeksiyonu:</h4><pre>constructor(private http: HttpClient) { }</pre><p>HttpClient sınıfı, servis sınıfının constructor&#39;ında enjekte edilir. Bu, HTTP istekleri yapmak için kullanılacaktır.</p><h4>getUserList Metodu:</h4><pre>getUserList(pageNumber: Number, pageSize: Number): Observable&lt;PagedUserData&gt; {<br>  const url = `https://reqres.in/api/users?page=${pageNumber}&amp;per_page=${pageSize}`;<br>  return this.http.get&lt;PagedUserData&gt;(url);<br>}</pre><ul><li>getUserList metodu, kullanıcı verilerini çekmek için HTTP GET isteği yapar.</li><li>pageNumber ve pageSize parametreleri, hangi sayfanın ve sayfadaki öğe sayısının alınacağını belirler.</li><li>http.get&lt;PagedUserData&gt;(url): HTTP GET isteği yapar ve bu isteğin tipini PagedUserData olarak belirtir. Bu, RxJS tarafından sağlanan bir Observable döner.</li></ul><p>Sıra bu servisimizi kullanacak olan user-list adındaki componentimizi oluşturmaya geldi.</p><pre>ng g c user-list</pre><p>Komutu ile yeni bir angular componenti oluşturuyoruz.</p><p>Bu işlemden hemen sonra app.component.html dosyasına ekleme yapabiliriz. Selector kısmına dikkat edin. Sizde app-user-list olabilir.</p><pre>&lt;user-list&gt;&lt;/user-list&gt;<br>&lt;router-outlet&gt;&lt;/router-outlet&gt;</pre><p>Projemizde <strong>Material </strong>bileşenlerini kullanacağız. Material kurulumu içinde küçük bir kod yazalım.</p><pre>ng add @angular/material</pre><p><a href="https://material.angular.io/guides">Material dökümanı için -&gt;</a></p><h4><em>user-list.component.ts</em></h4><pre>import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from &#39;@angular/core&#39;;<br>import { merge, Observable, of as observableOf } from &#39;rxjs&#39;;<br>import { catchError, map, startWith, switchMap } from &#39;rxjs/operators&#39;;<br>import { UserService } from &#39;src/userservice.service&#39;;<br>import { MatPaginator } from &#39;@angular/material/paginator&#39;;<br>import { MatTableDataSource } from &#39;@angular/material/table&#39;;<br>import { User, PagedUserData } from &#39;../interfaces/user.interface&#39;;<br><br>@Component({<br>  selector: &#39;user-list&#39;,<br>  templateUrl: &#39;./user-list.component.html&#39;,<br>  styleUrls: [&#39;./user-list.component.css&#39;]<br>})<br>export class UserListComponent {<br><br>  dataSource = new MatTableDataSource&lt;User&gt;();<br>  @ViewChild(&#39;paginator&#39;) paginator: MatPaginator;<br><br>  pageSizes = [3, 5, 7];<br>  totalData: number = 7;<br>  isLoading = false;<br><br>  displayedColumns: string[] = [<br>    &#39;id&#39;,<br>    &#39;first_name&#39;,<br>    &#39;last_name&#39;,<br>    &#39;email&#39;,<br>    &#39;avatar&#39;,<br>  ];<br>  UserData: User[];<br><br>  constructor(private userService: UserService, private cdr: ChangeDetectorRef) { }<br><br>  getUserListTableData$(pageNumber: number, pageSize: number): Observable&lt;PagedUserData&gt; {<br>    return this.userService.getUserList(pageNumber, pageSize);<br>  }<br><br>  ngAfterViewInit() {<br>    this.dataSource.paginator = this.paginator;<br><br>    merge(this.paginator.page)<br>      .pipe(<br>        startWith({}),<br>        switchMap(() =&gt; {<br>          this.isLoading = true;<br>          return this.getUserListTableData$(<br>            this.paginator.pageIndex + 1,<br>            this.paginator.pageSize<br>          ).pipe(catchError(() =&gt; observableOf(null)));<br>        }),<br>        map((userTableData) =&gt; {<br>          if (userTableData == null) return [];<br>          this.totalData = userTableData.total;<br>          this.isLoading = false;<br>          return userTableData.data;<br>        })<br>      )<br>      .subscribe((userData) =&gt; {<br>        this.UserData = userData;<br>        this.dataSource = new MatTableDataSource(this.UserData);<br>        this.cdr.detectChanges();<br>      });<br>  }<br><br>}</pre><p>Karmaşıkmı geldi? :) Biraz bakalım. Öncelikle constructorda bir servis enjeksiyonu yaparak biraz önce oluşturduğumuz servisi inject ediyoruz.</p><p>Sonrasında <strong>getUserListTableData </strong>fonksiyonu ile servisimize ulaşacak ve önyüzden topladığımız verileri <strong>args </strong>olarak gönderebileceğiz.</p><p>ngAfterViewInit metodu, bileşenin <strong>view </strong>(görünüm) bileşeninin oluşturulduktan ve görüntülendikten hemen sonra çalıştırılır.</p><p>Dolasıyla tablo işleyişini bu fonksiyonun içerisine yazabiliriz.</p><p>merge(this.paginator.page): MatPaginator&#39;daki sayfa değişikliklerini izleyen bir <strong>Observable </strong>oluşturur. Yani, sayfalandırıcıda bir değişiklik olduğunda bu değişiklikleri yakalayabiliriz.</p><p>pipe(...) ve switchMap(() =&gt; {...}): Bu kısımda, sayfa değiştikçe çalışacak olan işlemler tanımlanır.</p><ul><li>switchMap: Her sayfa değişikliğinde, getUserListTableData$ metodunu çağırır. Bu metot, servis aracılığıyla kullanıcı listesi verilerini getirir.</li><li>catchError(() =&gt; observableOf(null)): Eğer bir hata olursa, bu hatayı yakalar ve null ile birlikte bir Observable döner.</li></ul><p>map((userTableData) =&gt; {...}): getUserListTableData$ metodunun döndüğü veriyi işler.</p><ul><li>if (userTableData == null) return [];: Eğer veri yoksa, boş bir dizi döndürür.</li><li>this.totalData = userTableData.total;: Toplam veri sayısını günceller.</li><li>this.isLoading = false;: Yükleniyor durumunu kapatır.</li><li>return userTableData.data;: Kullanıcı verilerini döndürür.</li></ul><p>.subscribe((userData) =&gt; {...}): En sonunda, bu işlemleri dinlemek üzere bir subscribe işlemi gerçekleştirilir.</p><ul><li>this.UserData = userData;: Kullanıcı verilerini günceller.</li><li>this.dataSource = new MatTableDataSource(this.UserData);: MatTableDataSource&#39;ı günceller.</li><li>this.cdr.detectChanges();:</li></ul><blockquote><em>Değişiklik dedektörünü çalıştırır, böylece Angular, component&#39;in durumundaki değişiklikleri algılar ve günceller.</em></blockquote><p>Bir sonraki adımda; bu komponent içerisinde kullanacağımız bileşenleri modül olarak eklememizde gerekmekte.</p><p>Modülleri isterseniz tek tek <strong>app.module </strong>sayfasını içerisine ekleyebilir istersenizde daha düzenli olması için ayrı bir modül sınıfı yazarak, ana modül sınıfınızda bu sınıfı gösterebilirsiniz.</p><h4>mt-components.module.ts</h4><pre>import { NgModule } from &#39;@angular/core&#39;;<br>import { CommonModule } from &#39;@angular/common&#39;;<br><br>import { MatTableModule } from &#39;@angular/material/table&#39;;<br>import { MatInputModule } from &#39;@angular/material/input&#39;;<br>import { MatSelectModule } from &#39;@angular/material/select&#39;;<br>import { MatCardModule } from &#39;@angular/material/card&#39;;<br>import { MatSortModule } from &#39;@angular/material/sort&#39;;<br>import { MatPaginatorModule } from &#39;@angular/material/paginator&#39;;<br>import { MatProgressBarModule } from &#39;@angular/material/progress-bar&#39;;<br><br>@NgModule({<br>    declarations: [],<br>    imports: [<br>        MatTableModule,<br>        CommonModule,<br>        MatInputModule,<br>        MatSelectModule,<br>        MatCardModule,<br>        MatSortModule,<br>        MatPaginatorModule,<br>        MatProgressBarModule,<br>    ],<br>    exports: [<br>        MatTableModule,<br>        MatInputModule,<br>        MatSelectModule,<br>        MatCardModule,<br>        MatSortModule,<br>        MatPaginatorModule,<br>        MatProgressBarModule,<br>    ],<br>})<br>export class MaterialComponentsModule { }</pre><p>Oluşturulan modül dosyasını ana modül dosyamıza referans edelim.</p><h4>app.module.ts</h4><pre>import { NgModule } from &#39;@angular/core&#39;;<br>import { BrowserModule } from &#39;@angular/platform-browser&#39;;<br>import { HttpClientModule } from &#39;@angular/common/http&#39;;<br>import { AppRoutingModule } from &#39;./app-routing.module&#39;;<br>import { AppComponent } from &#39;./app.component&#39;;<br>import { BrowserAnimationsModule } from &#39;@angular/platform-browser/animations&#39;;<br>import { UserListComponent } from &#39;./user-list/user-list.component&#39;;<br>import { MatTableModule } from &#39;@angular/material/table&#39;;<br>import { MatPaginatorModule } from &#39;@angular/material/paginator&#39;;<br>import { MaterialComponentsModule } from &#39;src/shared/metarial-components.module&#39;;<br><br>@NgModule({<br>  declarations: [<br>    AppComponent,<br>    UserListComponent,<br>  ],<br>  imports: [<br>    BrowserModule,<br>    AppRoutingModule,<br>    BrowserAnimationsModule,<br>    HttpClientModule,<br>    MatTableModule,<br>    MatPaginatorModule,<br>    MaterialComponentsModule<br>  ],<br>  providers: [],<br>  bootstrap: [AppComponent]<br>})<br>export class AppModule { }</pre><p>imports dizisinin en alt satırında MaterialComponentsModule olarak referans ettik.</p><p>Artık Material Components’e ait çeşitli araçları kullanabileceğiz.</p><p>Material component gerekli değil. Çok daha farklı yapılar kullanarakta tablolar oluşturabilir ve yönetebilirsiniz. Material yapısıda gördüğüm kadarıyla popüler ve şık görünmekte.</p><p>Şimdi önyüz tasarımımızı yapalım.</p><h4>user-list.component.ts</h4><pre>&lt;table mat-table [dataSource]=&quot;dataSource&quot; class=&quot;mat-elevation-z8&quot;&gt;<br>    &lt;ng-container [matColumnDef]=&quot;column&quot; *ngFor=&quot;let column of displayedColumns&quot;&gt;<br>        &lt;th mat-header-cell *matHeaderCellDef&gt;{{ column }}&lt;/th&gt;<br>        &lt;td mat-cell *matCellDef=&quot;let usr&quot;&gt;{{ usr[column] }}&lt;/td&gt;<br>    &lt;/ng-container&gt;<br><br>    &lt;tr mat-header-row *matHeaderRowDef=&quot;displayedColumns&quot;&gt;&lt;/tr&gt;<br>    &lt;tr mat-row *matRowDef=&quot;let usrRow; columns: displayedColumns&quot;&gt;&lt;/tr&gt;<br>&lt;/table&gt;<br>&lt;mat-progress-bar mode=&quot;indeterminate&quot; *ngIf=&quot;isLoading&quot;&gt;&lt;/mat-progress-bar&gt;<br>&lt;mat-paginator #paginator [length]=&quot;totalData&quot; [pageSizeOptions]=&quot;pageSizes&quot; showFirstLastButtons&gt;&lt;/mat-paginator&gt;</pre><p>Şimdi önyüzün nasıl göründüğüne bir bakalım.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F888451003%3Fapp_id%3D122963&amp;dntp=1&amp;display_name=Vimeo&amp;url=https%3A%2F%2Fvimeo.com%2F888451003&amp;image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1759574130-d9fc13a5d0344fc4d862d90566f55e654ede326ef9264e13ae9bb237a93e3693-d_1280&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vimeo" width="1690" height="380" frameborder="0" scrolling="no"><a href="https://medium.com/media/4839c549e6e47d4170fe5118667d4d88/href">https://medium.com/media/4839c549e6e47d4170fe5118667d4d88/href</a></iframe><h4>Proje repo</h4><p><a href="https://github.com/sametuca/ng-serverside-pagination">GitHub - sametuca/ng-serverside-pagination</a></p><p>Makalemiz burada son buluyor. Okuduğunuz için teşekkür ederim. Bir sonraki makalede görüşmek üzere. Hoşçakalın..</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2ccb3bd4a1af" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[.NET Core API + ASP.NET Identity, JWT Authorization ve Authentication]]></title>
            <link>https://sametuca.medium.com/net-core-api-asp-net-identity-jwt-authorization-ve-authentication-dbecafc90609?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/dbecafc90609</guid>
            <category><![CDATA[asp-net-core-jwt]]></category>
            <category><![CDATA[c-sharp-programming]]></category>
            <category><![CDATA[jwt-authentication]]></category>
            <category><![CDATA[aspnetcore]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Tue, 01 Aug 2023 00:12:32 GMT</pubDate>
            <atom:updated>2023-08-01T00:22:41.921Z</atom:updated>
            <content:encoded><![CDATA[<p>Merhabalar. Bu makalemizde .Net Core Web API JWT ile kimlik doğrulama işlemlerini yapacağız. Ancak ilk olarak JWT nedir bundan kısaca bahsedelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gnpLoXMgxNw_0HzC" /><figcaption><em>Görsel Kaynak : </em><a href="https://jwt.io/"><em>jwt.io</em></a></figcaption></figure><p>Yukarıda gördüğünüz gibi 3 bölümden oluşan bir biletten bahsediyoruz.</p><h3>Header</h3><p>Genel olarak jwt türü ve algoritması(RSA, SHA256) hakkında bilgi verir.</p><h3>Payload</h3><p>En önemli verilerin tutulduğu teknik olarak güvenceye almak istediklerimizin yer aldığı (tokenin süresi, kullanıcı ait bilgiler gibi) bilgiler içerir.</p><h3>Signature</h3><p>Son kısım ise aynı zamanda base64url kodlu olan imzadır. header, payload, key ve son olarak header kısmında belirtilen algoritmanın işlenmiş halidir. Sunucu bu yol ile header veya payload kısmında bir değişilik olup olmadığını ve doğru kişiden mi geldiğini kontrol eder.</p><h3>Peki JWT Nasıl Çalışır?</h3><p>Örnek olarak bir e-ticaret sitesine kullanıcı bilgileriniz ile giriş yapacaksınız. İlk adımda bilgileriniz sunucu tarafında kontrol edilir eğer kullanıcı bilgileriniz doğru ise sunucu tarafında tutulan secret-key ile size bir token üretilir. Bu token size gönderilir ve yeni bir sunucu tarafına yapılacak olan istekte sunucuya token ile gidersiniz. Sunucu token’ı public key ile çözer.</p><p>Daha iyi anlaşılması için aşağıda ki görseli inceleyebiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ltEDvb3Keo7X5fNE" /><figcaption><em>Görsel Kaynak : </em><a href="https://dev.to/ronakvsoni/log-in-with-jwt-authentication-in-rails-and-react-1382">https://dev.to/ronakvsoni/log-in-with-jwt-authentication-in-rails-and-react-1382</a></figcaption></figure><p>Peki sıfırdan JWT ile yetkilendirme kullanan bir api uygulaması yazarak işe başlayalım.</p><p>Projemiz .Net Core Web API projesi olacak. Konunun dışına çıkmamak adına pattern kullanmayacağız. İlk olarak projemizi oluşturalım. Devamında klasörlerimizi oluşturalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/572/0*A_6zISWINPDmTxxe" /></figure><p>hemen sonra gerekli paketleri nuget üzerinden kurabiliriz. Paketler dotnet6&#39;a uygun olarak kurulduğundan siz kendi .net sürümünüze uygun olanı seçmelisiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*yP5t8OAV6N6oBJ53" /></figure><p>İlk olarak daha sonra tekrar dönmeyelim diye ileride kullanacağımız sınıflarımızı oluşturalım. Uygulamada 3 farklı rol olacak.</p><ol><li><strong>Administrator</strong></li><li><strong>Moderator</strong></li><li><strong>User</strong></li></ol><p>Bu rolleri bir enum içerisinde tutacağız. İlgili sınıfı oluşturalım.</p><pre>public class Authorization<br>    {<br>        public enum Roles<br>        {<br>            Administrator,<br>            Moderator,<br>            User<br>        }<br>        public const string default_username = &quot;user&quot;;<br>        public const string default_email = &quot;user@secureapi.com&quot;;<br>        public const string default_password = &quot;Pa$$w0rd.&quot;;<br>        public const Roles default_role = Roles.User;<br>    }</pre><p>Görüldüğü üzere default olarak verilen değerler var. Bu değerleri bir sonra ki adımlarda kullanacağız.</p><p>Sıra context sınıflarımızı oluşturmaya geldi. 2 adet context sınıfımız olacak. Biliyoruz ki context sınıfları veritabanı ile uygulamamız arasında köprü görevi gören bir yapıdır. İlk olarak bu yapıya ihtiyacımız var.</p><pre>public class ApplicationDbContext : IdentityDbContext&lt;ApplicationUser&gt;<br>    {<br>        public ApplicationDbContext(DbContextOptions&lt;ApplicationDbContext&gt; options):base(options)<br>        {<br>}<br>    }</pre><p>görüldüğü üzere IdentityDbContext base olarak alınmış ve bu sınıf generic. İçerisine ise ApplicationUser sınıfını verdik. Bu sınıf MsIdentity kütüphanesinde custom kullanıcı bilgilerini kullanmamız için gerekli. Yeni bir sınıf oluşturalım ve adını ApplicationUser olarak belirleyelim.</p><pre>public class ApplicationUser : IdentityUser<br>    {<br>        public string FirstName { get; set; }<br>        public string LastName { get; set; }<br>    }</pre><p>Dikkat ederseniz IdentityUser sınıfından kalıtım alarak bu sınıfı genişlettik. Sadece ek olarak first ve last name bilgilerinide kullanacağımız için gerekli 2 alanı eklemiş bulunuyoruz. Daha fazla field eklenebilir orası size kalmış. Sıra ikinci context sınıfımıza geldi. Bu sınıfımız uygulamamız ayağa kalktığı anda veritabanına default değerler gönderecek. Bir çok projede Seed şeklinde kullanılmaktadır.</p><p>Yeni bir sınıf oluşturalım ve adını ApplicationDbContextSeed olarak belirleyelim.</p><pre>public class ApplicationDbContextSeed<br>    {<br>        public static async Task SeedEssentialAsync(UserManager&lt;ApplicationUser&gt; userManager,<br>            RoleManager&lt;IdentityRole&gt; roleManager)<br>        {<br>            //Seed roles<br>            await roleManager.CreateAsync(new IdentityRole(Authorization.Roles.Administrator.ToString()));<br>            await roleManager.CreateAsync(new IdentityRole(Authorization.Roles.Moderator.ToString()));<br>            await roleManager.CreateAsync(new IdentityRole(Authorization.Roles.User.ToString()));<br>//Seed Default User<br>            var defaultUser = new ApplicationUser { UserName =Authorization.default_username, <br>                Email = Authorization.default_email,<br>                EmailConfirmed=true,<br>                PhoneNumberConfirmed = true,<br>            };<br>            if (userManager.Users.All(u=&gt;u.Id!=defaultUser.Id))<br>            {<br>                await userManager.CreateAsync(defaultUser, Authorization.default_password);<br>                await userManager.AddToRoleAsync(defaultUser, Authorization.default_role.ToString());<br>            }<br>        }<br>    }</pre><p>Bu sınıfta ise, Identity ile kullanıma açık olan UserManager&lt;ApplicationUser&gt; sınıfına biraz önce oluşturduğumuz sınıfı verdik. Aynı zamanda roller ile de çalışacağımız için hazır olarak gelen RoleManager&lt;IdentityRole&gt; sınıfımızı generic olarak veriyoruz. Sonrasında roller ile daha detaylı işlemler yapacağız. Ancak bu adım için yeterli.</p><p>Sınıfımızı incelersek; asenkron şekilde 3 farklı rol eklenmekte. Bu rolleri default olarak daha önce oluşturduğumuz sınıfta ki değerleri veriyoruz. Rol ve kullanıcı bilgilerini default olarak setledikten sonra son aşamada veritabanında bu kaydın aynısının var olup olmadığını kontrol ediyor eğer yok ise kaydediyoruz.</p><pre>if (userManager.Users.All(u=&gt;u.Id!=defaultUser.Id))<br>            {<br>                await userManager.CreateAsync(defaultUser, Authorization.default_password);<br>                await userManager.AddToRoleAsync(defaultUser, Authorization.default_role.ToString());<br>            }</pre><p>Oluşturduğumuz yapıları Code First yöntemi ile veritabanına yansıtmamız gerekiyor. İlk olarak AppSettings.json dosyasının içerisine aşağıda gördüğünüz alanın size uygun halini yazınız.</p><pre>&quot;ConnectionStrings&quot;: {<br>    &quot;DevConnection&quot;: &quot;Data Source=localhost;Initial Catalog=SecureDb;Integrated Security=True&quot;<br>  },</pre><p>Appsettings.json dosyasındayken JWT için gerekli olan anahtar ve geçerlilik süresini de burada tutabileceğimizden geri dönmemek adına şimdi yazabiliriz.</p><pre>{<br>  &quot;Logging&quot;: {<br>    &quot;LogLevel&quot;: {<br>      &quot;Default&quot;: &quot;Information&quot;,<br>      &quot;Microsoft&quot;: &quot;Warning&quot;,<br>      &quot;Microsoft.Hosting.Lifetime&quot;: &quot;Information&quot;<br>    }<br>  },<br>  &quot;AllowedHosts&quot;: &quot;*&quot;,<br>  &quot;ConnectionStrings&quot;: {<br>    &quot;DevConnection&quot;: &quot;Data Source=localhost;Initial Catalog=SecureDb;Integrated Security=True&quot;<br>  },<br>  &quot;JWT&quot;: {<br>    &quot;key&quot;: &quot;C1CF4B7DC4C4175B6618DE4F55CA4&quot;,<br>    &quot;Issuer&quot;: &quot;SecureApi&quot;,<br>    &quot;Audience&quot;: &quot;SecureApiUser&quot;,<br>    &quot;DurationInMinutes&quot;: 60<br>  }<br>}</pre><p>appsettings.json dosyası altında işimiz bittikten sonra migration işlemine başlayalım.</p><p>Bir sonra ki sınıfımız ise bir kullanıcıya rol eklemesi yapılırken kullanacağımız sınıf. Bu sınıf içerisinde kullanıcıya ait olan mail, şifre ve rol bilgisini tutacak. Tools \ NuGet Package Manager \ Package Manager Console &#39; u açalım ve aşağıda ki 2 kodu sırasıyla yazalım. Oluşabilecek bir hata da Entity Framework varlığını ve versiyonunu kontrol etmenizi tavsiye ederim.</p><pre>Add-Migration Initial</pre><pre>Update-Database</pre><p>Artık gerekli tablolarımız veritabanımıza yansıtıldı. Şimdi sınıflarımızı oluşturmaya devam edelim.</p><p>Kullanıcının ilk olarak sistemde kayıtlı olduğunu bilmemiz var ise rollerini görmemiz gerekir. sonrasında ise authorization işlemi gerçekleştirilecektir.</p><p>Yeni bir sınıf oluşturalım ve adını AuthenticationModel olarak belirleyelim.</p><pre>public struct AuthenticationModel<br>    {<br>        public string Message { get; set; }<br>        public bool IsAuthenticated { get; set; }<br>        public string UserName { get; set; }<br>        public string Email { get; set; }<br>        public List&lt;string&gt; Roles { get; set; }<br>        public string Token { get; set; }<br>    }</pre><pre>public class AddRoleModel<br>    {<br>        [Required]<br>        public string Email { get; set; }<br>        [Required]<br>        public string Password { get; set; }<br>        [Required]<br>        public string Role { get; set; }<br>    }</pre><p>Şimdi sıra geldi bir JWT sınıfı oluşturmaya. JWT ile ilgili bize gerekli olan verileri tutacak bir sınıf gerekmekte. Yeni bir sınıf oluşturup adını JWT olarak belirleyelim.</p><pre>public class JWT<br>    {<br>        public string Key { get; set; }<br>        public string Issuer { get; set; }<br>        public string Audience { get; set; }<br>        public double DurationInMinutes { get; set; }<br>    }</pre><p>Anahtar ve bu biletin geçerlilik süresi vs. üzerinde işlem yapmamız için gerekli alanları yazıyoruz.</p><p>Eklememiz gereken bir başka sınıf ise RegisterModel. Bu sınıfı ile bir kullanıcının sisteme kayıt olması aşamasında kullanacağız.</p><pre>public class RegisterModel<br>    {<br>        [Required]<br>        public string FirstName { get; set; }<br>        [Required]<br>        public string LastName { get; set; }<br>        [Required]<br>        public string UserName { get; set; }<br>        [Required]<br>        public string Email { get; set; }<br>        [Required]<br>        public string Password { get; set; }<br>    }</pre><p>Alanların gerekli olduğunu belirtmek için Required ile işaretlediğimizden emin olalım.</p><p>Yukarıda bahsettiğim gibi kullanıcının bilgilerinin doğruluğunu kontrol ettikten sonra kullanıcıya token vermemiz gerektiği. Bu sebeple kullanıcının mail ve şifresi üzerinde işlem yapabileceğimiz bir modele ihtiyacımız var. Yeni bir sınıf oluşturalım ve adını TokenRequestModel olarak belirleyelim.</p><pre>public class TokenRequestModel<br>    {<br>        [Required]<br>        public string Email { get; set; }<br>        [Required]<br>        public string Password { get; set; }<br>    }</pre><p>Kullanıcı bu bilgileri kullanarak token isteğinde bulunabilecek. Artık sıra geldi servisimizi yazmaya. Bir interface üretelim ve kullanacağımız metot imzalarını yazalım.</p><pre>public interface IUserService<br>    {<br>        Task&lt;string&gt; RegisterAsync(RegisterModel model);<br>        Task&lt;AuthenticationModel&gt; GetTokenAsync(TokenRequestModel model);<br><br>        Task&lt;string&gt; AddRoleAsync(AddRoleModel model);<br>    }</pre><ol><li>Kullanıcının sisteme üye olması için gereken ve kullanıcıdan bir RegisterModel bekleyen metot.</li><li>Kullanıcının bilgilerini doğruladıktan sonra ona bir AuthenticationModel içerisinde Token döneceğimiz ve kendisinden TokenRequestModel beklediğimiz metot.</li><li>Kullanıcıya rol bazlı işlem yapmak için AddRoleModel sınıfını beklediğimiz metot.</li></ol><p>Şimdi bu oluşturduğumuz arayüzü yeni bir sınıf oluşturarak implement edelim.</p><pre>public class UserService : IUserService<br>    {<br>        private readonly UserManager&lt;ApplicationUser&gt; _userManager;<br>        private readonly RoleManager&lt;IdentityRole&gt; _roleManager;<br>        private readonly JWT _jwt;<br>        public UserService(UserManager&lt;ApplicationUser&gt; userManager, RoleManager&lt;IdentityRole&gt; roleManager, IOptions&lt;JWT&gt; jwt)<br>        {<br>            _userManager = userManager;<br>            _roleManager = roleManager;<br>            _jwt = jwt.Value;<br>        }</pre><p>Kullanacağımız metotları doldurmadan önce gerekli DI işlemlerini yapıyoruz. UserManager ve RoleManager sınıfları ile gelen kullanıcı bilgilerini doğrulayacağız. IOption ile JWT modeline uygun olarak appsettings.json içerisinde oluşturduğumuz alanlara ulaşabiliriz.</p><p>İlk fonksiyonumuz Register. Bu fonksiyon ile kullanıcı sisteme kayıt olabilecek</p><pre>public async Task&lt;string&gt; RegisterAsync(RegisterModel model)<br>        {<br>//ApplicationUser sınıfının instancesini alarak içerisini gelen modeldeki bilgilere göre doldurduk. Bu işlemi yapmamızın sebebi userManager sınıfı bizden parametre olarak bu modeli beklemektedir.<br>            var user = new ApplicationUser<br>            {<br>                UserName = model.UserName,<br>                Email = model.Email,<br>                FirstName = model.FirstName,<br>                LastName = model.LastName,<br><br>            };<br><br>            var userWithSameEmail = await _userManager.FindByEmailAsync(model.Email);<br>            if (userWithSameEmail == null)<br>            {<br>                var result = await _userManager.CreateAsync(user, model.Password);<br>                if (result.Succeeded)<br>                {<br>                    await _userManager.AddToRoleAsync(user, Authorization.default_role.ToString());<br>                }<br>                return $&quot;User Registered {user.UserName}&quot;;<br>            }<br>            else<br>            {<br>                return $&quot;Email {user.Email } is already registered.&quot;;<br>            }<br><br><br>        }</pre><ol><li>ApplicationUser sınıfının instancesini alarak içerisini gelen modeldeki bilgilere göre doldurduk. Bu işlemi yapmamızın sebebi userManager sınıfı bizden parametre olarak bu modeli beklemektedir.</li><li>Kullanıcının mail adresi ile varlığının kontrolünü sağlıyoruz.</li></ol><p>3.Eğer kullanıcı yok ise artık kayıt işlemine başlayabiliriz. Bu durumda ilk olarak kullanıcı bilgisini FindByEmailAsync metodu ile kontrol ediyoruz. CreateAsync metoduna göndererek kullanıcıyı oluşturuyoruz. Oluşturulan kullanıcıya bir rol ataması için AddToRoleAsync metoduna default rol bilgisini veriyoruz.</p><p>“AddRoleAsync” metodumuz henüz hazır değil. Kullanıcıya rol ekleme işlemleri için aşağıda ki gibi metodu dolduralım.</p><pre>public async Task&lt;string&gt; AddRoleAsync(AddRoleModel model)<br>        {<br>            var user = await _userManager.FindByEmailAsync(model.Email);<br>            if (user==null)<br>            {<br>                return $&quot;No Accounts Registered with {model.Email}.&quot;;<br>            }<br>            if(await _userManager.CheckPasswordAsync(user,model.Password))<br>            {<br>                var roleExists = Enum.GetNames(typeof(Authorization.Roles))<br>                    .Any(x =&gt; x.ToLower() == model.Role.ToLower());<br>                if (roleExists)<br>                {<br>                    var validRole = Enum.GetValues(typeof(Authorization.Roles)).Cast&lt;Authorization.Roles&gt;()<br>                        .Where(x =&gt; x.ToString().ToLower() == model.Role.ToLower())<br>                        .FirstOrDefault();<br><br>                    await _userManager.AddToRoleAsync(user, validRole.ToString());<br>                    return $&quot;Added {model.Role} to user {model.Email}.&quot;;<br>                }<br>                return $&quot;Role {model.Role} not found.&quot;;<br>            }<br>            return $&quot;Incorrect Credentials for user {user.Email}.&quot;;<br>        }</pre><p>Register işlemlerinde yapılanların bir benzerini burada yaparak ilk kullanıcıyı bulup sonrasında rol eklemesi yapıyoruz.</p><p>Sıra en önemli aşama olan kullanıcıya token üretmede.</p><pre>public async Task&lt;AuthenticationModel&gt; GetTokenAsync(TokenRequestModel model)<br>        {<br>            AuthenticationModel authenticationModel;<br>            var user = await _userManager.FindByEmailAsync(model.Email);<br>            if (user == null)<br>                return new AuthenticationModel { IsAuthenticated = false, Message = $&quot;No Accounts Registered with { model.Email }.&quot; };<br><br>            if (await _userManager.CheckPasswordAsync(user, model.Password))<br>            {<br>                JwtSecurityToken jwtSecurityToken = await CreateJwtToken(user);<br><br>                authenticationModel = new AuthenticationModel<br>                {<br>                    IsAuthenticated = true,<br>                    Message = jwtSecurityToken.ToString(),<br>                    UserName = user.UserName,<br>                    Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken),<br>                    Email = user.Email,<br>                };<br>                var rolesList = await _userManager.GetRolesAsync(user).ConfigureAwait(false);<br>                authenticationModel.Roles = rolesList.ToList();<br>                return authenticationModel;<br>            }<br>            else<br>            {<br>                 authenticationModel = new AuthenticationModel()<br>            {<br>                IsAuthenticated = false,<br>                Message = $&quot;Incorrect Credentials for user {user.Email}.&quot;<br>            };<br>            }<br><br><br>            return authenticationModel;<br>        }</pre><ol><li>İlk olarak gelen modelde ki email bilgisine bakarak kullanıcının verilerini veritabanından çekiyoruz. Sonrasında şifre kontrolü yapıyoruz. Eğer bilgiler doğru ise yeni bir JwtSecurityToken instance alıp bunu CreateJwtToken metodundan dönecek olan token modeli ile dolduruyoruz.</li></ol><p>Oluşturduğumuz AuthenticationModel içerisine kullanıcı ile ilgili token ve diğer bilgileri yazıyoruz.</p><p>Burada kullandığımız CreateJwtToken metodunu dolduralım.</p><pre>private async Task&lt;JwtSecurityToken&gt; CreateJwtToken(ApplicationUser user)<br>        {<br>            var userClaims = await _userManager.GetClaimsAsync(user);<br>            var roles = await _userManager.GetRolesAsync(user);<br>            var roleClaims = new List&lt;Claim&gt;();<br>            for (int i = 0; i &lt; roles.Count; i++)<br>            {<br>                roleClaims.Add(new Claim(&quot;roles&quot;, roles[i]));<br>            }<br>            var claims = new[]<br>            {<br>                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),<br>                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),<br>                new Claim(JwtRegisteredClaimNames.Email, user.Email),<br>                new Claim(&quot;uid&quot;, user.Id)<br>            }<br>            .Union(userClaims)<br>            .Union(roleClaims);<br>            var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwt.Key));<br>            var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);<br>            var jwtSecurityToken = new JwtSecurityToken(<br>                issuer: _jwt.Issuer,<br>                audience: _jwt.Audience,<br>                claims: claims,<br>                expires: DateTime.UtcNow.AddMinutes(_jwt.DurationInMinutes),<br>                signingCredentials: signingCredentials);<br>            return jwtSecurityToken;<br>        }</pre><p>Rollerde dahil olmak üzere kullanıcı ile ilgili bilgilerini alıyoruz. Bir kullanıcının birden fazla rolü olabileceğinden döngü ile kontrol ediyoruz. Sonrasında kullanıcının username, email ve benzersiz bir anahtar oluşturup Claim dizisine ekliyoruz. Son bölümdeappsettings içerisinden key bilgisini okuyarak SymmetricSecurityKey oluşturuyoruz. Hemen altında credantial için oluşturduğumuz anahtar ve kullanacağımız algoritmayı yazıyoruz. Token oluşturmaya hazır hale geldiğinde yeni bir JwtSecurityToken modeli oluşturup bunu geri dönüyoruz.</p><p>Bir sonra ki aşamada Controller oluşturup yaptıklarımızı test etmek kaldı. İlk olarak sadece Authorize olan kullanıcılara bir değer döndürdüğümüz controller ve action oluşturalım. Controllerimiz route ayarlarını unutmayalım.</p><pre>[Route(&quot;api/[controller]&quot;)]<br>    [ApiController]<br>    public class SecuredController : Controller<br>    {<br>        [HttpGet]<br>        public IActionResult GetSecuredData()<br>        {<br>            return Ok(&quot;This Secured Data is available only for Authenticated Users.&quot;);<br>        }<br>    }</pre><p>Bir sonra ki adımda servisimi call edeceğimiz Controlleri oluşturuyoruz. Controllerimiz route ayarlarını unutmayalım.</p><pre>[Route(&quot;api/[controller]&quot;)]<br>    [ApiController]<br><br>    public class UserController : ControllerBase<br>    {<br>        private readonly IUserService _userService;<br>        public UserController(IUserService userService)<br>        {<br>            _userService = userService;<br>        }<br><br><br>        [HttpPost(&quot;register&quot;)]<br>        public async Task&lt;ActionResult&gt; ResultAsync(RegisterModel register)<br>        {<br>            var result = await _userService.RegisterAsync(register);<br>            return Ok(result);<br>        }<br><br>        [HttpPost(&quot;token&quot;)]<br>        public async Task&lt;IActionResult&gt; GetTokenAsync(TokenRequestModel model)<br>        {<br>            var result = await _userService.GetTokenAsync(model);<br>            return Ok(result);<br>        }<br><br>        [HttpPost(&quot;addrole&quot;)]<br>        public async Task&lt;IActionResult&gt; AddRoleAsync(AddRoleModel model)<br>        {<br>            var result = await _userService.AddRoleAsync(model);<br>            return Ok(result);<br>        }<br>    }</pre><p>Tabi ki unutmadan startup.cs içerisinde gerekli konfigurasyonları yapmak zorundayız.</p><pre>public class Startup<br>    {<br>        public Startup(IConfiguration configuration)<br>        {<br>            Configuration = configuration;<br>        }<br><br>        public IConfiguration Configuration { get; }<br><br>        public void ConfigureServices(IServiceCollection services)<br>        {<br>            //AppSettings konfigurasyonu<br>            services.Configure&lt;JWT&gt;(Configuration.GetSection(&quot;JWT&quot;));<br><br>            //DI User Service<br>            services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;().AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();<br>            services.AddScoped&lt;IUserService, UserService&gt;();<br><br>            //DB Contextin eklenmesi<br>            services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;<br>                options.UseSqlServer(<br>                    Configuration.GetConnectionString(&quot;DevConnection&quot;),<br>                    b =&gt; b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));<br><br>            // JWT<br>            services.AddAuthentication(options =&gt;<br>            {<br>                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;<br>                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;<br>            })<br>                .AddJwtBearer(o =&gt;<br>                {<br>                    o.RequireHttpsMetadata = false;<br>                    o.SaveToken = false;<br>                    o.TokenValidationParameters = new TokenValidationParameters<br>                    {<br>                        ValidateIssuerSigningKey = true,<br>                        ValidateIssuer = true,<br>                        ValidateAudience = true,<br>                        ValidateLifetime = true,<br>                        ClockSkew = TimeSpan.Zero,<br>                        ValidIssuer = Configuration[&quot;JWT:Issuer&quot;],<br>                        ValidAudience = Configuration[&quot;JWT:Audience&quot;],<br>                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration[&quot;JWT:Key&quot;]))<br>                    };<br>                });<br>            services.AddControllers();<br>            services.AddSwaggerGen(c =&gt;<br>            {<br>                c.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;sametuca_dev_jwt_v1&quot;, Version = &quot;v1&quot; });<br>            });<br>        }<br><br>        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)<br>        {<br>            if (env.IsDevelopment())<br>            {<br>                app.UseDeveloperExceptionPage();<br>                app.UseSwagger();<br>                app.UseSwaggerUI(c =&gt; c.SwaggerEndpoint(&quot;/swagger/v1/swagger.json&quot;, &quot;sametuca_dev_jwt_v1&quot;));<br>            }<br><br>            app.UseHttpsRedirection();<br><br>            app.UseRouting();<br>            app.UseAuthentication();<br>            app.UseAuthorization();<br><br>            app.UseEndpoints(endpoints =&gt;<br>            {<br>                endpoints.MapControllers();<br>            });<br>        }<br>    }</pre><p>Startup ayarlarımızda bittiğine göre artık uygulamamızı Postman üzerinden test edebiliriz.</p><p>Ben bu tip işlemlerde genel olarak Postman kullanmaktayım. Sizler farklı bir araç kullanabilirsiniz.</p><p><a href="https://www.postman.com/"><em>Postman Resmi Web Sitesi</em></a></p><p>Uygulamayı başlatın ve Postmanüzerinden aşağıda ki görseldeki seçeneklere göre post isteği atın.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/885/0*IIwjbfI57y0wJHLh" /></figure><p>User Registered hashcodemakale şeklinde mesajı gördük. Artık bu isimde bir kullanıcımız sistemde. Şimdi Token ile zenginleştirelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/0*uXrEt8J4bXiRiQ7h" /></figure><p>Artık kullanıcımıza ait sistem tarafından üretilmiş bir Token bulunmakta. Peki bu Tokeni nasıl kullanacağız? Hatırlarsanız sadece Authorize olmuş kullanıcıları kabul ettiğimiz bir Action vardı. Şimdi ona Token bilgimiz ile bir GET isteğinde bulunalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/0*S-1u7aH80fsobrnG" /></figure><p>İşlem bu kadar. Umarım yardımcı olabilmişimdir. Zaman ayırdığınız için teşekkürler. Bir sonraki makalede görüşmek üzere sağlıcakla kalın..</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbecafc90609" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[C# ile ElasticSearch Kullanımı: Güçlü Arama ve Analitik Yetenekleriyle Veritabanı İşlemlerini…]]></title>
            <link>https://sametuca.medium.com/c-ile-elasticsearch-kullan%C4%B1m%C4%B1-g%C3%BC%C3%A7l%C3%BC-arama-ve-analitik-yetenekleriyle-veritaban%C4%B1-i%CC%87%C5%9Flemlerini-d3116ac4572d?source=rss-d063cdda3fa------2</link>
            <guid isPermaLink="false">https://medium.com/p/d3116ac4572d</guid>
            <category><![CDATA[elasticsearch]]></category>
            <category><![CDATA[csharp]]></category>
            <category><![CDATA[elasticsearch-service]]></category>
            <category><![CDATA[dotnet]]></category>
            <dc:creator><![CDATA[Samet UCA]]></dc:creator>
            <pubDate>Wed, 19 Jul 2023 12:33:54 GMT</pubDate>
            <atom:updated>2023-07-19T12:33:54.679Z</atom:updated>
            <content:encoded><![CDATA[<h3>C# ile ElasticSearch Kullanımı: Güçlü Arama ve Analitik Yetenekleriyle Veritabanı İşlemlerini İyileştirmek</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cUmvWeCWk8wz7D9U.png" /><figcaption>Image Source : <a href="https://commons.wikimedia.org/wiki/File:Elasticsearch_logo.svg">https://commons.wikimedia.org/wiki/File:Elasticsearch_logo.svg</a></figcaption></figure><h3>Elasticsearch</h3><p>Elasticsearch’e<strong> </strong>baktığımızda<strong> </strong>açık kaynaklı arama ve analiz motoru olduğunu görüyoruz.</p><p>Kullanım senaryolarında, büyük miktardaki verileri hızlı bir şekilde depolamamıza, aramamıza ve analiz etmek olabilir. Özellikle büyük ölçekli veri arama senaryoları için kullanılır.</p><h3>Çalışma Mantığı</h3><p>Elasticsearch’in çalışma mantığı, bir dizi belgeyi alıp bunları bir indeks içinde depolamasına dayanır. Her belgenin birden çok alanı olabilir ve Elasticsearch, bu alanlara hızlı bir şekilde erişim sağlamak için bir ters indeksleme yapısı kullanır.</p><h3>Ters İndeksleme</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Dm5Te_qSvC4_TIqZ.png" /><figcaption>Image Source : <a href="https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch">https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch</a></figcaption></figure><p>Ters indeksleme, veri depolama ve arama süreçlerini optimize etmek için kullanılan bir yöntemdir. <em>Geleneksel bir indeksleme yönteminin tersine, ters indeksleme, her bir terimin hangi belgede bulunduğunu takip etmek için bir veri yapısı kullanır.</em></p><p>Bir belgenin içeriğini indekslemek için, ters indeksleme işleminde şu adımlar izlenecektir.</p><ol><li>Belgenin içeriği parçalara ayrılır. Örneğin, bir cümledeki her kelime ayrı bir terim olarak kabul edilir.</li><li>Her terim, hangi belgede bulunduğunu referans etmek için bir veri yapısı içinde saklanır.</li><li>Veri yapısında, her terimle ilişkili belgelerin listesi tutulur. Bu liste, ilgili belgenin konumunu veya diğer bilgilerini içerebilir.</li></ol><p>Ters indeksleme, arama sorgularını hızlandırmak için kullanılır. Arama sırasında, istenen terimlerle eşleşen belgelerin listesine hızlı bir şekilde erişilir ve döndürülebilir. Ters indeksleme ayrıca arama sorgularında <em>filtreleme, sıralama ve diğer işlemleri</em> de kolaylaştırır.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DrY6IBVlMFgc73Ir.png" /><figcaption>Image Source : <a href="https://www.knowi.com/blog/what-is-elastic-search/">https://www.knowi.com/blog/what-is-elastic-search/</a></figcaption></figure><blockquote>Bu açıklama yeterli olmadı mı? O zaman kısa bir ara verip şu makaleyi okuyabilirsiniz.</blockquote><blockquote><a href="https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch">https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch</a></blockquote><p>Devam edersek, yeni başlayanlar için, Elasticsearch’i şu şekilde düşünebilirsiniz:</p><blockquote>Bir kitaplığa benzer. Kitaplığınızda birçok kitap bulunur ve bu kitapların içindeki bilgilere hızlı bir şekilde erişmek istersiniz. Elasticsearch, kitapların dizinlenmiş bir sıralama ve kategorilendirme sistemine sahip olduğu bir kitaplık gibidir. İstediğiniz bilgiyi hızlıca bulabilir ve aradığınızı bulmanızı kolaylaştırır.</blockquote><p>Elasticsearch, genellikle büyük ölçekli veritabanları, web siteleri, uygulamalar ve <strong>log </strong>analizleri gibi veri yoğun alanlarda kullanılır. Verileri kolayca arayabilir, filtreleyebilir ve sıralayabilirsiniz.</p><p>Elasticsearch, dağıtık bir yapıya sahiptir, bu da performansı ve ölçeklenebilirliği artırır. Verilerinizi birden fazla sunucuda saklayabilir ve yüksek kullanılabilirlik sağlayabilirsiniz.</p><p>Özetlemek gerekirse, Elasticsearch büyük miktardaki verileri hızlı bir şekilde aramanıza, analiz etmenize ve keşfetmenize olanak tanıyan açık kaynaklı bir arama ve analiz motorudur. Verileri düzenlemek, aramak ve analiz etmek için kullanışlıdır ve genellikle büyük ölçekli veritabanları ve analitik senaryolarında kullanılır.</p><h3>Elasticsearch Kurulum</h3><p>Projemizde elasticsearch kullanmak için ilk olarak resmi web sitesinden indirmemiz gerekmekte.</p><p><a href="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.2-windows-x86_64.zip">https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.2-windows-x86_64.zip</a></p><p>İndirilen dosyayı arşiveden çıkarın.</p><p>Arşiveden çıkarılan klasörün içerisindeki <strong>config </strong>klasörüne gidin.</p><p><strong>elasticsearch.yaml</strong> dosyasını bir metin editörü ile açın.</p><blockquote>xpack.security.enabled: true</blockquote><p>satırını</p><blockquote>xpack.security.enabled: false</blockquote><p>olarak değiştirin.</p><p>Bu durumda elasticSearch kimlik doğrulama işlemini atlamış olacağız. Bunu yapmamızın sebebi bu anlatımın henüz giriş seviyesinde olmasından dolayı güvenlik aşamalarının ilerleyen seviyelere uygun olması.</p><p>Şimdi tekrar elasticsearch anaklasörüne gidin ve bin klasörünü açın.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*sapKuzI3PxfXzBBwBdrqIg.png" /></figure><p>Resimde işaretlediğim <strong>elasticsearch</strong>.bat dosyasını yönetici olarak çalıştırınız.</p><p>Kısa bir süre yükleme gerçekleşecek ve <a href="http://localhost:9200">http://localhost:9200</a> adresine erişim hazır olacaktır.</p><p>Bu adrese gittiğinizde şu JSON verisi ile karşılaşıyorsanız kurulum sorunsuz gerçekleşmiştir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/548/1*MgTZ5YCi7PT5EHs-9MtOvg.png" /></figure><p>Elasticsearch sistem kurulumu tamamlandığına göre artık uygulama geliştirme tarafına geçebiliriz.</p><h3>Uygulama Geliştirme</h3><p>Visual Studio IDE üzerinden çalışma yapacağım. Eğer siz farklı bir IDE kullanıyorsanız orada Console APP üretmeniz ilk aşama için yeterli.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*P8b7xVHKGFc4l1gVyz-3Xw.png" /></figure><p>Proje oluşturulduktan sonra elasticsearch ile iletişim kurabilmek için gerekli bir paket kurmamız lazım.</p><h4>NEST Paketi Nedir? Ne İşe Yarar?</h4><p>NEST, <strong>Elasticsearch </strong>ile etkileşimde bulunmak için kullanılan resmi bir <strong>.NET</strong> istemci kitaplığıdır. <strong>Elasticsearch </strong>ile veri indeksleme, sorgulama, güncelleme, silme gibi işlemleri gerçekleştirmenizi sağlar.</p><p><strong>NEST</strong>, Elasticsearch sorgularınızı ve veri işlemlerinizi daha kolay bir şekilde yapabilirsiniz. <strong>NEST</strong>, <strong>C#</strong>’ın özelliklerinden yararlanarak Elasticsearch ile etkileşimi basitleştirir ve daha okunabilir ve sürdürülebilir kod yazmanıza olanak tanır.</p><h4>NEST Kurulum</h4><p>Projede kullanacağınız NuGet paketlerini yönetmek için NuGet Paket Yöneticisi’ni açın.</p><ul><li>Visual Studio’da “Tools” menüsünden “NuGet Package Manager” seçeneğini seçin ve ardından “Manage NuGet Packages for Solution” seçeneğini tıklayın.</li></ul><ol><li>NuGet Paket Yöneticisi’nde, “Browse” sekmesine geçin.</li><li>Arama kutusuna “NEST” yazın ve arama yapın.</li><li>Sonuçlar arasından “NEST” paketini bulun ve “Install” (Yükle) düğmesine tıklayın.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kNYm2JMNeeYE7-WEJ65mBQ.png" /></figure><p>Kodlama kısmında satır satır ne yapabileceğimize bir bakalım.</p><p>İlk olarak paket kurulumundan sonra bir node üretip <strong>elasticsearch</strong> sunucusuna erişim sağlayacak temsili bir nesne olmalı.</p><pre> var node = new Uri(&quot;http://localhost:9200&quot;);</pre><p>Bir sonraki satırda ihtiyacımız olan <strong>URI </strong>nesnesini kullanarak bir ConnectionSettings nesnesi oluşturmak.</p><h4>ConnectionSettings</h4><p>ConnectionSettings, Elasticsearch istemcisine bağlantı ayarlarını sağlar</p><p>Bu nesne ile belirtilen <strong>Uri, elasticsearch </strong>sunucusuna bağlanır.</p><pre>var settings = new ConnectionSettings(node)</pre><p>Noktalı virgülü unuttumuğumu düşünmeyin bu kodun devamında çeşitli set işlemleri yapacağız.</p><p>Bir sonraki satırda Elasticsearch için varsayılan dizini “sametuca-medium” olarak ayarlıyoruz. Bu, Elasticsearch sunucusunda yapılan birçok işlemde varsayılan dizinin bu değeri kullanacağı anlamına gelir.</p><pre> .DefaultIndex(&quot;sametuca-medium&quot;)</pre><p>Bir satır aşağı inerek “<em>DisableDirectStreaming</em>” yöntemi çağrılarak doğrudan akışı devre dışı bırakır. Bu, Elasticsearch ile iletişimde doğrudan akışın kullanılmayacağı ve istemcinin verileri tamponlayacağı anlamına gelir.</p><pre>.DisableDirectStreaming();</pre><p>Şimdi şuana kadar yazdığımız koda bir bakarsak;</p><pre>var node = new Uri(&quot;http://localhost:9200&quot;);<br>            var settings = new ConnectionSettings(node)<br>                .DefaultIndex(&quot;sametuca-medium&quot;)<br>                .DisableDirectStreaming();</pre><p>Şimdi bize lazım olan ConnectionSettings nesnesini kullanarak bir elasticClient nesnesi oluşturmak. Bu nesne elasticsearch ile etkileşim için gereklidir.</p><pre>var client = new ElasticClient(settings);</pre><p>Bir sonraki adımda artık <strong>elasticsearch </strong>tarafına gönderilecek belgeyi oluşturmamız gerkeiyor.</p><p>Bu belge <strong>elasticsearch’e </strong>gönderilecek verileri temsi edecektir.</p><pre> var document = new MyDocument<br>            {<br>                Id = 1,<br>                Title = &quot;Örnek Belge 1&quot;,<br>                Content = &quot;Elasticsearch medium makalesi için örnek - sametuca&quot;<br>            };</pre><p>Bir sonraki adımda daha önce oluşturduğumuz client örneği ile document adlı belgeyi elasticsearch’e ekleyeceğiz.</p><pre>var indexResponse = client.IndexDocument(document);</pre><p><strong>IndexDocument </strong>fonksiyonu, parametre olarak dizine eklenecek belgeyi alır ve geriye bir <strong>IndexResponse </strong>döner. Bu <strong>response </strong>üzerinden belgenin eklenip eklenmediğini öğrenebiliriz.</p><blockquote>client.IndexDocument(document); <br>yöntemi aracılığıyla gönderilen belge JSON formatında Elasticsearch&#39;e iletilir.</blockquote><p>Bunun dışında eklenirken bir problem yaşarsak bununla ilgili detaylarıda içerecektir.</p><pre>if (indexResponse.IsValid)<br>            {<br>                Console.WriteLine(&quot;Belge başarıyla indekslendi.&quot;);<br>            }<br>            else<br>            {<br>                Console.WriteLine(&quot;Belge indekslenirken hata oluştu: &quot; + indexResponse.DebugInformation);<br>            }</pre><p><strong>indexResponse.IsValid</strong> kontrolüyle işlemin sonucuna göre aksiyon alabiliriz.</p><p>Bu aşamadan sonra bir sorun olmazsa belge eklenecektir. Peki belge eklendikten sonra bu belge için bir <strong>query </strong>yazabilirmiyiz?</p><pre>var searchResponse = client.Search&lt;MyDocument&gt;(s =&gt; s<br>                .Index(&quot;sametuca-medium&quot;)<br>                .Query(q =&gt; q<br>                    .Match(m =&gt; m<br>                        .Field(f =&gt; f.Title)<br>                        .Query(&quot;Elasticsearch medium makalesi için örnek - sametuca&quot;)<br>                    )<br>                )<br>            );</pre><p>Kodu incelediğimizde “sametuca-medium” dizinindeki Title alanında &quot;Elasticsearch&quot; kelimesiyle eşleşen belgeleri arıyoruz. Arama sonucu, nesne olarak döndürülür. Bu nesne, Elasticsearch&#39;ten dönen arama sonucunu içermektedir.</p><pre>if (searchResponse.IsValid)<br>            {<br>                Console.WriteLine(&quot;Arama sonuçları:&quot;);<br>                foreach (var hit in searchResponse.Hits)<br>                {<br>                    Console.WriteLine(&quot;Id: &quot; + hit.Id);<br>                    Console.WriteLine(&quot;Content: &quot; + hit.Source.Content);<br>                    Console.WriteLine();<br>                }<br>            }<br>            else<br>            {<br>                Console.WriteLine(&quot;Arama yapılırken hata oluştu: &quot; + searchResponse.DebugInformation);<br>            }<br><br>            Console.ReadLine();</pre><p>sorguda problem yoksa <strong>searchResponse </strong>nesnesinin <strong>Hits </strong>özelliğini kontrol ediyoruz.</p><h4>Hits</h4><p><strong>Hits, Elasticsearch</strong>’ten dönen arama sonuçlarını temsil eden bir özelliktir. <strong>ISearchResponse&lt;T&gt;</strong> arayüzünde bulunur.</p><p>Uygulama kodları hazır ise artık çalıştırabiliriz. Sonuç aşağıdaki gibi görünecektir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/1*xV0vudME4a4ay38p1IykUg.png" /></figure><p>Kodların tamamı ise şu şekildedir.</p><pre>using Nest;<br><br>namespace elasticsearch_dotnet<br>{<br>    public class MyDocument<br>    {<br>        public int Id { get; set; }<br>        public string Title { get; set; }<br>        public string Content { get; set; }<br>    }<br>    internal class Program<br>    {<br>        static void Main(string[] args)<br>        {<br>            var node = new Uri(&quot;http://localhost:9200&quot;);<br>            var settings = new ConnectionSettings(node)<br>                .DefaultIndex(&quot;sametuca-medium&quot;)<br>                .DisableDirectStreaming();<br>            var client = new ElasticClient(settings);<br><br>            var document = new MyDocument<br>            {<br>                Id = 1,<br>                Title = &quot;Örnek Belge 1&quot;,<br>                Content = &quot;Elasticsearch medium makalesi için örnek - sametuca&quot;<br>            };<br><br>            <br>            var indexResponse = client.IndexDocument(document);<br><br>            if (indexResponse.IsValid)<br>            {<br>                Console.WriteLine(&quot;Belge başarıyla indekslendi.&quot;);<br>            }<br>            else<br>            {<br>                Console.WriteLine(&quot;Belge indekslenirken hata oluştu: &quot; + indexResponse.DebugInformation);<br>            }<br><br>            <br>            var searchResponse = client.Search&lt;MyDocument&gt;(s =&gt; s<br>                .Index(&quot;sametuca-medium&quot;)<br>                .Query(q =&gt; q<br>                    .Match(m =&gt; m<br>                        .Field(f =&gt; f.Title)<br>                        .Query(&quot;Elasticsearch medium makalesi için örnek - sametuca&quot;)<br>                    )<br>                )<br>            );<br><br>            //bir hata olduğunda detaylı bilgi alabiliriz. <br>            //var res = searchResponse.DebugInformation;<br>            //Console.WriteLine(res);<br><br>            if (searchResponse.IsValid)<br>            {<br>                Console.WriteLine(&quot;Arama sonuçları:&quot;);<br>                foreach (var hit in searchResponse.Hits)<br>                {<br>                    Console.WriteLine(&quot;Id: &quot; + hit.Id);<br>                    Console.WriteLine(&quot;Content: &quot; + hit.Source.Content);<br>                    Console.WriteLine();<br>                }<br>            }<br>            else<br>            {<br>                Console.WriteLine(&quot;Arama yapılırken hata oluştu: &quot; + searchResponse.DebugInformation);<br>            }<br><br>            Console.ReadLine();<br>        }<br>    }<br>}</pre><p>Projenin kaynağına <a href="https://github.com/sametuca/elasticsearch-dotnet">buradan</a> ulaşabilirsiniz.</p><p><strong><em>Bu makale yazılırken yararlanılan kaynaklar</em></strong><br><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/elasticsearch-intro.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/elasticsearch-intro.html</a></p><ul><li><a href="https://www.toptal.com/dot-net/elasticsearch-dot-net-developers">An Elasticsearch Tutorial for .NET Developers | Toptal®</a></li><li><a href="https://www.instaclustr.com/support/documentation/elasticsearch/using-elasticsearch/connecting-to-elasticsearch-with-c-sharp/">Connecting to Elasticsearch with C#</a></li></ul><p><a href="https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch">https://codingexplained.com/coding/elasticsearch/understanding-the-inverted-index-in-elasticsearch</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d3116ac4572d" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>