Arda Çetinkaya Yazılım ve arada kendim ile ilgili karaladıklarım…

“Monolith” uygulamaların günümüzün hızlı değişim ihtiyaçlarına çok sağlıklı cevap verememesi ile “microservices” mimari stili, geliştirme yöntemi olarak hayatımıza girdi. Son 3-4 yıldır da “tüketim” ve “pazarlama” dünyası gerçekleri ile de reklamı yapılınca belli kalıplar içinde herkesin tercih etmeye çalıştığı bir stil oldu. Gerçekten ne kadar bu mimari yöntem ihtiyaç olarak tercih ediliyor ya da getirilerinden ne kadar değer üretiliyor bilemeyeceğim. Sonuçta “microservices” kusursuz bir çözüm yöntemi ya da ideal bir çözüm değil. Ayrıca tüm çözümler “microservices” tasarımı ile en doğru, en ideal olacak diye de bir şey yok.

Her fırsatta paylaşmaya çalışıyorum, konuya girmeden tekrar altınız çizmek isterim; “microservices”, servis odaklı mimarinin günümüz ihtiyaçlarına uygun bir şekilde evrilerek kullanılmasını sağlıklı hale getiren bir tasarım stili.

Bu kısa girişten sonra konumuza gelelim. “Microservices”(Mikroservis)’lerin bir birleri arasındaki veri ihtiyacı nasıl olmalı? Servisin bir fonksiyonunu başka bir servisten aldığımız verileri kullanarak nasıl sağlarız? Bu sorular karşıma çok çıkıyor, direkt mikroservis tasarımları ile geliştirmeye başlayan herkesin problem olarak da en çok takıldığı nokta olarak görüyorum, duyuyorum.

Açıkcası bu sorular karşınıza çıkıyor ya da kendi kendinize bunları soruyorsanız, mikroservis tasarımın stili kavram olarak tam netleşmemiştir. Öncelikle servislerin bir birleri arasındaki veri ihtiyaçları için bir birlerini çağırması, bir servisin belli işlemleri için başka servisten verileri alması falan normal ve zaten “Remote Procedure Call”(RPC) ile hayatımızda olan bir kavram. “Service Oriented Architecture(SOA)”‘nın ve dağıtık sistemlerdeki servis çağırımları yöntemleri ile servisler bir birlerinin her türlü verisini paylaşabilir. Ama bu yaklaşım günümüz ihtiyaçları ile bazen uyuşmadığı için, mikroservis tasarım stilinde de bu şekilde bir yol çok gösterilmiyor.

Mikroservislerin, en önemli karakteristik özelliği; servislerin kendi başlarına çalışan, tek bir sorumluluğu olan, bağımsız servis olmalarıdır. Dolayısıyla bir mikroservis bir veri için başka bir mikroservise ihtiyaç duymamalıdır. Aksi takdirde tek başına çalışan, bağımsız bir servis olma karakteristik özelliğini kaybedecektir.

Mikroservislerin ikinci önemli karakteristik özelliği de “business capability” yani iş alanlarının belli yetkinliklere göre sadece belli bir işi yapacak şekilde geliştirilen servisler olmaları. Yani eğer iş alanı bir veriye ihtiyaç duyuyorsa, o veri aslında o iş alanının(domain) bir parçasıdır. Eğer ihtiyaç duyduğu veriyi başka bir iş alanından alma durumu varsa yine bağımsız olma özelliği kaybolmuş oluyor. Mikroservisin çalışması için başka bir mikroservise bağımlı olması mikroservis mimari tasarım stiline ters bir durum.

Biraz gerçek hayattan bir örnek ile biraz daha anlaşılır hale getirmeye çalışacağım. Adres bilgimiz bankaların bizimle iletişim kurabilmesi için gerekli olan bir veri. Bu veri hesabımızın olduğu tüm bankalarda ayrı ayrı banka özelinde tutulmakta. Bankalar, bu adres verisi ile bizimle iletişim kurabilmekte ve fonksiyonel özelliğini gerçekleştirebilmekte. Bize her ekstre gönderecekleri zaman telefon edip, “Ekstre göndereceğiz, adresinizi söyler misiniz?” diye sormuyorlar. Böyle olsaydı eğer, telefon ettiklerinde ilgili veriyi alamadıkları zaman ekstre göndermeleri sıkıntılı olup, ekstre gönderme özelliği için istenmeyen bir bağımlılık olacaktı. Bunun yerine ilk hesap açılırken adres bilgimizi alıyorlar, kendi sistemlerine kaydediyorlar ve onu kullanıyorlar. Adresimiz değiştiği zaman bizim bilgilendirmemiz ile kendi sistemlerini güncelliyorlar.

Devam…

Yine çok hızlı bir yazı ile karşınızdayım. 🙂 Çok derinlere girmeden daha çok kod üzerinden örnekler ve bazı anahtar kelimeler ile JSON Web Token(JWT) konseptini ASP.NET Core projelerinde nasıl uygularız bundan bahsetmeye çalışacağım.

Açıkcası JWT oldukça derin bir konu. Şeması olsun, şeması ile ilişkili özellikler olsun bunların ayrıntılarına çok girmeyeceğim. Çok derinlere girmeden, JWT nedir bununla başlayalım. Client-Server iletişim mimarisinde, sunucu tarafından kimlik doğrulama, yetki tanımlama/doğrulama ve bilgi akışı güvenliği sağlamak için oluşturulmuş bir işaretleme standartı diye basitçe açıklayabilirim. İşaretleme diyerek, sunucu tarafından oluşturulan ve iletilen bir “token” ile işaretlenmiş client‘lar, bu işaret ile kendilerini sunucuya tanıtarak ve doğrulayarak, belli metotları çalıştırabiliyorlar demek istedim. Açıkcası bu şekilde bir ifade ile daha net anlaşılabileceğini düşünüyorum.

HTTP’nin “Stateless” bir protokol olması, “Session” yönetiminin transfer protokollerinde sağlıklı olmaması, dağıtık mimarilerde “Session” ve “State” yönetimin zor olması JWT’nin önünü açan bir durum. Bu bahsetmiş olduğum konular ile ilgili sorunlar ya da ihtiyaçlar ortaya çıkıyorsa JWT’ye göz atmanızda fayda var.

Neyse çok konuştuk… Daha çok kod üzerinden gidecektik, hani nerde? Öncelikle burada bahsedeceğim tüm kodlar, projeler GitHub profilimde mevcut. Direkt oradan da devam edebilirsiniz.

Şimdi gelelim senaryomuza… Bir tane WebAPI uygulamamız olsun. Bu uygulama üzerinden kullanıcı kimliği doğrulaması yapıp, web api uygulamasındaki başka kaynakları çalıştırabilelim. Eğer kimlik doğrulaması yapamıyorsak tabi ki çalıştıramayalım. Bu Web API uygulamasına kimlik doğrulaması için istersek mobilden, istersek de başka bir Web uygulamasından bağlanabileceğimizi de düşünün.

ASP.NET Core ile bu bahsetmiş olduğum senaryoyu nasıl yapacağız buna bakalım bizde. Açıkcası ASP.NET Core’da, kendi içerisindeki API’lar ve middleware yaklaşımı sayesinde JWT oluşturmasını ve doğrulamasını yapmak oldukça kolay.

Bunun için “JSON Web Token” yaratmak ve doğrulamak istediğimiz ASP.NET projemizde ConfigureServices() metoduna öncelikle JWT yapısını kullanacağımızı belirtiyoruz.

Burada önemli olan yerlere kısaca bakalım. AddAuthentication() içinde şema formatının nasıl olacağını söylüyoruz. Burada aslında çok fazla alternatifimiz yok, ama JWT şemasını kullanacığımızı tanımlıyoruz. Bu metottan hemen sonra çağırdığımız AddJWTBearer() metotu asıl önemli olan kısım. Burada artık uygulamamızda Authentication için JWT şemasının taşınacağını ve bununla ilgili çeşitli ayarların olacağını belirtiyoruz.

Devam…

Bir önceki yazıda ASP.NET Core’daki “Scaffolding” kavramından bahsetmeye çalışmıştım. Bir ASP.NET Core uygulaması yarattığınız zaman, eğer “Identity” ile yaratırsanız, uygulamayı çalıştırdığınız zaman “Login” ve “Register” işlemleri ile alakalı UI bileşenlerini proje içeriğinde olmamasına rağmen görebiliyorduk… Bunun nasıl olduğundan, hızlıca bahsetmeye çalışmıştım.

Bu yazıya biraz ön ayak olması için aslında bir şeyler karalamıştım. Ve şimdi geldik asıl konumuza. Bir uygulamada kullanılan bileşenleri, diğer başka bir uygulamada da kullanabiliyor olmak oldukça faydalı bir durum olabilir projelere göre. Aynı bir ihtiyacı, farklı projelerde her seferinde geliştirmek kimi zaman tercih edilmez. Mesela eski ASP.NET WebForms ile uğraşanlar için UserControl çok tanıdık gelecektir. Belli bir fonksiyonel özelliği olan bir bileşen oluşturup bunu farklı farklı ABC projesinde, XYZ projesinde kullanabiliyoruz. Ya da bir takvim gösterimi için jQuery Datepicker’ı eminim alakasız farklı bir çok projede kullanmışınızdır.

Peki özel bir fonksiyonel bileşeni, farklı ASP.NET Core uygulamalarında nasıl kullanabiliriz? Burada bileşen derken, belli bir ön yüze(UI) sahip, kullanıcı ile etkileşimi olan parçadan bahsediyorum…Aman diyim yanlış anlaşılma olmasın.

Hadi başlayalım…

ASP.NET Core’da tekrar kullanılabilir UI bileşenler oluşturmak için önce bir “Class Library” oluşturmamız lazım. Bu “Library”, ASP.NET Core için olacağı için Razor Class Library(RCL) olarak tanımlanıyor. ASP.NET Core 2.1 ile hayatımıza giren bir kavram. Bu tipdeki bir projeyi “dotnet new razorclasslib” ile oluşturuyoruz. Direkt “dotnet new classlib” ile de olabilir tabi ki ama projeye sonradan bir şeyler eklemek gerekir… Bu yüzden gerek yok. Bu arada tabi ki Visual Studio ile de mümkün. Yeni bir ASP.NET Core projesi yaratmak istediğinizde size zaten soracaktır.

Şimdi WebApplication.UI.Component diye bir proje oluşturduğumuzda içeriği direkt aşağıdaki gibi olacaktır.

*.cshtml ve *.cshtml.cs diye, içeriği çok basit iki tane dosya olacaktır sadece. Bunlar bizim UI bileşenimizin ilk örnek içerikler. Bu içerikleri yazıyı biraz daha anlamlı hale getirmek için biraz değiştirelim. UI bileşeni dediğimiz olay, “Kağıt-Taş-Makas” oyunu olsun. (Ulan koca adam oldum hala oyun peşindeyim 🙂 ).

Game.cshtml‘in içeriğini de aşağıdaki gibi yapalım.

@page
@model WebApplication.UI.Component.CustomComponentAsPage.Pages.GameModel
@section Scripts
{
    <script>
        $('#random').on('click', function (e) {
            var number = Math.floor(Math.random() * 3);
            var messages = ["Rock", "Paper", "Scissors"];
            alert(messages[number]);
        });
    </script>

}
<div class="text-center">
    <h1 class="display-4">Hello from a Custom UI Library, Do you wanna play Rock-Paper-Scissors?</h1>
    <a class="btn btn-large btn-success" id="random" href="">1-2-3!!!</a>
</div>

Burada dikkat ederseniz, içeriği jQuery ile javascript kodu da yazdık. Ama her hangi bir javascript kütüphanesini eklemedik. Bu şekilde projemizi derleyelim(dotnet build) ve asıl ASP.NET Core web uygulamıza referans olarak ekleyelim ve uygulamayı çalıştıralım.

Diretk olarak https://localhost:5001/CustomComponentAsPage/Game adresine gidelim. Burada url’deki path’e dikkat edelim. Bileşendeki “Areas” içeriğindeki gibi olmalı.

Yukarıdaki gibi cılız bir içerik olacaktır. Eklediğimiz javascript’de ilgili kütüphaneler olmadığı için sağlıklı çalışmayacaktır. Şimdilik çalışmasın, dert değil; birazdan daha hoş bir hale getireceğiz. 🙂 Burada önemli olan çalışan ASP.NET Core uygulamamızın projesinde böyle bir içeriğin, html, javascript vs. bulunmaması. Bu yukarıdaki içerik tamamen WebApplication.UI.Component.dll’inden yani referans olarak eklediğimiz projemizden gelmekte.

Devam…

.NET Core’un geliştirme dinamiklikleri arasında komut satırı oldukça önemli bir yer tutuyor. Direkt komut satırından uygulama geliştirmeye başlamak, derlemek ve çalıştırmak oldukça kolay ve hızlı. Bildiğiniz gibi bütün bunların sorumlusu “dotnet” komutu. Bu komut sayesinde uygulama şablonları seçip, uygulamaların temel iskeletleri ile hızlı bir şekilde başlayabiliyoruz. ASP.NET Core uygulamaları için MVC, Razor modelleri hatta Angular/React bileşenleri ile uygulama yaratmak bu komut ile oldukça basit.

“Eeee biliyoruz bunları, konuya gel!!!” dediğinizi duyar gibiyim. Bu yazıda ASP.NET Core uygulamaları için, “dotnet” komutu ile uygulama yarattığımız zaman uygulamanın varsayılan olarak yaratılan ama proje içerisinde olmayan içeriklerinden bahsedeceğim. “Olm o ne, ne dedin???” dediğinizi de duydum.

Şimdi mesela “dotnet new razor —auth Individiual” diye komut satırıyla bir ASP.NET Core uygulaması yarattığımızı düşünelim. Aşağıdaki gibi bir proje içeriği oluşacaktır.


“dotnet run” dediğimizde de, proje içeriğinde olmayan “Register”, “Profile” vs. sayfaları göreceğiz. Peki bu sayfalar nereden geliyor? Proje içerisinde yoktu ki…İşte yazının konusuna gelebildik. 🙂

Devam…

Geliştirdiğimiz uygulamaların durumlarını kontrol eden, bu kontrollere göre çeşitli alarmlar üreten monitör araçları eminim bir çoğumuza tanıdık gelecektir. Uygulamaların belli durumlarına göre tedbirler alıp, bu durumlarda müdahale edip gerekli düzenlemeleri yapabilmek adına uygulama monitör araçları ve yöntemleri oldukça önemli bir konu. Dağıtık bir yapıya sahip uygulamalarda ise olmazsa olmaz; hatta bence uygulamanın sağlığı için zorunlu bir yaklaşım. ASP.NET Core tarafında bu tarz ihtiyaçları nasıl gerçekleştirebiliriz buna bakalım…

Ama önce kavramı ve konuyu daha iyi anlamak için, bir çoğumuza tanıdık gelebilecek bir senaryoyu hatırlayalım. Bir web uygulamasının monitör edilmesini sağlamak için http://minepla.net/Status.aspx tarzı bir sayfa(url) geliştirdiğimizi düşünelim; hatta uygulamanın içinde belki bir web servis. Bu URL’de basit belli işlemler gerçekleştirerek uygulamanın durumu hakkında monitör araçlarına çeşitli bilgiler paslayabiliriz. Bu sayfaya erişim olmazsa, sayfanın yüklenmesi uzun sürerse, veri tabanı işlemlerinde yavaşlık, sayfanın içinde basit bir iş kuralından beklenen sonuç dönmezse gibi gibi farklı durumları, ilgili sistemlere iletip alarm yaratılmasını sağlayabiliyoruz. Piyasadaki bir çok monitör araçının bu tarz kaynaklardan alarm üretmesi standart artık…

ASP.NET Core tarafında, monitör araçlarının bu tarz ihtiyaçları için v2.2 Preview 2 ile gelen HealthChecks kavramına bir bakalım hızlıca.

HealthChecks kavramı ASP.NET Core’un önceki versiyonları için de bir şekilde vardı. Ama Preview 2’deki son durumundan farklı ve ek paketler ile kullanılıyordu. Şimdi Preview olmasına rağmen direkt ASP.NET Core’un içinde ve daha olgun bir durumda.

ASP.NET Core’da artık uygulamaların sağlıkları ile ilgili çeşitli durumları paylaşmak için servis olarak çeşitli kontrolleri ekleyebiliyoruz. Bunun için ConfigureServices() metodunun içerisine aşağıdaki gibi .AddHealthChecks() şeklinde kendi ihtiyaçlarımıza göre geliştirdiğimiz servisimizi ekliyoruz. Burada ihtiyaça göre metotun diğer versiyonlarını da bir göz atın derim. Şimdi onlara çok girmeyeceğim.

        public void ConfigureServices(IServiceCollection services)
        {
            .
            ..
            ...
            ....
            
            services.AddHealthChecks()
                    .AddCheck&amp;amp;amp;amp;amp;lt;CustomCheck&amp;amp;amp;amp;amp;gt;();
            ....
            ...
            ..
            .
        }

Bununla beraber, Startup.cs içindeki Configure() methodu ile uygulamamızda da HealthCheck servisinin aktif olacağını belirtmemiz gerekiyor. Burada URL olarak path’i de belirtebiliyoruz. Bu sayede http://localhost:1234/IsHealthy şeklinde uygulamanın çeşitli durumlarını paylaşabileceğimiz URL path’ini tanımlıyoruz.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            .
            ..
            ...
            app.UseHealthChecks(&amp;amp;amp;amp;quot;/IsHealthy&amp;amp;amp;amp;quot;);
            
            ...
            ..
            .
        }

Microsoft.AspNetCore.Diagnostics.HealthChecks namespace’i ile gelen bir kaç arayüz ile kendi kontrol yöntemimizi geliştirip, uygulamamızın durumlarını kontrol edebiliyoruz.

Devam…