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 

 

31 Ağustos 2023 Perşembe

Asp .Net Core’da In-Memory Cache Kullanımı

 

Asp .Net Core’da In-Memory Cache Kullanımı
 

Bu yazımızda Asp.Net Core’un default built-in yapısında In-Memory Cache özelliğinden bahsedeceğiz. Asp.Net Core, uygulama performansını artırmak için çeşitli önbellekleme mekanizmaları sağlar. Bunlardan biri de In-Memory Cache kullanımıdır. In-Memory Cache, uygulamanın hafızasında tutulan önbellek verileridir.

In-Memory Cache Özelliğini Aktif Etmek

In-Memory Cache kullanmak için, öncelikle uygulamanızda Microsoft.Extensions.Caching.Memory paketinin yüklü olduğundan emin olunuz. Daha sonra, ConfigureServices() metodunda IMemoryCache arayüzüne ait bir instance oluşturmanız gerekmektedir. In-memory cache özelliği Asp.Net Core içerisinde bir service olarak bulunmaktadır. Bu servis default kapalı gelir yapmamız gereken Startup.cs içerisinde bulunan ConfigureServices metodunda aşağıdaki gibi cache servisini açmak. 

 

1
2
3
4
5
 public void ConfigureServices(IServiceCollection services)
 {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddMemoryCache();
 }

 

Bu kod parçası, ConfigureServices() metodunda services koleksiyonuna IMemoryCache instance’ı ekler.

IMemoryCache interface, Asp.Net Core projelerinde in-memory cache kullanmamızı sağlayan bir arayüzdür. Bu arayüze ait metotları kullanarak cache set, get, remove gibi işlemleri yapabiliriz. 


1
2
3
4
5
6
 public interface IMemoryCache : IDisposable
 {
         bool TryGetValue(object key, out object value);
         ICacheEntry CreateEntry(object key);
         void Remove(object key);
 }

 

In-Memory Cache Kullanımı

In-Memory Cache servisi aktifleştirdikten sonra IMemoryCache arayüzünü kullanmak istediğimiz katmana ait constructor’da inject ediyoruz. Bizde geriye Student listesi return ettiğimiz bir controller tanımlayarak IMemoryCache arayüzünü aşağıdaki gibi constructor injection parameter olarak verelim.

StudentController içerisindeki Get metodunda sırasıyla işlemlerimizi uygulayalım. _memoryCathe.Set(key, value, cacheOptions) metodu 3 tane parametre alıyor. cacheOptions parametresi de 2 tane değer alıyor. 

Bunlar;

AbsoluteExpiration: Cache expire süresi

Priority: Memory şiştiğinde cache objelerini hangi öncelikte silinecek.

 

 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
 using InMemoryCatchKullanimi.Domain;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Caching.Memory;
 using System;
 using System.Collections.Generic;
 namespace InMemoryCatchKullanimi.Controllers
 {
     [Route("api/[controller]")]
     [ApiController]
     public class StudentController : ControllerBase
     {
         private readonly IMemoryCache _memoryCache;
         public StudentController(IMemoryCache memoryCache)
         {
             this._memoryCache = memoryCache;
         }
         [HttpGet]
         public IEnumerable Get()
         {
             const string cacheKey = "studentListKey";
             if (!_memoryCache.TryGetValue(cacheKey, out List response))
             {
                 response = new List { new Student { Id = Guid.NewGuid(), Name = "ismail kaşan" }, new Student { Id = Guid.NewGuid(), Name = "serkan ulukoca" } };
                 var cacheExpirationOptions = new MemoryCacheEntryOptions
                 {
                     AbsoluteExpiration = DateTime.Now.AddMinutes(5),
                     Priority = CacheItemPriority.Normal
                 };
                 _memoryCache.Set(cacheKey, response, cacheExpirationOptions);
             }
             return response;
         }
     }
 }

 

Gelen ilk request için cache’de o key’e ait bir nesne olmadığından ilk request source’a gidip(bir repository yada service layer olabilir) bir veri alınır. Sonra bu veriye 5 dakikalık bir expire süresi set edilerek cache’e atılır. Artık ondan sonraki bütün request’ler 5 dakika boyunca source’a gitmeden response’u cache’den eturn edecektir. Expire süresi dolduğunda ise ilgili key ve obje cache’den silinecektir.

Set, Get yapabildiğimiz gibi Remove işlemide yapabiliriz. Bunun için cacheKey değerini parametre olarak Remove metoduna verip call yapmak yeterli.

 

1
_memoryCache.Remove(cacheKey);

 

CacheItemPriority enum’ı içerisinde Low, Normal, High, NeverRemove değerleri vardır. CachedObject Priority değerine göre memory de yer açmak için sırayla silinir. Memory’den otomatik silme işlemi yapıldığında bunun bilgisini bize iletmesini sağlayan bir callback handler metodunu aşağıdaki gibi options’a register edebiliriz ve silme işlemi yapılırken bu metot tetiklenerek bize haber verir. 


1
2
3
4
5
6
 cacheExpirationOptions.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);

 private static void EvictionCallback(object key, object value,EvictionReason reason, object state)
 {
             var message = $"Entry was evicted. Reason: {reason}.";          
 }

 

Server-side bir uygulama için cache olmazsa özelliklerden biri haline gelmiştir. Asp.Net core’da da In-Memory Cache ve Distributed Cache işlemleri yapmamızı sağlayan servisler bulunmaktadır. Bu yazımızda basitçe In-Memory Cache özelliğini projemize nasıl entegre edeceğimize baktık. Umarım faydalı olmuştur.

Yararlanılan kaynaklar:

 Kaynak Kodu

http://www.canertosuner.com/post/asp-net-core-in-memory-cache 

 

 

C#'ta JSON Kullanımı

 

C#'ta JSON Kullanımı

JSON Nedir ?

JSON (JavaScript Object Notation) hafif bir veri değişim formatıdır.

  • İnsanların veriyi okuması ve yazması kolaydır.
  • Makinelerin ayrıştırması ve oluşturması kolaydır.
  • JavaScript Programlama Dili, ECMA-262 alt kümesini temel alır.
  • JSON, tamamen dilden bağımsız olarak veri taşıma formatıdır.
  • C ++, C #, Java, JavaScript, Perl, Python gibi bütün dillerde kullanılır.
  • Bu özellikler JSON’u ideal bir veri değişimi dili yapar.

Aşağıda örnek bir JSON veri yapısı bulunmaktadır.

1
2
3
4
5
"employees":[
    {"firstName":"John", "lastName":"Doe"}, 
    {"firstName":"Anna", "lastName":"Smith"}, 
    {"firstName":"Peter", "lastName":"Jones"}
] 

 C# ile JSON Kullanımı

C# programlama dilinde, JSON kullanımı oldukça yaygındır ve genellikle web servisleri ile iletişim kurmak için kullanılır. JSON, verileri kolayca okunabilir ve anlaşılabilir bir formatta temsil eder.

JSON verilerini C# programında kullanmak için, öncelikle Newtonsoft.Json paketinin projenize eklenmesi gerekmektedir. Asp.Net Core’da default olarak SDK nin içinde geliyor. Eğer projenizde yok ise Nuget üzerinden indirebilirsiniz. Bu paket, JSON verilerini C# nesnelerine dönüştürmek için kullanılır.

JSON verilerini C# nesnelerine dönüştürmek için, JsonConvert sınıfının DeserializeObject() metodunu kullanabilirsiniz. Bu metod, bir JSON veri dizisini C# nesnesine dönüştürür. Aşağıdaki örnek, bir JSON veri dizisini C# nesnesine dönüştürmektedir:

Öncelikle C# tarafındaki Member adlı sınıfı oluşturuyorum.

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

namespace DependencyInjection.Domain
{
    public class Member
    {      
        public string Name { get; set; }
        public string LastName { get; set; }
    }
}

C# ta kullanabilmek için öncelikle Newtonsoft.Json namespace’nin projenizde ekli olması gerekiyor. Şuan versiyon olarak 12.0.2 mevcut ama kendini sürekli geliştiren bir kütüphanedir. Newtonsoft hakkında detaylı bilgiye buradan erişebilirsiniz.

Örnekte Member tipinden oluşan listeyi JSON dizisine çevirelim.

 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
using System.Collections.Generic;
using System.Linq;
using DependencyInjection.Domain;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace DependencyInjection.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class OrnekJsonController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<string> Get()
        {
            List<Member> liste = new List<Member>
            {
                new Member { Name= "John", LastName= "Doe" },
                new Member { Name = "Anna", LastName = "Smith" },
                new Member { Name = "Peter", LastName = "Jones" }
            };
            string json = JsonConvert.SerializeObject(liste);
            return json;
        }      
    }
}

 Get methoduna istek attığımızda JSON dizisine verilerimizin değiştiğini göreceğiz.

C# ile JSON Verilerini Okumak

Öncelikle JSON formatındaki bir string veriyi Member tipinden oluşan bir listeye çevirelim. Kodlar 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
using System.Collections.Generic;
using System.Linq;
using DependencyInjection.Domain;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace DependencyInjection.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class OrnekJsonController : ControllerBase
    {
        // GET api/values
        [HttpGet("GetOlustur")]
        public ActionResult<IEnumerable<Member>> GetOlustur()
        {
            string json = @"[{""Name"":""John"",""LastName"":""Doe""},{""Name"":""Anna"",""LastName"":""Smith""},{""Name"":""Peter"",""LastName"":""Jones""}]"
            var liste = (List<Member>)JsonConvert.DeserializeObject(json, typeof(List<Member>));
            return liste.ToList();
        }
    }
}

 Örnek metoda istek attığımızda çıktımız aşağıdaki gibidir.


 Umarım faydalı olmuştur.

.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ığı ...