3 Eylül 2023 Pazar

Factory Method Design Pattern Nedir ?

 

Factory method design pattern nedir ?

Merhabalar, bu yazımızda Factory Method Design Pattern ile ilgili bir örnek proje gerçekleştireceğiz. Bu tasarım kalıbıyla yapılmak istenen amaç, oluşturmak istediğimiz sınıfın kendisinden bir örnek istemek yerine Factory Method Pattern'i sayesinde tek bir instance üzerinden gerekli nesnenin üretilmesini sağlamaktır.

Uygulamamızda belirli adımlarda farklı tiplerde nesnelere ihtiyacımız olabilir. Bu nesneleri if - else veyahut switch yapıları aracılığıyla, duruma göre oluşturabiliriz. Tabi bunu her seferinde yapmanın zaman ve kod açısından çok tasarruflu olduğunu düşünülemez. İşte böyle durumlarda Factory Method Pattern'ini kullanabiliriz.

Bir başka deyişle, elinizin altındaki birden çok ilişkisel sınıftan nesne üreteceksek, söz gelimi her defasında ilgili nesneye özel üretme gramerini uygulamanıza gerek kalmayacak, tek bir sınıf üzerinden oluşturacağımız nesne talebiyle istediğiniz nesneyi elde edebileceğiz.

Şimdilik şöyle bir örnek üzerinden gidelim.Bir galeri düşünelim Bmw, Opel, Mercedes markalarını satıyor. Factory Method Pattern'i ile istediğimiz araba nesnesini üretelim.

Abstract Class İle Factory Method Design Pattern

Kurgulanan senaryoya göre tüm arabalarin türetilecek abstract class’ı dizayn edelim.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    /// <summary>
    /// Soyutlanacak base class abstract kelimesi ile belirtilir
    /// </summary>
   abstract class ArabaMarkasi
    {
        /// <summary>
        /// MarkaAdi methodu abstract kelimesi ile işaretlenerek ArabaMarkasi clasından kalıtılan
        /// classta bu method override edilmek zorunda. Oyuzden gövdesi burada doldurulmaz.
        /// </summary>
        public abstract void MarkaAdi();
    }
}

 

Şimdide arabalarımızı tasarlayalım ve oluşturmuş olduğumuz “ ArabaMarkasi ” abstract class’ından bu ürünleri türetelim.

Bmw:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    /// <summary>
    /// Bmw class'ını soyutlanmış ArabaMarkasi class'ından türetiyorum.
    /// Ve ArabaMarkasi class'ındaki abstract olarak tanımlanmış methodu override ederek methodun body'sini dolduruyorum
    /// </summary>
    class Bmw : ArabaMarkasi
    {
        /// <summary>
        /// ArabaMarkasi class'ından iplement'e edilen ve override edilen method
        /// </summary>
        public override void MarkaAdi()
        {
            Console.WriteLine("Bu araba abstarc'tan Oluşturuldu ve Bmw dir.");
        }
    }
}


Mercedes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    /// <summary>
    /// Mercedes clasını soyutlanmış ArabaMarkasi clasından türetiyorum.
    /// Ve ArabaMarkasi klasındaki abstract olarak tanımlanmış methodu override ederek, methodun body sini dolduruyorum
    /// </summary>
    class Mercedes : ArabaMarkasi
    {
        /// <summary>
        /// ArabaMarkasi clasından iplemente edilen ve override edilen method
        /// </summary>
        public override void MarkaAdi()
        {
            Console.WriteLine("Bu araba Abstarctan Oluşturuldu ve Markası Mercedes tir.");
        }
    }
}

 

Opel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    /// <summary>
    /// Opel platformunun clasını soyutlanmış ArabaMarkasi clasından türetiyorum.
    /// Ve ArabaMarkasi klasındaki abstract olarak tanımlanmış methodu override ederek, methodun body sini dolduruyorum
    /// </summary>
    class Opel : ArabaMarkasi
    {
        /// <summary>
        /// ArabaMarkasi clasından iplemente edilen ve override edilen method
        /// </summary>
        public override void MarkaAdi()
        {
            Console.WriteLine("Bu araba Abstarctan Oluşturuldu ve Markası Opel dir.");
        }

    }
}

 

Araba ürünlerimi Abstract class olan ArabaMarkasi sınıfından türeterek sınıflarımı oluşturdum. Artık bu sınıflardan nesne üretecek olan Creater sınıfını oluşturalım ve içerisine Factory işlemini yapacak metodumuzu tanımlayalım.

Ama öncelikle bu method hangi tipten nesne üreteceğini nerden bilecek? Bu durumu Enumaration ile halledebiliriz. Aşağıdaki Enumaration FactoryMethod’un hangi tipte nesne üreteceğine yardımcı olacaktır.

Araba Çeşitleri:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    enum Markalar
    {
        Bmw,
        Opel,
        Mercedes
    }
}

 

 Bu işlemden sonra FactoryMethod’u tam olarak inşa edebiliriz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Collections.Generic;
using System.Text;

namespace FactoryMethodDesign.AbstractClass
{
    /// <summary>
    /// Creator clasımız objelerin oluşturulmasından sorumlu obje
    /// </summary>
    class Creator
    {
        /// <summary>
        /// ArabaMarkasi tipinde obje oluşturan factory method 
        /// </summary>
        /// <param name="oyunTipi"></param>
        /// <returns></returns>
        public ArabaMarkasi FactoryMethod(Markalar arabaMarkasi)
        {
            ArabaMarkasi araba = null;
            switch (arabaMarkasi)
            {
                case Markalar.Bmw:
                    araba = new Bmw();
                    break;
                case Markalar.Opel:
                    araba = new Opel();
                    break;
                case Markalar.Mercedes:
                    araba = new Mercedes();
                    break;
                default:
                    break;
            }
            return araba;
        }
    }
}

 

Gördüğünüz gibi FactoryMethod parametresinde belirttiğimiz tipe göre istediğimiz nesneyi oluşturacak bir işleyişe sahip oldu. Burada dikkat etmeniz gereken husus, her bir araba ürününün “ArabaMarkasi” abstract class’ından kalıtım almasından dolayı çok biçimlilik kullanılarak “ArabaMarkasi” referansında tutulabilmekte ve geriye döndürülebilmektedir. Sıra geldi istediğimiz nesneyi üretmeye…

Ekran görüntüsü aşağıdaki gibi oluyor.

 

Tabi ilişkisel sınıflar ve algoritmada ki ihtiyaca göre üretilmesi gereken sınıflar üzerinde bu tasarım desenini uygulamak en doğrusudur.

Eğer Factory Method tasarım desenenini interface kullanarak uygulamak istiyorsanız, “ArabaMarkasi” isimli abstract sınıfını interface’e çevirmeniz yeterlidir. Tabi bu çevrim sırasında interface kurallarını dikkate almalı ve arabalari interfaceden türetirken yapılacak implementte override komutu olmadan uygulama gerçekleştirilmelidir. Bununla ilgili yazıda kod parçaaı koymayacağım ama github taki projede o kodlar mevcut.Umarım faydalı olmuştur iyi çalışmalar.

 Yararlandığım Kaynaklar

Kaynak Kodu 

https://www.gencayyildiz.com/blog/c-factory-method-design-patternfactory-method-tasarim-deseni/ 

http://www.canertosuner.com/post/factory-method-pattern-nedir-nasil-kullanilir 

Singleton Design Pattern Nedir ?

 

Singleton Design Pattern Nedir ?

Merhaba arkadaşlar bu yazımızda yazılımcılar tarafından en çok kullanılan tasarım kalıbı olan Singleton tasarım kalıbından bahsedeceğiz.Ama öncelikle çalışma mantığından bahsedelim.

Programlamada yaratılan her nesne ve değişken bellekte yer kaplar.Bazı nesneler vardır ki her istekte tekrar yaratılmasına ve bellekte yer kaplamasına gerek yoktur.Örneğin Db connection nesnesi veya Log nesnesi gibi. Her istek için ayrı ayrı bu nesneyi oluşturmak performans kaybına sebep olacaktır. Singleton ile oluşturulan nesneler tek bir örnek üzerinde kalır ve her istek bu örneği kullanır.

Signleton Design Pattern Kullanımı

Singleton design pattern deseninin 6 farklı şekilde kullanımı mevcut fakat ben en basit halini göstereceğim.Geri kalanlarına detaylı olarak buradan bakabilirsiniz.

En önemli kural burada Singleton ile ilgili sınıf dahilinde instance alınmasını önlemek, bu işlem için private ve protected access modifier ile classı tanımlayarak da yapılabilir fakat bizim isteklerimizden bir diğeri de yalnızca bir defa instance alınabilmesini sağlamak. O halde ilgili sınıfın içinde bir yerlerde nesnemizin oluşması gerekiyor. Bunu property veya statik bir metotla yapabiliriz.

Burada aslında en önemli noktalardan birinden bahsetmek istiyorum. Buradaki asıl amaç manuel olarak instance oluşturulmasını engellemek. Bu amaçla yola çıkarak Teksinif class’ımızın default constructor’unu private yapıyoruz ve ikinci bir instance oluşturulmasını engelliyoruz. Oluşturacağımız nesne sadece sınıf içerisinden oluşturulacağı için tek bir instance oluşturulmasını garantilemiş olacağız. Şimdi Teksinif class’ımızı görelim:

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
using System.Collections.Generic;
using System.Text;

namespace Singleton
{
    public class SingleClass
    {
        private SingleClass()
        {
            Random r = new Random();
            deger = r.Next();
        }
        private static SingleClass _instance;
        private static SingleClass instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new SingleClass();
                }
                return _instance;

            }
            set
            {
                _instance = value;
            }

        }
        public int deger;
        public static SingleClass getInstance()
        {
            return instance;
        }
    }
}


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using System;

namespace Singleton
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            SingleClass tek = SingleClass.getInstance();

            Console.WriteLine("\n Ilk Instance: {0}", tek.deger);

            SingleClass tek2 = SingleClass.getInstance();
            Console.WriteLine("\n Ikinci Instance: {0}", tek2.deger);
        }
    }
}

Göründüğü üzere yapıcı metodumuz private erişim belirleyicisi ile korunmakta. Burada altını çizmem gereken yapıcı metodumun içerisinde deger değişkenimi random bir sayı ile doldurmam yani Main metodumda iki adet getInstance yaptığımda tek bir nesne ile mi çalıştığımızı anlayabilmek için.

Main tarafında test etmek için getInstance metodunu kullandık ve degerlerini test ediyoruz. Çıktı aşağıdaki gibi olmalı yani sayılar eşit olmalı.

 

 

Umarım faydalı olmuştur.Bir sonarki yazımızda görüşmek üzere.

Yaralanılan Kaynaklar

Kaynak Kodu 

http://sehmusgokce.com/singleton-tasarim-deseni-design-pattern-nedir-ve-nasil-kullanilir-324.html 

http://www.ismailgursoy.com.tr/singleton-pattern-design-tek-nesneler/

 

Design Pattern Nedir?

 

Design Pattern Nedir? 
 
Yazılım dünyasında temel bir yazılım diline sahip bir yazılımcı küçük çaplı projeleri rahatlıkla yazabilir. Fakat projeler büyüdükçe işler farklılaşmaya başlar. Örneğin küçük bir blog sitesi, bir araba kiralama tanıtım sitesi gibi projelerden temel bir dil bilgisiyle başa çıkılabilir. Ancak bir devletin vatandaş portali gibi yada tüm dünyada satış yapan bir e-ticaret platformu gibi projeler büyükçe işler biraz daha da değişiyor. Kullanıcı sayısı artıkça performansın da önemi ortaya çıkmaya başlıyor.
 
Haliyle de teknoloji sürekli değişiyor ve yeni teknolojiler çıkıyor. Projenin bu değişikliğe en hızlı şekilde adapte olması gerekiyor. Bu adapte sürecinde kodların çok yalın ve karmaşık olmaması lazım. İşte bu noktada tasarım kalıplarının zorunluluğu ortaya çıkmış oluyor.
 

Peki Design Pattern Nedir?

Tasarım desenleri, deneyimli nesne yönelimli yazılım geliştiriciler tarafından kullanılan en iyi uygulamaları temsil eder. Tasarım kalıpları, yazılım geliştiricilerin yazılım geliştirme sırasında karşılaştıkları genel sorunların çözümleridir. Bu çözümler, oldukça uzun bir süre boyunca sayısız yazılım geliştiricisi tarafından deneme yanılma yoluyla elde edilmiştir.
 

Desing Pattern’lerin Kullanımı

Tasarım desenleri yazılım geliştirmede iki ana kullanım alanına sahiptir.Bunlar;

Geliştiriciler için ortak platform: Tasarım desenleri standart bir terminoloji sağlar ve belirli senaryolara özgüdür. Örneğin, bir singleton tasarım deseni, tek bir nesnenin kullanımını belirtir, böylece tek tasarım modeline aşina olan tüm geliştiriciler, tek nesneden yararlanır ve programın bir singleton modelini takip ettiğini söyleyebilirler.

Pratik Uygulamaları: Tasarım Desenleri uzun bir süredir gelişmiştir ve yazılım geliştirme sırasında karşılaşılan bazı sorunlara en iyi çözümleri sunmaktadır. Bu kalıpları öğrenmek, deneyimsiz geliştiricilerin yazılım tasarımını kolay ve hızlı bir şekilde öğrenmelerine yardımcı olur.

Design Pattern Türleri: 1994 yılında dört yazar Erich Gamma, Richard Helm, Ralph Johnson ve John Vlissides, Yazılım geliştirmede tasarım deseni kavramını başlatan tasarım desenleri — Yeniden Kullanılabilir Nesneye Yönelik Yazılım Öğeleri başlıklı bir kitap yayımladı. Buradan bakabilirsiniz.

Bu yazarlar toplu olarak Dörtlü “Gang of Four” olarak bilinir. Bu yazarlara göre tasarım desenleri öncelikle nesne yönelimli tasarım ilkelerine dayanmaktadır. Bu dörtlü kitaplarında 3 kategoride 23 farklı kalıba yer vermişlerdir.

Creational: Nesneleri yaratmakta kullanılan 5 adet tasarım kalıbı. Yazılım sistemindeki nesnelerin yaratılışı hakkında yol gösterirler. Bunlar;

  1. Factory Method
  2. Singleton
  3. Abstract Factory
  4. Builder 

Structural: Nesneler arasındaki yapıları ifade eden ilişkilerden 7 adet tasarım kalıbı. Yazılım sistemindeki nesnelerin birbirleriyle olan ilişkilerini gösteren kalıptır.

  1. Adapter
  2. Bridge
  3. Composite
  4. Decorator
  5. Facade
  6. Flyweight
  7. Proxy

Behavioral: Nesnelerin çalışma zamanına ait davranışlarını değiştirmek için oluşturulan tasarımlardan 11 adet tasarım kalıbı var. Nesne davranışlarını takip eden kalıptır.

  1. Iterator
  2. Observer
  3. Memento
  4. Mediator
  5. Chain of Responsibility
  6. Command
  7. Observer
  8. State
  9. Strategy
  10. Template Method
  11. Visitor

Tasarım kalıpları, yazılım mühendisliği alanında yaygın olarak kullanılan bir yaklaşım olup, birçok yazılım projesinin tasarım ve geliştirme süreçlerinde başarıyla uygulanmaktadır. Bu kalıplar, çözümlenmesi zor olan sorunlara karşı etkili bir şekilde çözümler sunmak için kullanılan standart çözüm yaklaşımlarını temsil eder. Tasarım kalıpları, yazılım geliştiricilerinin tekrarlanan problemleri yeniden keşfetmelerini önleyerek, kodun yeniden kullanılabilirliğini ve sürdürülebilirliğini arttırır. Buna ek olarak, tasarım kalıpları, yazılım uygulamalarının performansını, güvenilirliğini ve esnekliğini artırabilir. Bu nedenle, tasarım kalıplarının kullanımı, yazılım geliştirme süreçlerinde çok önemlidir ve yazılım mühendislerinin bilgi birikimlerinde yer almalıdır.

Yararlanılan kaynaklar

https://www.tutorialspoint.com/design_pattern/factory_pattern.htm

https://medium.com/nsistanbul/design-patterns-factory-method-pattern-615457e9560b 

 

2 Eylül 2023 Cumartesi

Asp.Net Core’da Web Socket Kullanımı

Asp.Net Core’da Web Socket Kullanımı

 

Merhaba, bugün ki yazımızda WebSocket’ten bahsedeceğiz. Ama öncelikle sunucu-istemci mimarisinde haberleşmeye bakmamız gerekir. Web uygulamarı(istemci) sunucuyla HTTP protokolü üzerinden istek/cevap mantığıyla haberleşir. İstemci sunucudan bir şey talep ettiğinde bir bağlantı açar ve bir istek gönderir. Sunucu isteği alır ve gerekli işlemleri yapar. Sunucu, istemciye cevabı döner. Bu trafik sürekli bu şekilde devam eder. İstemci her istek için bir bağlantı açmak zorundadır. Ve eğer sunucuda istemciye verebileceği yeni bir bilgi varsa, bunu istemciye doğrudan gönderemez, yerine istemciden talep gelmesini beklemelidir.

Bu fazlalık tüm bir bant genişliğini doldurabilmektedir. Daha kötüsü bu durum istemcinin ikinci bir bilgi ile dolmasını neredeyse engelleyebilir. Bu da anlık hıza ihtiyaç duyulan online finansal işlemlerde büyük kayıplara neden olabilmektedir.

Web geliştiricileri uzun yıllardır HTTP’nin bu kısıtlamasını aşmak ve herhangi bir bağlantı esnasında daha çok veri transferini sağlayabilmek için sistemler geliştiriyorlardı. Fakat asıl yapmak istedikleri sunucu ile istemci arasındaki bağlantıyı hiç koparmadan her iki tarafında birbirlerine karşılıklı veri alıp-göndermesine olanak sağlamaktı.

İşte tam bu ihtiyaca şifa gibi gelecek olan çözüm standartları neredeyse oturmak üzere olan HTML5’ten geldi. HTML5 ile gelen bu yeni protokol WebSocket’di. WebSocket, internetin karmaşık haberleşme işlemlerini gerçek-zamanlı olarak gerçekleştirebilmesini sağlayan bir sistemdir. WebSocket, istemciye bir bağlantı kurup bu bağlantıyı istediği kadar sürdürebilmesini ve veriyi iki taraflı olarak hem almasını hem de göndermesini sağlıyor.

 

Asp.Net Core’da WebSocket Örneği

Web Socketi kullanmak için basit bir script bilgisi ve .Net Core da orta düzey bir bilgi yeterlidir. Mantığı basit zaten.

İşe öncelikle WebsocketKullanimi adında bir tane core web application projesi açıyoruz. Daha sonra projeye Nuget üzerinden AspNetCore.WebSockets paketini ekliyoruz.

Install-Package Microsoft.AspNetCore.WebSockets -Version 2.2.1

İlk olarak uygulamamızın Startup.cs sınıfında Configure methodunda gerekli ayarları yapacağız. Çalışma zamanında WebSocket kullanacağızı bildiriyoruz. İstemci ile sunucu arasındaki iletişimi açıp gelen isteklerin mesajları kontrol edeceğiz. Amacımız gelen mesajı yakalayıp ve ona bir şeyler söylemek.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseWebSockets();

        app.Use(async (ctx, nextMsg) =>
        {
            Console.WriteLine("Web Socket is Listening");
            if (ctx.Request.Path=="/nokya")
            {
                if (ctx.WebSockets.IsWebSocketRequest)
                {
                    var wSocket = await ctx.WebSockets.AcceptWebSocketAsync();
                    await Talk(ctx, wSocket);
                }
                else
                {
                    ctx.Response.StatusCode = 400;
                }

            }else
            {
                await nextMsg();
            }
               
        });
        app.UseFileServer();
    }
    private async Task Talk(HttpContext hContext,WebSocket wSocket)
    {
        var bag = new byte[1024];
        WebSocketReceiveResult result = await wSocket.ReceiveAsync(new ArraySegment<byte>(bag),CancellationToken.None);

        while (!result.CloseStatus.HasValue)
        {
            var inComingMesage = Encoding.UTF8.GetString(bag, 0, result.Count);
            Console.WriteLine("\nClients says that: '{0}'", inComingMesage);
            var rnd = new Random();
            var number = rnd.Next(1, 100);
            string message = string.Format("You luck Number is '{0}'. Dont't remember that", number.ToString());
            byte[] outGoingMeesage = Encoding.UTF8.GetBytes(message);
            await wSocket.SendAsync(new ArraySegment<byte>(outGoingMeesage, 0, outGoingMeesage.Length),result.MessageType,result.EndOfMessage,CancellationToken.None);

            result = await wSocket.ReceiveAsync(new ArraySegment<byte>(bag), CancellationToken.None);

        }
        await wSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);           

    }
}

 

Kodların içinde ilk önce Configure methoduna bakıyoruz. Web Socket kullanacağımızı UseWebSockets() fonksiyonu ile ortama bildiriyoruz. Uygulama ayağa kalktığında gelen istekleri dinlemeye başlıyoruz. Gelen bu talep bir Web Socket isteğiyse(ki bunun ws:// protokolü ile başlayan bir talep olması gerekiyor) bir socket nesnesi yakalıyor ve Talk isimli fonksiyonu çağırıyoruz(yine asenkron olarak tabi) Eğer gelen istek /nokya adresine yapılmamışsa bir sonraki mesajı bekleyecek şekilde dinleme işlemine devam ediliyor.

Talk operasyonu içerisinde istemciden gelen mesajın terminale basılması ve rastgele üretilen bir sayı değerinin geri gönderilmesi için gerekli kodlar yer alıyor. İstemcinin gönderdiği mesajın yakalanması için ReceiveAsync isimli metodtan yararlanılmakta. Metodun ilk parametresi gelen içeriği bir Byte dizisine alıyor. Eğer aradaki iletişim açıksa(CloseStatus.HasValue ile bu kontrol edilmekte) bu byte içeriğini string’e dönüştürmek yeterli. Bağlı olan istemciye soket üzerinden mesaj göndermek içinse SendAsync metodundan yararlanılmakta. Trafik byte array’ler ile çalışıyor bu nedenle string operasyonları için UTF8 tabanlı Encoding mekanizmalarından yararlanılmakta.

Program.cs’de kullanacağımız portu ayarlıyoruz. http://localhost:5556 adresinden yayın yapacağız ve istemcilerimiz ws://localhost:5556/nokya adresini kullanarak websocket temelli iletişimi kurabileceklerdir.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
namespace WebSocketKullanimi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // CreateWebHostBuilder(args).Build().Run();
            BuildWebHost(args).Run();
        }

        //public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        //    WebHost.CreateDefaultBuilder(args)
        //        .UseStartup<Startup>();

        public static IWebHost BuildWebHost(string[] args) =>
          WebHost.CreateDefaultBuilder(args)
              .UseUrls("http://localhost:5556/")
              .UseStartup<Startup>()
              .Build();
    }
}

 

Örnek projede istemci olarak index.html sayfasında javascript kullanılarak socketle haberleşeceğiz. wwwroot klasöründe koyduğumuz sayfanın içeriği aşağıdaki gibidir.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<html>
<head>
    <title>Asp.Net Core ile Web Sockets Kullanımı</title>
</head>
<body>
    <button id="btnConnect" type="submit">Connect</button><br />
    Message : <input id="lblMessage" style="width:300;" /><br />
    <button id="btnSendMessage" type="submit">Send Message</button><br />
    <button id="btnDisconnect" type="submit">Disconnect</button><br />
    <script>
    var btnConnect = document.getElementById("btnConnect");
    var btnSendMessage=document.getElementById("btnSendMessage");
    var lblMessage=document.getElementById("lblMessage");
    var btnDisconnect=document.getElementById("btnDisconnect");
    var socket;

    btnConnect.onclick = function() {
            socket = new WebSocket("ws://localhost:5556/nokya");
            socket.onopen = function (e) {
                console.log("Connected",e);
            };
            socket.onclose = function (e) {
                console.log("Disconnected",e);
            };
            socket.onerror = function(e){
                console.error(e.data);
            };
            socket.onmessage = function (e) {
                console.log(e.data);
            };
        }

    btnSendMessage.onclick = function () {
            if (!socket || socket.readyState != WebSocket.OPEN) {
                console.error("Houston we have a problem! Socket not connected.");
            }
            var data = lblMessage.value;
            socket.send(data);
            console.log(data);
        }

    btnDisconnect.onclick = function () {
            if (!socket || socket.readyState != WebSocket.OPEN) {
                console.error("Houston we have a problem! Socket not connected.");
            }
            socket.close(1000, "Closing from Apollo 13");
        }

    </script>
</body>
</html>

 

Kodlarımızda btnConnect butonuna basıldığında çalışıyor. Dikkat edileceği üzere bir WebSocket nesnesi üretilmekte. Adres olarak da ws://localhost:5556/nokya adresi kullanılıyor. Adresin ws ile başladığına dikkat edelim. Oluşturulan WebSocket nesnesi için bazı olaylar tanımlanıyor. Bağlantı açıldığında, kapatıldığında, sunucudan mesaj alındığında veya bir hata oluştuğunda. Sunucuya mesaj göndermek için WebSocket nesnesinin send fonksiyonundan yararlanılmakta.

Projeyi debug edip sonuçları kendiniz görebilirsiniz. Umarım faydalı olmuştur.

 

Yararlanılan kaynaklar

Kaynak Kodu 

https://buraksenyurt.com/post/asp-net-core-da-bir-websocket-macerasi

 

Asp Net Core'da Moq Kütüphanesi ile Unit Test Yazımı

 

Asp Net Core'da Moq Kütüphanesi ile Unit Test Yazımı

Daha önceki yazımızda Birim Test Nedir konusuna değinmiştik ve birim test için kullanılabilecek frameworkleri vermiştik. Bu yazımızda Db operasyonları olan bir projede unit test yazmak istersek ne yapardık bu soruya cevap arıyor olacağız.

Bir UserRepository sınıfımız olsun ve bu repository için unit test metotları yazıyor olalım. Peki ama test metotlarını yazarken nasıl bir yol izleyeceğiz ? Her bir test case’i için gidip veritabanına dummy kayıtlar atıp CRUD işlemleri yapmamamız gerekir. Bu gibi durumlar için mocking dediğimiz “alaycı” veya “sahte” kayıtlar oluşturmamızı sağlayan library’ler bulunmakta. Bu library’lerden Moq’u kullanarak sahte nesneler üreterek UserRepository için basit bir test projesi yazacağız. Peki bu Moq nedir?

 

Moq Nedir ?

Mock kavramı istediğimiz bir nesnenin yerine geçebilen fake nesnelerdir. Bu objelerin istediğimiz gibi davranmalarını sağlayabiliriz. Moq’ta bu tarz işlemleri handle eden ve mock objelerini bize hazır sunan bir kütüphane.

 

Örnek Proje

Örnek projemiz için öncelikle bir tane UnitTestWithMoq adımda Console Application oluşturalım ve içerisine IUserRepository.cs arayüzünü ve User.cs sınıfını aşağıdaki gibi tanımlayalım. 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace UnitTestWithMoq
{
    public interface IUserRepository
    {
        IList<User> GetAll();
        User GetById(int userId);
        void Insert(User user);
        void Update(User user);
        void Delete(int Id);
    }
}

 

1
2
3
4
5
6
7
8
9
namespace UnitTestWithMoq
{
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

 

Şimdi ise UnitTestWithMoq.Test adında test projemizi oluşturalım ve UnitTestWithMoq projemizi referans olarak test projemize ekleyelim. Sonrasında test projemize Nuget üzerinden Moq kütüphanesini kuralım.

Tools > Nuget Package Manager > Package Manager Console > PM> Install-Package Moq

Kurulum işlemi tamamlandıktan sonra UserRepositoryTest adında bir class oluşturalım.

İlk olarak UserRepository için gerekli olan setup işlemlerini yapalım. Setup işlemi kısaca repository’nin içerisindeki metotların sahte objelerle işlemleri yapmasını sağlayacak kodları yazmak diyebiliriz. Mocking setup ile ilgili kodlarımız aşağıdaki gibi olacaktır.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
namespace UserRepositoryTest
{
    [TestClass]
    public class UserRepositoryTest
    {
        public readonly IUserRepository MockUserRepository;
        public UserRepositoryTest()
        {
            // Test metotları genelinde kullanacağımız User listesi
            var userList = new List<User>
            {
                new User {Id=1,FirstName="User1",LastName="User1LastName" },
                new User {Id=2,FirstName="User2",LastName="User2LastName" },
                new User {Id=3,FirstName="User3",LastName="User3LastName" }
            };
            // Mock the Products Repository using Moq
            var mockUserRepository = new Mock<IUserRepository>();
            // GetAll metodu için setup işlemi
            mockUserRepository.Setup(mr => mr.GetAll()).Returns(userList);
            // GetById metodu için setup işlemi
            mockUserRepository.Setup(mr => mr.GetById(It.IsAny<int>())).Returns((int i) => userList.Single(x => x.Id == i));
            // Insert için setup işlemi
            mockUserRepository.Setup(mr => mr.Insert(It.IsAny<User>())).Callback(
                (User target) =>
                {
                    userList.Add(target);
                });
            // Update için setup işlemi
            mockUserRepository.Setup(mr => mr.Update(It.IsAny<User>())).Callback(
                (User target) =>
                {
                    var original = userList.Where(q => q.Id == target.Id).Single();
                    if (original == null)
                    {
                        throw new InvalidOperationException();
                    }
                    original.FirstName = target.FirstName;
                    original.LastName = target.LastName;
                });
            // Test metotlarından erişilebilmesi için global olarak tanımladığımız MockUserRepository'e yukarıdaki setup işlemlerini atıyoruz
            this.MockUserRepository = mockUserRepository.Object;
        }
    }
}

 

Peki biz bu kodlarda ne yapıyoruz.

IUserRepository diye CRUD işlemlerinin yapıldığı bir class’ın ve bu class içerisinde bulunan GetAll, GetById, Insert, Update, Delete metotları için tanımlanan mocking veya kandırmaca işlemleri yukarıdaki gibidir. Database üzerinden bu işlemleri yapmak yerine rahatça userList array’i üzerinden bu işlemleri yapabilir.

 

GetAll metodunu çağırarak bize veri döndüğünü gösteren test metodu.

1
2
3
4
5
6
7
 [TestMethod]
 public void GetAll_Than_Check_Count_Test()
 {
    var expected = this.MockUserRepository.GetAll().Count;
    Assert.IsNotNull(expected); // test not null
    Assert.IsTrue(expected > 0);// test GetAll returns user objects
}

 

GetById metodu için doğru objeyi return edip etmediği durumu için test metodu.

1
2
3
4
5
6
7
8
9
[TestMethod]
public void GetById_Than_Check_Correct_Object_Test()
{
     var actual = new User { Id = 2, FirstName = "User2", LastName = "User2LastName" };
     var expected = this.MockUserRepository.GetById(2);
     Assert.IsNotNull(expected); // Test is not null
     Assert.IsInstanceOfType(expected, typeof(User)); // Test type
     Assert.AreEqual(actual.Id, expected.Id); // test correct object found
}

  

Insert işleminden sonra GetAll metodundan dönen object sayısı doğrumu testi

1
2
3
4
5
6
7
8
9
[TestMethod]
public void Insert_User_Than_Check_GetAll_Count_Test()
{
    var actual = this.MockUserRepository.GetAll().Count + 1;
    var user = new User { Id = 4, FirstName = "User4", LastName = "User4LastName" };
    this.MockUserRepository.Insert(user);
    var expected = this.MockUserRepository.GetAll().Count;
    Assert.AreEqual(actual, expected);
}

 

 GetById metoduna hatalı bir Id ile çağrım yapıldığında Exception döneceği durumu için test metodu.

1
2
3
4
5
6
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]//Eğer beklediğimiz bir exception var ise bu şekilde tanımlayabiliriz
public void GetyId_With_Undefined_Id_Than_Exception_Occurred_Test()
{
    var expected = this.MockUserRepository.GetById(It.IsAny<int>());
}

  

Update işlemi sonrasında GetById yapılarak dönen nesnede bulunan değerler doğrumu test metodu.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[TestMethod]
public void Update_User_Than_Check_It_Is_Updated_Test()
{
    var actual = new User { Id = 2, FirstName = "User2_Updated", LastName = "User2LastName_Updated" };
    this.MockUserRepository.Update(actual);
    var expected = this.MockUserRepository.GetById(actual.Id);
    Assert.IsNotNull(expected);
    Assert.AreEqual(actual.FirstName, expected.FirstName);
    Assert.AreEqual(actual.LastName, expected.LastName);
}

 

Test metotlarını yazdıktan sonra Run All Tests diyerek testlerimizi çalıştırıp success-fail durumlarını görebiliriz.

Bu yazımızda Moq kullanarak basitçe bir Unit Test projesi hazırladık. Artık yazılım dünyasında unit test olmazsa olmazdır. Umarım faydalı olmuştur.

Yararlanılan kaynaklar

Kaynak Kodu 

http://www.canertosuner.com/post/moq-kullanarak-unittest-yazma

Unit Test Nedir ? Asp.Net ve Asp.Net Core’da Unit Test

 

Unit Test Nedir ? Asp.Net ve Asp.Net Core’da Unit Test

 

Unit Test Nedir ?

Tabiki de hatasız kod olmaz. Her zaman sizden sonra gelen geliştirici, kodta ekstra hatalar bulabilir. Yada ekstra özellikler ekleyebilir. Bu yüzden birim testi yazılan bir kodun anlaşılması daha kolaydır. Sizden sonra gelen geliştiricide kodu daha hızlı bir şekilde anlayabilir.

 

DevOps Açısından Unit Test

Unit Test artık yazılım dünyasında olmazsa olmaz bir kural olarak bütün projelerde yazılması zorunlu hale gelmektedir. DevOps açısından düşündüğümüzde Continuous Integration ve Continuous Deployment araçları yazmış olduğumuz kodları derleyip edip yüklemeden önce ilk olarak birim test metotlarını çalıştırır. Bu metotlardan herhangi biri hat aldığında yüklemeyi durdurabilir. Böylelikle birim test yazmak artık yazılım geliştirme dünyasında olsa da olur olmaktan çıkıp olmalıdır haline gelmektedir.

 

Asp.Net ve Asp.Net Core’da Unit test

ASP.NET’de birim test yazmak için genellikle NUnit veya Microsoft tarafından sağlanan Visual Studio Test Runner kullanılır. Bunlar, bir sınıfın veya birim işlevinin bir parçası olarak çalışan kodların test edilmesine olanak tanır. Bunlar, kodun daha önce yazılmış testlerle uyumlu olup olmadığını ve beklenen sonuçları üretip üretmediğini doğrulamak için kullanılabilir.

ASP.NET Core’da birim test yazmak için, .NET Core 2.1 veya üstü bir sürümü ve genellikle xUnit, NUnit veya MSTest frameworklerini kullanabilirsiniz. Bu frameworkler, birim testlerinin oluşturulması, yürütülmesi ve sonuçlarının değerlendirilmesi için araçlar sağlar. ASP.NET Core, birim testlerinin yazılması ve yürütülmesi için birçok özellik ve fayda sağlar. Bu, kodun test edilmesini ve hataların tespit edilmesini kolaylaştırır.

ASP.NET ve ASP.NET Core’da birim test kullanarak, yazılımın doğru çalıştığından ve beklenen sonuçları ürettiğinden emin olabilirsiniz. Bu, yazılım geliştirme sürecinde önemli bir adımdır ve kodun güvenilirliğini arttırır. Ayrıca, birim test kullanımı, kodun daha kolay bakımının yapılmasını sağlar ve geliştirme sürecinin daha hızlı ve verimli olmasına yardımcı olur.

 

Bazı Unit Test Framework'leri

  1. NUnit: NUnit, özellikle .NET uygulamaları için tasarlanmış açık kaynaklı bir birim test kütüphanesidir. Asp.Net ve Asp.Net Core uygulamalarında da sıkça kullanılmaktadır.
  2. xUnit: xUnit, açık kaynaklı bir birim test kütüphanesidir ve .NET Core ile uyumludur. Asp.Net Core uygulamaları için özellikle uygun bir birim test kütüphanesidir.

Bu kütüphanelerden birini kullanarak kendinize uygun test metodları oluşturabilirsiniz. Bir sonraki yazımızda Moq kütüphane kullanarak Unittest projesi oluşturacağız. Umarım faydalı olmuştur.

Yararlanılan kaynaklar

http://www.canertosuner.com/post/asp-net-core-unit-test 

https://medium.com/@resulzel/unit-test-nedir-ff353aac240a 

 

 

Asp.Net Core’da Hangfire Kullanımı

 

Asp.Net Core’da Hangfire Kullanımı

Hangfire, Asp.Net Core uygulamalarında zamanlanmış görevleri yönetmek için kullanılan bir araçtır. Hangfire, uygulamanın arkasında çalışan bir job süreci oluşturarak, zamanlanmış görevleri güvenilir bir şekilde yürütür.

Hangfire’ı kullanmak için, öncelikle uygulamanıza Hangfire paketini yüklemeniz gerekmektedir. Bunun için, NuGet Paket Yöneticisi’ni kullanabilirsiniz. Ayrıca, Hangfire’ı kullanmak için bir veritabanı seçmeniz gerekmektedir. Hangfire, desteklediği birçok veritabanı sunucuları arasında SQL Server, PostgreSQL, MySQL, Oracle, Redis ve MongoDB’yi sayabiliriz.

Program sunucuda çalışırken arka planda belli kurallara göre ve belli zamanlarda yapılmasını istediğimiz işler için inanılmaz bir çözüm. Web arayüzü ile baya kullanışlı bir yardımcı kütüphanedir. Sahip olduğu dashboard ile job’larınızı tarihsel olarak görüntüleyebilir, start-stop/restart gibi işlemler yapabiliriz.

Öncelikle local Db’de HangFire adında bir database oluşturalım. Database’in user login bilgilerini ayarlıyoruz.

 

 

Şimdide TaskWithHangFire adında bir web api projesi açıyoruz. Nuget üzerinden bugün için en güncel olan Hangfire paketini projemize ekliyoruz.

 

 

Oluşturduğumuz database’in connection string’ini application.json dosyasına ekliyoruz. 


1
2
"HangfireDbConn": "Server=DESKTOP-FRC4TQU\SQLEXPRESS;Initial Catalog=HangFire;Persist Security Info=False;User ID=HangFireUser;
 Password=123456;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;"

 

Hangfire’ı uygulamaya tanıtmamız gerekiyor. Bu kısımda Startup.cs de bulunan ConfigureServices metodu içerisinde Hangfire’ı service olarak ekleyelim ve sonrasında Configure metodu içerisinde bu servisi kullanacağımızı belirten kod bloklarını yazıyoruz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddHangfire(_ => _.UseSqlServerStorage(Configuration.GetValue<string>("HangfireDbConn")));
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
           // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHangfireDashboard();
        app.UseHangfireServer(); 
        app.UseHttpsRedirection();
        app.UseMvc();
}

 

Yukarıdaki kod bloğunda hangfire database bilgisini vererek uygulamamız servislerine register ettik. Devamında da hangfire’ın server ve dashboard servislerini kullanacağımızı belirttik.

Hangfire dashboard default olarak uygulamanın çalıştığı portta’ http://hangfire adresinde host edilir. Bizde localhost’ta çalıştığımızdan uygulamayı run edip browser üzerinden http://localhost/hangfire adresine gittiğimizde aşağıdaki gibi hangfire dashboard’u görüntüleyebiliriz.

 

 

Uygulama start edildiğinde database’de gerekli tablolar oluşturulmuş mu ? kontrol ediyoruz.

 

 

 

Hangfire konfigurasyonunu tamamladık şimdi sırasıyla Hangfire kütüphanesinde bulunan BackgroundJob sınıfını kullanarak oluşturabileceğimiz job türlerine bakacak olursak;

 

1- Fire-and-Forget Jobs

Job create edildikten sonra çalışır ve process olur. Bir daha da çalışmaz. Tek kullanımlık bir job’tır.  


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
namespace TaskWithHangFire.Jobs
{
    public class FireAndForgetJob
    {
        public FireAndForgetJob()
        {
            // Fire and forget
            var jobId = BackgroundJob.Enqueue(()=>ProcessFireAndForgetJob());            
        }
        public void ProcessFireAndForgetJob()
        {
            //to do jobs
            throw new NotImplementedException();
        }
    }
}

 

2- Delayed Jobs

Belli bir zaman bilgisi set edilerek sadece bir kez çalışmasını istediğimiz task’lar için kullanabileceğimiz job türü. Aşağıdaki gibi Job register olduktan 4 dakika sonra çalışacaktır.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace TaskWithHangFire.Jobs
{
    public class DelayedJob
    {
        public DelayedJob()
        {
            // Delayed Jobs
            var jobId = BackgroundJob.Schedule(()=>ProcessDelayedJob(),TimeSpan.FromMinutes(4));
        }
        public void ProcessDelayedJob()
        {
            Console.WriteLine("");
        }
    }
}

 

3- Recurring Jobs

Recurring yani tekrar eden task’lar için kullanılan job türü. Örneğin; her saat başı çalışmasını istediğiniz bir job’a ihtiyacınız olduğunda aşağıdaki gibi tanımlayabiliriz.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace TaskWithHangFire.Jobs
{
    public class Recurring_Job
    {
        public Recurring_Job()
        {
            //Recurring job
            RecurringJob.AddOrUpdate(() => ProcessRecurringJob(), Cron.Hourly);
        }
        public void ProcessRecurringJob()
        {
            Console.WriteLine("I am a Recurring Job !!");
        }
    }
}

 

4- Continuations Jobs

Parent-child ilişkisinin olduğu yani bir job’ın çalışması için başka bir job’ın tamamlanmasını bekleyip bittikten sonra çalışmasını istediğimiz işler için kullanabileceğimiz job türü.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace TaskWithHangFire.Jobs
{
    public class ContinuationsJob
    {
        [Obsolete]
        public ContinuationsJob()
        {
            //Delayed job
            var parentJobId = BackgroundJob.Schedule(() => Console.WriteLine("I am a Delayed Job !!"), TimeSpan.FromMinutes(4));
            //Continuations job
            BackgroundJob.ContinueWith(parentJobId,() => ProcessContinuationsJob());
        }
        public void ProcessContinuationsJob()
        {
            Console.WriteLine("I am a Recurring Job !!");
        }
    }
}

 

Uygulamanızda çalıştırmanız gereken arka plan işleri için Hangfire implementasyonunu hızlı bir şekilde yapıp dashboard’u ile birlikte kolayca kullanabilirsiniz. Hangfire’ın muadili olan Quartz.net veya bir queue çözümü de kullanarak işlemlerinizi yapabilirsiniz. Umarım faydalı olmuştur.

 

Yararlanılan kaynaklar

Kaynak Kodu

http://www.canertosuner.com/post/asp-net-core-hangfire-ile-birlikte-background-task-islemleri 

 

.Net Core'da Swagger UI Kullanımı

  Web API geliştirirken API de yazılan metodların ne iş yaptığı? Hangi parametreleri aldığı? Ne cevap döndüğü? Gibi bilgilerin yer aldığı ...