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

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…

.NET Core bir çok acıdan .NET teknolojileri ile geliştirilen sistemlere farklı yaklaşımlar katıyor. Açık kaynak geliştirme yaklaşımı, farklı platformlarda çalışabilen bir yapısının olması, performans açısından kuvvetli olması, hızlı ve sürekli olan geliştirme döngüleri gibi gibi temel bir kaç konu ve derinlerde niceleri… Bu yazıda çok derinlere inmeden, .NET Core’un performans konusundaki iyileştirmelerinden bir tanesinden bahsetmeye çalışacağım.

Şu sıralar bildiğiniz gibi .NET Core 2.2 Preview 2 yayınlandı ve RTM’e biraz daha yaklaştı. Bu versiyon ile arka tarafta oldukça önemli; performans ile alakalı, bir özellik .NET Core ile geliştirilen uygulamalara dahil oluyor. Performans tarafındaki bazı iyileştirmeler direkt geliştirme alışkanlıklarımıza dokunmasa da onların farkındalığı, uzun vadede önemli diye düşünüyorum.

Bahsedeceğim iyileştirme ya da yeni özellik, derleme tarafında olan bir yenilik. Ve aslında .NET Core 2.1 ile hayatımıza çoktan gelmişti. Ancak varsayılan özellik olarak bu özellik devreye sokulmamıştı. Sadece belli bir ayar ile aktif hale geliyordu. .NET Core 2.2 ile beraber artık varsayılan olarak, aktif bir şekilde .NET Core uygulamalarının hayatına girecek. .NET Core 2.2 Preview 2 ile de direkt artık aktif… Peki ne bu iyileştirme?

İyileştirmeden tam bahsetmeden önce, standart .NET Framework tarafındaki derleme yaklaşımını bir hatırlayalım. Bildiğiniz gibi yazmış olduğumuz C#/VB.NET/F# kodlarını derlediğimiz zaman, bu kodlar Microsoft Intermediate Language(MSIL)’e dönüşüyor ve *.dll olarak ya da *.exe olarak çalışmaya hazır bir şekilde saklanıyor. Kodlarımız çalıştığı zaman, Common Language Runtime(CLR) tarafından MSIL’e dönüşmüş kodlarımızı Just-In-Time(JIT) derleyicisi ile tekrar derleniyor ve işlemcinin(CPU) anlayacağı dile yani makine diline dönüştürüp işlemci tarafından çalıştırılmasını sağlıyor. Bu iki farklı derleme aşamasında, derleyiciler kendi çalışma durumlarına göre çeşitli optimizasyonlar yapıyor. Bu derlemeler tek bir seferde yapılıyor. Dolayısıyla yapılan optimizasyonlar tek bir seferlik oluyor. JIT derleyicisi çalışma zamanını direkt etkileyecek çıktılar ürettiği için oradaki optimizasyonlar oldukça önemli. Orada kullanılan algoritmalara göre derlenen çıktı, çok hızlı başlayabilir ama normal durağan anında farklı şekilde işleyebilir. Ya da tam tersi…Kısa bir özet olması için çok ayrıntılara girmiyor ve burada bırakıyorum, biz gelelim .NET Core 2.x tarafına…

.NET Core 2.1 ile, JIT tarafında bir çok iyileştirme yapıldı. Microsoft’un benchmark’larına göre de oldukça etkileyici çıktılara sahip iyileştirmeler. Bunlara buradan erişebilirsiniz…

.NET Core 2.2 ile hayatımıza girecek en önemli iyileştirme çalışma zamanında yapılan derlemenin tek değil, duruma göre çoklu versiyonlara sahip bir derleme olması. Bu sayede JIT derlemeyi birden fazla kez yapabilecek ve hızlı bir şekilde derlenmiş çıktı değişebilecek. Bu sayede de kodları daha hızlı çalışabilecek, hatta çalışıyor da. Bu olaya “Tiered Compilation” diyor .NET Core tarafı…

Biraz daha basite indirgeyip daha iyi anlayalım. Derlenmiş C# kodumuzun çıktısı MSIL, run-time zamanında JIT tarafından çok hızlı bir şekilde derleniyor(Tiered Compilation). Bu derleme aşamasında, kod çıktısı hızlı ayağa kalksın, motor hızlıca ısınsın(:P) diye belli optimizasyonlardan ferakat ediliyor. Eğer kod çok çalışan bir nokta ise derleme yine gerçekleşiyor ve farklı optimizasyonlar ile yine hızlı çalışan bir kod çıktısı oluyor.

Hepimizin bildiği; Release ve Debug modda derleyince farklı optimizasyonların yapılmış olmasını düşünün. Release modda derlendiğinde yapılan optimizasyonların uygulamanın çalışma şekline göre tekrar farklı farklı yapıldığını düşünün. Bu son “düşünün, düşünün” diye verdiğim örnek umarım biraz daha net anlaşılmasına yardımcı olur. 🙂

Başta da söylediğim gibi bu özellik, .NET Core 2.1 ile hayatımıza girmişti. Ancak *.csproj ya da environment değişkenlerinden aktif hale getirebiliyorduk. .NET Core 2.2 ile artık aktif hale getirmemize gerek yok. Varsayılan çalışma şekli olarak zaten aktif olacak. Ama benzer şekilde bu sefer de istersek, pasif hale almak mümkün olacak.

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>netcoreapp2.1</TargetFramework>
      <TieredCompilation>true(artık false yapıp kapatabiliriz)</TieredCompilation>
    </PropertyGroup>
</Project>

Arka taraftaki bu iyileştirme dediğim gibi geliştirme yaklaşımıza direkt dokunacak bir konu değil. Ama üzerinde çalıştığımız teknolojilerin, çalışma yapılarını ne kadar bilirsek, çözüm sağlama ve problem çözme yaklaşımlarımız o derece iyi olur düşüncesindeyim. Umarım bir şekilde de olsa faydası dokunur. Bir sonraki yazıda görüşmek üzere…