Bu yazımızda Middleware’ın (ara yazılımın) ne olduğu, ne işe yaradığı, onu neden kullandığımız hakkında konuşacağız ve çeşitli türde middleware yazılımlarının çeşitli uygulamalarının tanıtımını yapacağız. Ayrıca middleware içinde bulunduğu pipeline (işlem hattı), nasıl oluşturulacağı ve bu pipeline daki işlem sırasının neden önemli olduğu hakkında da konuşacağız.
Middleware
En temelinde, HTTP kullanan herhangi bir etkileşim, bir request (istek – genellikle bir tarayıcıdan veya API’den) ve bir response’den (yanıt dan) oluşur. Tarayıcılar, API’ler veya diğer request bulunanlar bir request gönderir ve hedefin (bir web sunucusu, başka bir API, başka bir şey) response vermesini bekler.
Middleware, request bulunan ile hedef arasında yer alır ve request’e bağlı olarak bunu yapmak için request içindeki verileri kullanarak response doğrudan değiştirebilir, bir şeyleri günlüğe kaydedebilir veya response oluşturan kodun davranışını genel olarak değiştirebilir.
ASP.NET 6, bir dizi middleware sınıfından oluşan bir pipeline uygular. Bir request, bir middleware sınıfının bir response oluşturduğu bir noktaya ulaşana kadar pipeline (işlem hattını) filtreler. Hesaplamalarının sonuçlarına bağlı olarak, bir middleware bir sonraki öğeye yürütme kontrolü vermemeyi seçebilir.
Middleware Ne İçin Kullanılır?
Devam etmeden önce, neden bir ASP.NET 6 uygulamasında middleware yazılımını kullanmak isteyebileceğimizden bahsetmeliyiz. Bunu yapmak için yaygın senaryolardan bahsedelim.
Middleware iyi hizmet ettiği yaygın bir senaryo (ve daha sonraki bir gönderide ayrıntılı olarak ele alacağımız senaryo) logging’ dir (günlüğe kaydetmedir). Middleware, URL’ler ve path (yollar) da dahil olmak üzere request’lerin daha sonra raporlanmak üzere bir logging sistemine kolayca kaydedilmesini sağlar.
Middleware yazılımı aynı zamanda authorization (yetkilendirme) ve authentication (kimlik doğrulama), tanılama ve error logging (hata kaydı) ve handling (yönetimi) yapmak için harika bir yerdir.
Temel Bir Program.cs Dosyası
Yeni bir .NET 6 web uygulaması oluşturduğunuzda Visual Studio tarafından oluşturulan Program.cs dosyasına bir göz atalım:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Bu dosya, ASP.NET 6 web uygulamasının request’leri işlemek için kullandığı pipeline (işlem hattını) oluşturur. Ayrıca, .NET 6 tarafından sağlanan özel metotları kullanarak pipeline bir dizi “default” middleware ekler. Uygulamanın .js ve .css gibi statik dosyaları döndürmesine izin veren UseStaticFiles() ve URL’lerin server end point yönlendirilmesini işlemek için .NET Routing ekleyen UseRouting() gibi. Varsayılan olarak, bir ASP.NET 6 uygulaması kullanıyorsanız zaten middleware kullanıyorsunuz demektir.
Ayrıca, ASP.NET 6 uygulamaları, .NET 6 tarafından sağlanan bu “built-in” middleware büyük bir kısmını Microsoft docs sitesinde bulabilirsiniz.
Middleware Basit Özelleştirme
Tam olarak tek bir şey yapan basit bir middleware oluşturalım: “Merhaba Dünya!” yazısını response olarak döndüren.
Program.cs’de, Run() metodunu kullanarak aşağıdaki gibi yeni bir middleware ekliyoruz:
app.Run(async context =>
{
await context.Response.WriteAsync("Merhaba Dünya!");
});
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Uygulamayı çalıştırdığımızda şu çok basit çıktıyı göreceğiz:
Run(), Use(), ve Map()
Program.cs dosyasını okurken, genel olarak uygulamanın hangi bölümlerinin middleware olarak kabul edildiğini, bunları pipeline eklemek için kullanılan metoda bakarak belirleyebilirsiniz. En yaygın olarak, Run(), Use() ve Map() metotları kullanılır.
Run()
Run() metodu, pipeline’da o noktada bir middleware çağırır. Ancak, bu middleware her zaman terminal olacaktır, örn. response döndürülmeden önce yürütülen son middleware yazılımı. Önceki bölümden bu kod bloğunu hatırlayın:
app.Run(async context =>
{
await context.Response.WriteAsync("Merhaba Dünya!");
});
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Run() metodunun çağrılması nedeniyle, bu çağrıdan sonra yazılan hiçbir şey yürütülmez.
Use()
Use() metodu, pipline’a bir middleware yerleştirir ve bu middleware’in denetimi işlem hattındaki bir sonraki öğeye geçirmesine izin verir.
app.Use(async (context, next) =>
{
//Do work that does not write to the Response
await next.Invoke();
//Do logging or other work that does not write to the Response.
});
“Next” parametresine dikkat edin. Bu parametre, daha önce bahsedilen request delegate’dir. Pipeline hattındaki bir sonraki middleware parçasını temsil eder. “next.Invoke()” üzerinde bekleyerek, isteğin bir sonraki middleware geçmesine izin veriyoruz.
Map()
Pipeline’ı “dallara ayırmamıza” izin verir; request path (yoluna) bağlı olarak middlware’i koşullu olarak çağırmak için kullanabiliriz.
app.Map("/branch1", HandleBranchOne);
app.Map("/branch2", HandleBranchTwo);
//Rest of Program.cs file
app.Run();
static void HandleBranchOne(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("You're on Branch 1!");
});
}
static void HandleBranchTwo(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("You're on Branch 2!");
});
}