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.

Read More

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.

Read More

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.
Read More

.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. 🙂

Read More

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.

Read More

.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…

Blog’u uzun süredir takip edenler ya da az biraz tanışma fırsatı bulduğum kişiler Managed Extensibility Framework(MEF) ile ilk çıktığı günden beri haşır neşir olduğumu bilir. 🙂 Artık direkt .NET Framework’ün bir parçası olması belki farkındalığını biraz azalttı ama açıkcası .NET ile uygulama geliştirirken belli ihtiyaçları kolayca geliştirmek için güzel bir yapı.

MEF ne işe yarıyor, neler yapılabilir bunlara tekrar girmeyeceğim ama özet olması için;

  • Plug-in kavramı gibi ek parçalar ile uygulamalara yeni fonksiyonlar eklemek için ortaya çıkan bir yapı.
  • WPF, WinForms, ASP.NET gibi farklı uygulama tiplerinde kullanılabilmekte.
  • .NET Framework 4.0 ile beraber, .NET Framework’ün içine dahil edildi.
  • Uygulamanın bütünlüğünü çok değiştirmeden sadece fonkisyonları kolayca ekleyip, çıkarmak mümkün olabiliyor.

Daha önceleri paylaştığım yazılara da göz atmanızı tavsiye ederim. [MEF Yazıları]

Gelelim bu yazımızın konusuna; .NET Core’da Managed Extensibility Framework(MEF) kullanımı…

MEF, .NET Core’a Microsoft.Composition ile port edildi. Ama ne yazık ki tüm API’ları ile beraber edilmedi. Önemli bir kaç API port edilemese de, MEF’in karakteristik özelliklerini ve temel fonksiyonlarını sorunsuz bir şekilde .NET Core’da kullanabiliyoruz.

Port edilen API’lar sadece System.Composition namespace’indeki API’lar. Dolayısıyla MEF’deki en sevdiğim özelliklerden, kataloglar; AggregateCatalog, ApplicationCatalog, AssemblyCatalog .NET Core tarafında kullanılır durumda değil. Dolayısıyla MEF kullandığınız bir uygulamanızı .NET Core’a port etme çalışması içerisindeyseniz, MEF kısımlarında bir kaç düzenleme yapmanız gerekebilir.

Ayrıca sağlıklı MEF’i sağlıklı kullanmak için Microsoft.Composition 1.0.31 min. versiyon olacak şekilde kullanmanızı tavsiye ederim. Bir kaç sinir bozucu hata giderilmiş durumda. NuGet‘den versiyonları takip edebilirsiniz…

Neyse kafanızı yeteri kadar karıştırdığıma göre örnek kodlara geçelim…

Öncelikle MEF bileşeni olarak “export” etmek istediğimiz sınıflar için .NET Framework’de temel olarak ne yapıyorsak, .NET Core’da da devam.

Önce bir interface oluşturup, bu interface ile sınıfımızı geliştirip, [Export] özelliği ile MEF için dışarıya aktarılacak bir sınıf olduğunu belirtmemiz gerekmekte.


namespace NotifyMe.Common
{
    public interface IBaseTemplate
    {
        string Create(string message, string from, string image);
    }
}

//Export edeceğimiz sınıfların ayrı bir assembly'de olması,
//MEF'in genişletilebilir özellikleri sunması açısından doğru olacaktır.
namespace NotifyMe.Templates
{
    [Export("ChatMessage",typeof(IBaseTemplate))]
    public class ChatMessageBaseTemplate : IBaseTemplate
    {
        public string Create(string message, string from, string image)
        {
            //Burada takla atalım, zıplayalım, uçalım...
        }
    }
}

MEF’in tak-çıkart yaklaşımı ile fonksiyonları kullanma yaklaşımdan dolayı, tüm [Export]’ların ayrı assembly’ler yani ayrı projeler olmasına dikkat edin.

Şimdi de export ettiğimiz bileşenleri ana uygulamamızda nasıl alırız buna bakalım. .NET Core tarafında tüm katalogları kullanamadığımız için ContainerConfiguration sınıfı ile MEF bileşenleri için bir katalog oluşturup, bunun üzerinden bileşenleri alıyoruz.

Aşağıdaki örnek bir web uygulamasından(ASP.NET Core); örnekteki uygulamada root dizininde Plugins diye bir klasör var. Bu klasöre konan *.dll’ler, ana web uygulaması tarafından kontrol edilip yüklenmekte. Daha sonra _templates şeklinde bir liste üzerinden erişilebilir duruma geçiyor.Bu sayede bir ASP.NET Core uygulamasında herhangi bir değişiklik yapmadan sadece belli bir dizine(Plugins) ABC.dll’ini koyup belli fonksiyonları çalıştırmak mümkün. Eğer bu fonksiyonu değiştirmek gerekiyorsa, ana uygulamada bir değişiklik yapmadan ABC.dll’i yerine XYZ.dll’ini koyarak fonksiyonu değiştirmek oldukça kolay.


        [ImportMany]
        private IEnumerable<IBaseTemplate> _templates { get; set; }
        public MessageService(IHostingEnvironment hosting, ILogger<MessageService> logger)
        {
            _logger = logger;

            try
            {

                
                var rootPath = hosting.ContentRootPath;
                var path = Path.Combine(rootPath, "Plugins");
                var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories)
                            .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)
                            .ToList();
                var pluginContainer = new ContainerConfiguration().WithAssemblies(assemblies);
                using (var container = pluginContainer.CreateContainer())
                {
                    _templates = container.GetExports<IBaseTemplate>("ChatMessage");
                }
            }
            catch (System.IO.DirectoryNotFoundException dnfe)
            {
                _logger.LogError(dnfe.Message);
            }
            catch (System.Exception ex)
            {
                _logger.LogError($"Unable to find message templates. {ex.Message}");
            }
        }

Hızlıca ve kısa oldu ama .NET Core tarafında da MEF API’larının kullanılabilir olduğunun farkındalığı bir çok ihtiyacınızı çok rahat bir şekilde karşılamanız için yol gösterecektir. Özellikle .NET Core’un “dependency injection” desteği ile MEF’in gücü birleştiği zaman ortaya güzel şeyler çıkıyor.