Aspect Injector in .Net
Aspect-Oriented Programming (AOP) yapısını kullanarak yazılım projelerinde kod tekrarını en aza indirmek ve yönetilebilirliği artırmak, modern yazılım geliştirme süreçlerinde büyük bir ihtiyaç haline gelmiştir. .NET tabanlı projelerde bu ihtiyacı karşılayan Aspect Injector kütüphanesi, geliştiricilerin belirli noktalara kod enjekte etmesine olanak tanıyarak logging, yetkilendirme, transaction yönetimi gibi kesişen işlemleri merkezi bir şekilde yönetmelerini sağlar. AOP tekniklerini benimseyen bu kütüphane, uygulamalarda tekrarlanan görevlerin her metot içinde yazılması yerine, merkezi bir noktada tanımlanarak daha modüler bir yapı oluşturulmasına olanak tanır.
Aspect Injector gibi kütüphanelere en çok ihtiyaç duyulan senaryolar arasında sistem çapında loglama işlemleri, hata yönetimi, yetkilendirme kontrolü ve performans ölçümleri gibi işlemler yer alır. Örneğin, bir uygulama genelinde belirli metotların başlama ve bitiş noktalarını loglamak veya belirli kullanıcı rollerine göre erişim kontrolü uygulamak, kodun her yerine eklenmesi gereken tekrar eden işlemler doğurur. Aspect Injector, bu işlemleri merkezi bir yerden yönetmeyi kolaylaştırarak, daha düzenli ve sürdürülebilir bir kod yapısı sağlar.
Bu bölümde, Aspect Injector kütüphanesinin temel özellikleri ve kullanımı ile ilgili örnek kod bloklarını inceleyerek açıklamalar yapacağım. Kütüphanenin sunduğu özellikler sayesinde projelerimizde metot başlangıç ve bitişine müdahale etme, parametre değerlerini okuma, dinamik işlemler gerçekleştirme gibi işlevleri kolayca uygulayabiliriz.
Install-Package AspectInjector
Aspect Tanımlama ve Enjekte Etme
Aspect Injector ile, belirli bir sınıfa veya metoda müdahale etmek istediğinizde öncelikle bir aspect sınıfı tanımlamamızı zorunlu kılar. Bu sınıfta, müdahale etmek istediğiniz noktalara göre, belirli işaretleyiciler kullanmanıza izin verir. Örneğin, bir metot çağrısı başlamadan önce ve bittikten sonra çalışacak bir logging aspect’i tanımlayabilirsiniz.
using AspectInjector.Broker;
using System;
[Aspect(Scope.Global)]
[Injection(typeof(LoggingAspect))]
public class LoggingAspect
{
[Advice(Kind.Before, Targets = Target.Method)]
public void Before([Argument(Source.Name)] string methodName)
{
Console.WriteLine($"Method {methodName} is starting...");
}
[Advice(Kind.After, Targets = Target.Method)]
public void After([Argument(Source.Name)] string methodName)
{
Console.WriteLine($"Method {methodName} has finished.");
}
}
Yukarıdaki LoggingAspect
sınıfı, Before
ve After
metodları ile çağırdığınız herhangi bir metodun başlangıç ve bitişine müdahale ederek, Console
ekranına metot adı ile birlikte bilgi mesajları yazdırır. Argument
özelliği ile metot adını dinamik olarak alabilirsiniz.
public class SampleClass
{
[Inject(typeof(LoggingAspect))]
public void ProcessData()
{
Console.WriteLine("Processing data...");
}
}
ProcessData
metodu çalıştırıldığında, LoggingAspect
tarafından sağlanan Before
ve After
işlemleri de tetiklenecektir.
$ dotnet run
Method ProcessData is starting...
Processing data...
Method ProcessData has finished.
Parametreler ile çalışma
Aspect Injector, metot parametrelerine erişim sağlayarak parametre bazlı işlemler yapmanıza olanak tanır. Örneğin, belirli bir metot parametresini loglamak veya doğrulamak için aşağıdaki gibi bir aspect oluşturabilirsiniz.
[Aspect(Scope.Global)]
[Injection(typeof(ParameterLoggingAspect))]
public class ParameterLoggingAspect
{
[Advice(Kind.Before, Targets = Target.Method)]
public void LogParameter([Argument(Source.Arguments)] object[] args)
{
Console.WriteLine("Parameters:");
foreach (var arg in args)
{
Console.WriteLine(arg);
}
}
}
Yukarıdaki ParameterLoggingAspect
sınıfı, metoda gönderilen tüm parametreleri args
dizisi olarak alır ve ekrana yazdırır.
public class SampleClass
{
[Inject(typeof(ParameterLoggingAspect))]
public void CalculateSum(int x, int y)
{
Console.WriteLine($"Sum: {x + y}");
}
}
$ dotnet run
Parameters:
x
y
Sum : {x+y}
Exception Handling
Aspect Injector kullanarak hataları merkezi bir yerden yönetebiliriz. Belirli metodlarda oluşabilecek hataları ele almak, loglamak ve gerekirse özel bir işlem yapmak için Exception
handling aspect’i oluşturabilirsiniz.
[Aspect(Scope.Global)]
[Injection(typeof(ExceptionHandlingAspect))]
public class ExceptionHandlingAspect
{
[Advice(Kind.Around, Targets = Target.Method)]
public object HandleException([Argument(Source.Target)] Func<object> method)
{
try
{
return method();
}
catch (Exception ex)
{
Console.WriteLine($"Exception caught: {ex.Message}");
return null;
}
}
}
Bu örnekte, HandleException
metodu Around
tavsiyesi ile çalışarak metoda giriş ve çıkışı kapsar. Func<object>
türündeki method
parametresi sayesinde metodu çalıştırır ve hata alındığında yakalar.
public class SampleClass
{
[Inject(typeof(ExceptionHandlingAspect))]
public void Divide(int a, int b)
{
Console.WriteLine($"Result: {a / b}");
}
}
Performans Ölçümü
Aspect Injector ile metotların çalışma sürelerini ölçmek de mümkündür. Performans gerektiren işlemlerde bu tür bir aspect kullanarak hangi metodun ne kadar sürede çalıştığını kolayca görebilirsiniz.
[Aspect(Scope.Global)]
[Injection(typeof(TimingAspect))]
public class TimingAspect
{
private Stopwatch _stopwatch = new Stopwatch();
[Advice(Kind.Before, Targets = Target.Method)]
public void StartTimer()
{
_stopwatch.Start();
}
[Advice(Kind.After, Targets = Target.Method)]
public void StopTimer([Argument(Source.Name)] string methodName)
{
_stopwatch.Stop();
Console.WriteLine($"Method {methodName} took {_stopwatch.ElapsedMilliseconds} ms to execute.");
_stopwatch.Reset();
}
}
Bu TimingAspect
sınıfı, bir metot başlamadan önce StartTimer
metodunu ve metot bittikten sonra StopTimer
metodunu çağırarak çalışma süresini ölçer.
public class SampleClass
{
[Inject(typeof(TimingAspect))]
public void ComplexCalculation()
{
// Simulate a time-consuming operation
System.Threading.Thread.Sleep(500);
Console.WriteLine("Complex calculation completed.");
}
}
Authorization Check
Bir kullanıcı rolüne göre belirli metodlara erişimi kontrol etmek de Aspect Injector ile mümkündür. Böylece, belirli rollerin veya kullanıcıların belirli işlevlere erişimi olup olmadığını aspect ile merkezi bir yerden yönetebilirsiniz.
[Aspect(Scope.Global)]
[Injection(typeof(AuthorizationAspect))]
public class AuthorizationAspect
{
[Advice(Kind.Before, Targets = Target.Method)]
public void CheckAuthorization([Argument(Source.Name)] string methodName)
{
// Örnek: Kullanıcının yetkisini kontrol et
bool isAuthorized = /* Kullanıcı yetkisini doğrula */;
if (!isAuthorized)
{
throw new UnauthorizedAccessException($"Access denied to method {methodName}");
}
}
}
Bu aspect, metot çağrısından önce kullanıcının yetkisini kontrol eder ve yetki yoksa UnauthorizedAccessException
fırlatır.
public class SampleClass
{
[Inject(typeof(AuthorizationAspect))]
public void SensitiveOperation()
{
Console.WriteLine("Sensitive operation executed.");
}
}
Aspect Injector kütüphanesi, Aspect-Oriented Programming (AOP) yaklaşımını benimseyen uygulamalar için güçlü bir çözüm sunarak yazılım projelerinde kod tekrarını en aza indirir ve merkezi bir yapı oluşturmaya olanak tanır. Kesişen görevlerin, örneğin hata yönetimi, loglama, yetkilendirme ve performans ölçümü gibi işlemlerin merkezi bir noktada toplanması, projelerin hem okunabilirliğini hem de sürdürülebilirliğini artırır. Bu kütüphane sayesinde, farklı modüller arasında tekrara düşmeden, daha modüler ve dinamik bir yapı oluşturmak mümkün hale gelir. Yazılım geliştiriciler, Aspect Injector ile projelerinde kod kalitesini ve yönetilebilirliğini yükseltebilir, aynı zamanda iş süreçlerini hızlandırabilirler. Aspect Injector’ın sunduğu olanaklar sayesinde, daha temiz, düzenli ve performans odaklı kodlar oluşturmak artık çok daha kolay ve verimlidir. 👋