ASP.NET Core‘un en önemli özelliklerinden biri de “Middleware” yapısı. “Request-Response” modelinin ortasında özelleştirilmiş operasyonlar gerçekleştirip, request-response akışını yönetmek için oldukça etkili bir özellik. Gelen bir request‘in geçerliliğini kontrol etmek, response‘ları cache‘den oluşturmak gibi gibi birçok farklı ihtiyacı bu araya koyduğumuz yapılar ile ASP.NET Core‘da yapabiliyoruz.  

“Middleware”ler temelinde IApplicationBuilder arayüzünden türeyen bir sınıfa eklenti şeklinde eklenen metotların çalıştırılmasını sağlayan bir yapı. Web uygulamalarında da uygulamanın “request-response” yönetimini sağlayan sınıfın, yeni metodlar ile yapabileceklerinin artması ya da çeşitlenmesi şeklinde de basitçe düşünebiliriz. Çok daha ayrıntıya girmeden yavaştan konumuza geçelim…

Şartlı “middleware” kullanımı…

Eklediğimiz middleware‘lerin farklı şartlarda/durumlarda geçerli olmasını ya da olmamasını çok kolay bir şekilde ASP.NET Core‘da sağlayabiliyoruz. Bu ne demek hızlıca bakalım… 

Biraz daha anlaşılır olması için, basit bir senaryo örneği oluşturalım. Bir “middleware” geliştirdiğimizi düşünün, web uygulamasına gelen request‘in header bilgisindeki bir değeri kontrol etsin; “GET www.abc.com/v1/user/” eğer bu request‘in header‘ında key:abc123 varsa geçerli bir request olsun, yoksa da 401 dönsün… Çok tanıdık ve standart bir senaryo. Bu senaryoyu biraz daha kompleks hale getirelim. Eğer yeni geliştirdiğimiz v2 versiyonuna bir request gelirse de ek olarak farklı bir kontrol daha yapılsın. 

Şimdi “Ama bu çok kolay zaten, ne var ki bunda” dediğinizi duyar gibiyim.😉 Geliştirdiğimiz “middleware” içerisinde bir if-else kontrolü ile akışı kontrol eder ve ihtiyaca göre istenilen operasyonları gerçekleştirebiliriz. 

if(v1==true)
{
    ......
    ...
    ..
} else if(v2==true) {
    ......
    ...
}

Ne yazık ki yazılım geliştirme için bu basitlik yeterli değil, daha da basit olmalı. 🤔 Geliştirdiğimiz bu “middleware“i farklı projelerinde de kullandığımızı ve projelere göre farklı adreslerin olabileceği (/v1/user değil, versiyon1/user/ mesela) ya da farklı ek özelliklerin gerektiğini düşünün… 

UseWhen() 

Az önce yukarıda “middleware” yapısının, eklenti(extension) metodlar ile oluştuğunu belirtmiştim. ASP.NET Core içerisinde olan UseWhen() metodu da yine bir extension metot ve bununla diğer “middleware”‘leri belli şartlara göre uygulamamızda geçerli olacak şekilde kullanabiliyoruz. 

            app.UseExceptionHandlingMiddleware();

            app.UseWhen(context => context.Request.Path.StartsWithSegments("/v1"), appBuilder =>
            {
                appBuilder.UseMiddleware<ApplicationAuth>();
            });

            app.UseHttpsRedirection();
            app.UseStaticFiles();

Yukarıdaki örnekte eğer request yapılan adres “/v1” şeklinde bir içerikle başlıyorsa, ApplicationAuth diye bir “middleware” kullanılsın şeklinde bir tanım var. Eğer request yapılan adres “/v1” şeklinde başlamıyorsa araya eklediğimiz “middleware” etkili olmayacaktır. Ve alttaki diğer “middleware”‘ler etkili olacaktır. 

Bu sayede ApplicationAuthmiddleware“‘in içindeki kodu temiz ve sade tutarak, kütüphane şeklinde birden fazla projede kullanabilir hale getirebiliyoruz. 

MapWhen() 

Benzer bir yapıyla da bir “middleware”‘den sonra “request-response” arasındaki akış devam etmesin ve farklı bir şekilde sonuçlansın istenebilir. Bunun içinde MapWhen() extension metodu yardımımıza koşuyor. 

            app.UseExceptionHandlingMiddleware();

            app.MapWhen(context => context.Request.Path.StartsWithSegments("/v1/user/"), appBuilder =>
            {
                appBuilder.UseMiddleware<ActiveEndPointCheck>();
            });

            app.UseHttpsRedirection();
            app.UseStaticFiles();

Yukarıdaki örnekte de MapWhen() ile, request yapılan adres “/v1/user/” şeklinde başlıyorsa, ActiveEndPointCheck “middleware”‘i etkin olacak ama sonrasındaki diğer “middleware”‘ler etkin olmayacaktır. Bu yüzden MapWhen()’nin kullanımına ekstra dikkat etmek gerekiyor.  

Hem MapWhen() hem de UseWhen() parametre olarak Func<HttpContext, bool> şeklinde bir boolean dönen delege bir metot bekliyor. boolean dönen her hangi bir ifade ile de metotlar için geçerlilik oluşturabiliyoruz.

            app.UseWhen(context => DateTime.Now.Date.Month==2, appBuilder =>
            {
                appBuilder.UseMiddleware<CampaignControl>();
            });

ASP.NET Core içinde gelen bu iki extension metotu GitHub’dan da kontrol edebilir, kendi projelerinizde de benzer yaklaşımları uygulamak için ilham alabilirsiniz. 😀

“Middleware”‘ler kullanım yöntemleri ile de ASP.NET Core çözümlerine oldukça değer katıyor. Basit ama etkili bu iki metot benim ihtiyacımı hızlıca çözümlememde çok yardımcı oldu, aynı hızla ben de paylaşmak istedim. Umarım size de yardımcı olur.