Blog SAkan

Blog SAkan'a Hoşgeldiniz

Aramak istediğiniz makaleyi bir kaç kelime ile giriniz
image

SignalR

25.04.2024 tarihinde yayınlandı 2 dakikalık okuma 0 yorum
İnternet üzerinde gerçek zamanlı iletişim giderek daha önemli hale gelmektedir. Web uygulamaları, kullanıcılar arasında hızlı ve etkileşimli iletişim sağlamak için teknolojik olarak gelişmektedir. Bu ihtiyaca cevap veren birçok çözüm bulunmaktadır ve SignalR, bu çözümlerden biridir. SignalR, Microsoft tarafından geliştirilen bir kütüphanedir ve gerçek zamanlı web uygulamaları oluşturmayı kolaylaştırır. İstemci ve sunucu arasında iki yönlü iletişimi destekler. Bu, sunucudaki değişikliklerin anında istemcilere iletilmesini ve istemcilerden sunucuya geri bildirim alınmasını sağlar. Özellikle sohbet uygulamaları, canlı puan tabloları, anlık bildirimler gibi gerçek zamanlı etkileşim gerektiren uygulamalarda yaygın olarak kullanılır. SignalR, WebSocket, Server-Sent Events (SSE), Long Polling gibi farklı iletişim mekanizmalarını kullanarak gerçek zamanlı iletişim sağlar. Bunların arasında en etkin olanı WebSocket'tir çünkü tam çift yönlü iletişim sağlar. Ancak, WebSocket'in desteklenmediği ortamlarda SignalR diğer yöntemlere de otomatik olarak uyum sağlar. Hub'lar (Hubs): SignalR, bir veya daha fazla hub sınıfı aracılığıyla iletişimi yönetir. Hub'lar, sunucuda gerçekleşen olayları dinler ve istemcilere bildirir. Aynı zamanda istemcilerden gelen talepleri alır ve bunları sunucu tarafında işler. Hub sınıfları, sunucu ve istemci arasındaki iletişimde aracı olarak görev yapar. İstemci ve Sunucu: SignalR, istemci ve sunucu arasında iletişimi kurar. İstemci tarafında JavaScript API'si kullanılarak sunucuyla bağlantı kurulur ve sunucudaki hub'larla etkileşim sağlanır. Sunucu tarafında ise .NET veya .NET Core ortamında hub sınıfları tanımlanır ve istemcilerle iletişim gerçekleştirilir. İletişim Protokolleri: SignalR, iletişimde WebSocket, Server-Sent Events, Long Polling gibi farklı protokolleri kullanabilir. Sunucu ve istemci arasında en etkin iletişim protokolü WebSocket'tir ancak bu protokolün desteklenmediği durumlarda diğer alternatif protokoller otomatik olarak devreye girer. Avantajları Gerçek Zamanlı İletişim: SignalR, sunucudaki değişikliklerin anında istemcilere iletilmesini sağlar, bu da gerçek zamanlı etkileşimli uygulamaların geliştirilmesini kolaylaştırır. Çoklu Platform Desteği: SignalR, .NET ve .NET Core platformlarında kullanılabilir. Ayrıca istemciler için JavaScript API'si sağlar, bu da çeşitli istemci platformlarında (web tarayıcıları, mobil uygulamalar vb.) kullanılabilmesini sağlar. Otomatik Protokol Seçimi: SignalR, desteklenen en etkin iletişim protokolünü otomatik olarak seçer. Bu sayede farklı platformlarda ve ortamlarda sorunsuz bir şekilde çalışabilir. Kolay Kullanım: SignalR, basit bir API'ye sahiptir ve gerçek zamanlı iletişim sağlamak için gerekli olan alt yapıyı sağlar. Bu da geliştiricilerin uygulama geliştirmeye odaklanmalarını kolaylaştırır. SignalR, gerçek zamanlı iletişim gerektiren web uygulamaları için güçlü bir çözümdür. Basit API yapısı ve otomatik protokol seçimi gibi özellikleriyle geliştiricilere kolaylık sağlar ve çeşitli platformlarda sorunsuz bir şekilde çalışabilir. Bu nedenle, gerçek zamanlı uygulamalar geliştiren geliştiriciler için önemli bir araçtır. İlgili kütüphaneleri ekledikten sonra basit bir örnek için aşağıdaki kodlar kullanılabilir. public interface IExampleTypeSafeHub { Task ReceiveMessageForAllClient(string message); } public class ExampleTypeSafeHub : Hub<IExampleTypeSafeHub> { public async Task BroadcastMessageToAllClient(string message) { await Clients.All.ReceiveMessageForAllClient(message); } } Program.cs'de; builder.Services.AddSignalR(); app.MapHub<ExampleTypeSafeHub>("/exampleTypeSafeHub"); Javascript tarafında; $(document).ready(function () { const connection = new signalR.HubConnectionBuilder().withUrl("/exampleTypeSafeHub").configureLogging(signalR.LogLevel.Information).build(); const broadcastMessageToAllClientHubMethodCall = "BroadcastMessageToAllClient"; const receiveMessageForAllClientClientMethodCall = "ReceiveMessageForAllClient"; async function start() { try { await connection.start().then(() => { console.log("Hub connected"); $("#div-connection-id").html(`Connection Id : ${connection.connectionId}`); }); } catch (e) { setTimeout(() => start(), 5000); } } connection.onclose(async () => { await start(); }) start(); $("#btn-send-message-all-client").click(function () { const message = "hello world"; connection.invoke(broadcastMessageToAllClientHubMethodCall, message).catch(err => console.error("error:", err)); }); connection.on(receiveMessageForAllClientClientMethodCall, (message) => { console.log("Received message:", message); }); }); Örnek projeyi github üzerinden inceleyebilirsiniz.
Daha fazla göster
image

RabbitMQ

23.04.2024 tarihinde yayınlandı 4 dakikalık okuma 0 yorum
RabbitMQ, başlangıçta Gelişmiş Mesaj Kuyruk Protokolü'nü (AMQP) uygulayan ve o zamandan beri Akış Metin Odaklı Mesajlaşma Protokolünü (STOMP) desteklemek için bir eklenti mimarisiyle genişletilen, açık kaynaklı bir mesaj aracı yazılımıdır Erlang'da yazılan RabbitMQ sunucusu, kümeleme ve yük devretme için Açık Telekom Platformu çerçevesi üzerine inşa edilmiştir. Aracıyla arayüz oluşturacak istemci kitaplıkları tüm önemli programlama dilleri için mevcuttur. Aşağıda basic şekilde kullanımı örneklendirilmiştir. public class BaseExchange { public static ConnectionFactory factory = new ConnectionFactory { HostName = "localhost", Port = 5672 }; } public enum LogNames { Critical = 1, Error = 2, Warning = 3, Info = 4 } Publisher; namespace RabbitMQ.Publisher { public class DirectExchange : BaseExchange { private const string exchangeName = "logs-direct"; public static void Publisher() { using (var connection = factory.CreateConnection()) { var channel = connection.CreateModel(); channel.ExchangeDeclare(exchangeName, durable: true, type: ExchangeType.Direct); Enum.GetNames(typeof(LogNames)).ToList().ForEach(x => { var routeKey = $"route-{x}"; var queueName = $"direct-queue-{x}"; channel.QueueDeclare(queueName, true, false, false); channel.QueueBind(queueName, exchangeName, routeKey); }); Enumerable.Range(1, 50).ToList().ForEach(x => { LogNames log = (LogNames)new Random().Next(1, 5); string message = $"Log Type: {log}"; var messageBody = Encoding.UTF8.GetBytes(message); var routeKey = $"route-{log}"; channel.BasicPublish(exchangeName, routeKey, null, messageBody); Console.WriteLine($"Message sended : {message}"); }); } } } } Subscriber (Consumer); namespace RabbitMQ.Subscriber { public class DirectExchange : BaseExchange { public static void Consumer() { using (var connection = factory.CreateConnection()) { var channel = connection.CreateModel(); channel.BasicQos(0, 1, false); var consumer = new EventingBasicConsumer(channel); var queueName = $"direct-queue-Critical"; // bu örnekte sadece critical kuyruğunu dinliyoruz channel.BasicConsume(queueName, false, consumer); Console.WriteLine($"Logs listening"); consumer.Received += (object sender, BasicDeliverEventArgs e) => { var message = Encoding.UTF8.GetString(e.Body.ToArray()); Thread.Sleep(500); Console.WriteLine($"Recieved Message : {message}"); channel.BasicAck(e.DeliveryTag, false); }; Console.ReadLine(); } } } } Örnekler için; Diğer basic yöntemleriyle kullanımı örnek proje için tıklayınız. Worker service ile excel oluşturma örneği için tıklayınız. Background service ile image watermark örneği için tıklayınız.
Daha fazla göster
image

Redis

03.04.2024 tarihinde yayınlandı 4 dakikalık okuma 0 yorum
Redis (Remote Dictionary Server), bir veri yapısı sunucusudur. Açık kaynak, bellek kullanımlı, anahtar-değer deposudur. Redis "Uzak Sözlük Sunucusu" anlamına gelmektedir. Çeşitli kaynaklara göre en çok kullanılan anahtar-değer veritabanıdır. Haziran 2015'ten beri Redis Labs şirketi tarafından geliştirilmesine destek sağlanmaktadır. Verileri geçici olarak ram’de tutma yöntemlerinden biridir. Uygulama bir servis aracılığı ile ram’e erişir. Bu da in-memory cache yöntemlerinden daha yavaş olmasına sebep olur. Ama dağıtık yapılarda veri tutarlılığı açısından tercih edilir. .Net Core tarafında aşağıdaki gibi kullanılabilir. public static class StackExchangeRedisExtension { public static void AddStackExchangeRedis(this IServiceCollection services, IConfiguration configuration) { string _redisHost = configuration["Redis:Host"]; string _redisPort = configuration["Redis:Port"]; var configString = $"{_redisHost}:{_redisPort}"; var redis = ConnectionMultiplexer.Connect(configString); services.AddSingleton(redis); } } public class StackExchangeRedisService { private readonly ConnectionMultiplexer _redis; public StackExchangeRedisService(ConnectionMultiplexer redis) { _redis = redis; } public IDatabase GetDb(int db) { return _redis.GetDatabase(db); } } Program.cs tarafına servisi ekledik. builder.Services.AddStackExchangeRedis(builder.Configuration); builder.Services.AddSingleton<StackExchangeRedisService>(); En çok Hash veri yapısı ile kullanılır; public class HashTypeController : Controller { private readonly StackExchangeRedisService _redisService; private readonly IDatabase db; private readonly string hashKey = "hashKey"; public HashTypeController(StackExchangeRedisService redisService) { _redisService = redisService; db = _redisService.GetDb(4); } public IActionResult Index() { if (!db.KeyExists(hashKey)) { db.KeyExpire(hashKey, DateTime.Now.AddMinutes(1)); } db.HashSet(hashKey, "KeyS", "Selahattin"); db.HashSet(hashKey, 2, "Ahmet"); db.HashSet(hashKey, "KeyMehmet", "Mehmet"); db.HashSet(hashKey, "KeyMehmet", "Mehmet"); return View(); } public IActionResult Show() { if (!db.KeyExists(hashKey)) return Content("hash not found"); Dictionary<string, string> list = new Dictionary<string, string>(); db.HashGetAll(hashKey).ToList().ForEach(item => { list.Add(item.Name, item.Value); }); return Content(JsonConvert.SerializeObject(list)); } public IActionResult DeleteItem() { if (!db.KeyExists(hashKey)) return Content("hash not found"); string item = "KeyS"; db.HashDelete(hashKey, item); return Content("hash deleted"); } } Burada da Set veri yapısı ile kullanımına bir örnek mevcut; public class SetTypeController : Controller { private readonly StackExchangeRedisService _redisService; private readonly IDatabase db; private readonly string ListKey = "setNames"; public SetTypeController(StackExchangeRedisService redisService) { _redisService = redisService; db = _redisService.GetDb(2); } public IActionResult Index() { if (!db.KeyExists(ListKey)) { db.KeyExpire(ListKey, DateTime.Now.AddMinutes(5)); } //SetAdd uniq itemleri tutar, aynı item birden fazla eklenemez db.SetAdd(ListKey, "Selahattin"); db.SetAdd(ListKey, "Ahmet"); bool r1 = db.SetAdd(ListKey, "Mehmet"); //true bool r2 = db.SetAdd(ListKey, "Mehmet"); //false return View(); } public IActionResult Show() { HashSet<string> names = new HashSet<string>(); if (!db.KeyExists(ListKey)) return Content("set list not found"); db.SetMembers(ListKey).ToList().ForEach(name => names.Add(name)); return Content(JsonConvert.SerializeObject(names)); } public IActionResult DeleteItem() { if (!db.KeyExists(ListKey)) return Content("set list not found"); string item = "Selahattin"; db.SetRemove(ListKey, item); return Content("set list item deleted"); } }
Daha fazla göster
image

In-Memory Cache

01.04.2024 tarihinde yayınlandı 3 dakikalık okuma 0 yorum
In-Memory Cache Verileri geçiçi olarak ram'de tutma yöntemlerinden biridir. Uygulama direkt olarak ram'e erişir, arada bir katman yoktur. Bu yüzden performansı distributed cache yöntemlerinden (örneğin redis) daha yüksektir. Uygulamanın tek bir sunucuda çalıştığı senaryolarda tercih edilebilir. Birden fazla sunucuda çalışan uygulamalar için veri tutarlılığı konusunda sorun yaratabilir. Session yönetimi ve sunucu düzenlemeleri ile sorunlar kontrol edilebilir. public IActionResult SetValueSimple() { if (string.IsNullOrEmpty(_memoryCache.Get<string>("date"))) { _memoryCache.Set<string>("date", DateTime.Now.ToString()); } return Content("data cached"); } public IActionResult SetValue() { if (!_memoryCache.TryGetValue("date", out string? dateCache)) { MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); options.AbsoluteExpiration = DateTime.Now.AddMinutes(1); //1 dk sonra her türlü ramden silinir options.SlidingExpiration = TimeSpan.FromSeconds(10); // 10 sn içinde bu veriye erişilirse erişim süresi bi 10 saniye daha uzayacak, 10 sn hiç erişilmezse ramden silinecek options.Priority = CacheItemPriority.Low;//ram dolarsa öncelikle silinecekler arasında yer alır options.RegisterPostEvictionCallback((key, value, reason, state) => //ramden silinme durumunda çalışacak metot { _memoryCache.Set<string>("callback", $"{key} --> {value} => sebep : {reason} <> durum: {state}"); }); _memoryCache.Set<string>("date", DateTime.Now.ToString(), options); } else { return Content("data already cached : " + dateCache); } return Content("data cached"); } public IActionResult SetObject() { _memoryCache.Set<UserObj>("user:1", new UserObj { Id = 1, Age = 33, FullName = "Selahattin Akan" }); return Content("data cached"); } public IActionResult GetValue() { string cacheData = _memoryCache.Get<string>("date")!; return Content("cached data: " + cacheData); } public IActionResult GetOrCreate() { //eğer cache yoksa cacheliyor, varsa değeri okuyor string? cacheData = _memoryCache.GetOrCreate<string>("date", entry => { return DateTime.Now.ToString(); }); return Content("cached data: " + cacheData); } public IActionResult GetCallbackValue() { string callback = _memoryCache.Get<string>("callback")!; return Content("callback data: " + callback); } public IActionResult GetObject() { UserObj? user = _memoryCache.Get<UserObj>("user:1") as UserObj; if (user == null) return Content("not found"); return Content($"Id:{user.Id} Age:{user.Age} FullName:{user.FullName}"); } public IActionResult RemoveCache() { _memoryCache.Remove("date"); return Content("date cache removed"); }
Daha fazla göster
image

Elasticsearch

30.03.2024 tarihinde yayınlandı 7 dakikalık okuma 2 yorum
Elasticsearch, java programlama dili ile apache lucane altyapısını kullanan bir search enginedir. Verileri JSON formatında tutan bir NoSQL’dir. RestfulAPI üzerinden çalıştığı için tüm programlama dilleriyle kullanılabilir. Blog sitemizdeki arama özelliği için bu teknoloji kullanılmıştır. Elasticsearch uygulaması docker ile ayağa kaldırılmıştır. Elasticsearch mimarisi, yetenekleri, temel bileşenleri (index , document , node , cluster , shard , replica , text analyzing , tokenization , normalization vb.) gibi konuları detaylandırmak çok fazla vakit alacaktır. Bu yüzden kodlama tarafını paylaşacağım. Program.cs’de servislere eklemek için ufak bir eklenti hazırlıyoruz. Bu eklentide uygulamanın elasticsearch’e bağlantısını yapıyoruz. namespace Elasticsearch.Extensions { public static class ElasticsearchExtension { public static void AddElastic(this IServiceCollection services,IConfiguration configuration) { string userName = configuration.GetSection("Elastic")["UserName"]; string password = configuration.GetSection("Elastic")["Password"]; var settings = new ElasticsearchClientSettings(new Uri(configuration.GetSection("Elastic")["Url"]!)).Authentication(new BasicAuthentication(userName, password)); var client = new ElasticsearchClient(settings); services.AddSingleton(client); //Elastic Search singleton olarak kullanmanızı tavsiye ediyor. } } } Sonrasında Program.cs’ye servislerimizi ekliyoruz builder.Services.AddElastic(builder.Configuration); builder.Services.AddScoped<ArticleRepository>(); builder.Services.AddScoped<IElasticsearch, ElasticsearchService>(); Sonrasında veri yapımız için uygun modeli oluşturuyoruz. namespace Elasticsearch.Models { public class ES_Article { [JsonPropertyName("_id")] public string Id { get; set; } [JsonPropertyName("title")] public string Title { get; set; } [JsonPropertyName("content")] public string Content { get; set; } [JsonPropertyName("tags")] public string Tags { get; set; } [JsonPropertyName("created")] public string Created { get; set; } //Format must "dd.MM.yyyy HH:mm:ss" [JsonPropertyName("updated")] public string Updated { get; set; } //Format must "dd.MM.yyyy HH:mm:ss" } } Sonrasında makale verileri için insert, update, delete işlemlerinin elasticsearch tarafındaki kodu yazıyoruz. Sonrasında ise bizim asıl kullanacağımız özellik olan full text search metodunu hazırlıyoruz. namespace Elasticsearch.Repositories { public class ArticleRepository { private readonly ElasticsearchClient _client; private const string indexName = "blog"; public ArticleRepository(ElasticsearchClient client) { _client = client; } public bool Save(ES_Article article, int articleId) { article.Created = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"); var response = _client.Index(article, x => x.Index(indexName).Id(articleId)); return response.IsValidResponse; } public bool Update(ES_Article article, int articleId) { article.Updated = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"); var response = _client.Update<ES_Article, ES_Article>(indexName, articleId, x => x.Doc(article)); return response.IsValidResponse; } public bool Delete(int articleId) { var response = _client.Delete<ES_Article>(articleId, x => x.Index(indexName)); return response.IsValidResponse; } public async Task<bool> SaveAsync(ES_Article article, int articleId) { article.Created = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"); var response = await _client.IndexAsync(article, x => x.Index(indexName).Id(articleId)); return response.IsValidResponse; } public async Task<bool> UpdateAsync(ES_Article article, int articleId) { article.Updated = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"); var response = await _client.UpdateAsync<ES_Article, ES_Article>(indexName, articleId, x => x.Doc(article)); return response.IsValidResponse; } public async Task<bool> DeleteAsync(int articleId) { var response = await _client.DeleteAsync<ES_Article>(articleId, x => x.Index(indexName)); return response.IsValidResponse; } public async Task<(List<ES_Article> list, long totalCount)> SearchAsync(string searchText, int page, int pageSize) { List<Action<QueryDescriptor<ES_Article>>> ListQuery = new(); Action<QueryDescriptor<ES_Article>> matchAll = (q) => q.MatchAll(); Action<QueryDescriptor<ES_Article>> matchContent = (q) => q.Match(m => m .Field(f => f.Content) .Fuzziness(new Fuzziness(1)) .Query(searchText)); Action<QueryDescriptor<ES_Article>> contentMatchBoolPrefix = (q) => q.MatchBoolPrefix(m => m .Field(f => f.Content) .Fuzziness(new Fuzziness(1)) .Query(searchText)); Action<QueryDescriptor<ES_Article>> matchTitle = (q) => q.Match(m => m .Field(f => f.Title) .Fuzziness(new Fuzziness(1)) .Query(searchText)); Action<QueryDescriptor<ES_Article>> titleMatchBoolPrefix = (q) => q.MatchBoolPrefix(m => m .Field(f => f.Title) .Fuzziness(new Fuzziness(1)) .Query(searchText)); if (string.IsNullOrEmpty(searchText)) { ListQuery.Add(matchAll); } else { ListQuery.Add(matchContent); ListQuery.Add(contentMatchBoolPrefix); ListQuery.Add(matchTitle); ListQuery.Add(titleMatchBoolPrefix); } var pageFrom = (page - 1) * pageSize; var result = await _client.SearchAsync<ES_Article>(s => s.Index(indexName) .Size(pageSize).From(pageFrom) .Query(q => q .Bool(b => b .Should(ListQuery.ToArray())))); if (!result.IsValidResponse) return new(new List<ES_Article>(), 0); foreach (var hit in result.Hits) hit.Source.Id = hit.Id; return (list: result.Documents.ToList(), result.Total); } } } SearchAsync metodunda aynı zamanda pagination işlemini de gerçekleştiriyoruz. İlgili metotlar servisler aracılığı ile MVC uygulamamız tarafından çağırılmaktadır. public async Task<IActionResult> IndexAsync(int page = 1, int pageSize = 5, string searchText = "") { ViewBag.Page = page; ViewBag.FirstPage = false; ViewBag.LastPage = false; ViewBag.SearchText = searchText; var articles = await _elasticsearch.SearchAsync(searchText, page, pageSize); long totalCount = articles.totalCount; if (page == 1) { ViewBag.FirstPage = true; } if (page * pageSize >= totalCount) { ViewBag.LastPage = true; } return View(articles.list); } Denemek için tıklayın
Daha fazla göster

Blog SAkan bir developer blogdur.

Hoşgeldiniz, mail adresinizi girerek güncel makalalelerden haberdar olabilirsiniz!