Daha önceki Aspect Oriented yazılarında interceptor'lardan bahsetmiştik ve biz developer'lar için bulunmaz bir nimet olduğunu söylemiştik. Server-Side bir projede olmazsa olmaz özelliklerin başında gelen Logging, Exception Handling, Caching vs gibi özellikleri çok basit küçük interceptor'lar yazarak uygulamamıza bu özellikleri kazandırabiliriz. Daha önceki yazılarımızda bu ihtiyaçları karşılayabilmek için .Net tarafında oldukça entegrasyonu basit olan Postsharp kütüphanesinden faydalanmıştık. Bugün ki yazımızda ise IoC container'lardan Castle Windsor'ı kullanarak uygulamamız için bir Logging intercepter'ı geliştireceğiz.
Örneğimiz şu şekilde; Email göndermek için kullanılan basit bir Service projemiz olsun ve parametre olarak Address ve html olarak Content alsın. İlk olarak VS de EmailSender adında bir Api projesi oluşturalım ve projemizin referanslarına Nuget üzerinden Castle Windsor'ın paketlerini indirip kuralım.
Sonrasında SendEmailRequest adında request modelimizi tanımlayalım
public class SendEmailRequest
{
public string Address { get; set; }
public string Content { get; set; }
}
Email gönderme işlemini yapacak olan service interface'imiz ve onun impl. class'ını aşağıdaki gibi oluşturalım
public interface IEmailService
{
bool Send(SendEmailRequest reqModel);
}
public class EmailService : IEmailService
{
public bool Send(SendEmailRequest reqModel)
{
//todo return true dedik ancak bu kısımda email göndermek için kullandığınız kodları yazmalıyız.
return true;
}
}
Email gönderme servisimiz artık kullanıma hazır. Artık bu service'i Api ile dışarıya açma zamanı. Projemize CommunicationController adında bir controller ve bu controller içerisinde HttpPost kabul eden SendEmail adında bir endpoint tanımlayalım.
public class CommunicationController : ApiController
{
private readonly IEmailService _emailService;
public CommunicationController(IEmailService emailService)
{
_emailService = emailService;
}
[HttpPost]
public HttpResponseMessage SendEmail(SendEmailRequest reqModel)
{
var result = _emailService.Send(reqModel);
if (!result)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
return Request.CreateResponse(result);
}
}
Yukarıda görüldüğü üzre kullanacağımız IEmailService'ini Castle kullanarak EmailService'ine inject edeceğiz ve controller seviyesinde bu service interface'ini kullanarak email gönderme işlemini yapacağız.
Şimdi sırada LoggingInterceptor'ımızı oluşturma var. Bu interceptor ile log kayıtlarına MethodName, request ise aldığı parametreler ve response için return edilen değer bilgilerini atacağız.
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var serializer = new JavaScriptSerializer();
var parametersJson = serializer.Serialize(invocation.Arguments);
System.Diagnostics.Debug.WriteLine("Request of " + invocation.Method.Name + " is " + parametersJson);
invocation.Proceed();
var returnValueJson = serializer.Serialize(invocation.ReturnValue);
System.Diagnostics.Debug.WriteLine("Response of " + invocation.Method.Name + " is: " + invocation.ReturnValue);
}
}
Logları şimdilik sadece Output Window'a yazdırdım ancak gerçek hayatta tabikide NLog vs gibi bir kütüphane kullanıyor olmamızda fayda var.
Interceptor'ımızda hazır olduğuna göre artık IoC Initialize tarafına geçip gerekli register işlemlerimizi yapabiliriz. ServiceInstaller adında aşağıdaki gibi bir class oluşturalım ve içerisinde service'imizi ve interceptor'ımızı register edelim.
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For(typeof(IEmailService))
.ImplementedBy(typeof(EmailService))
.Interceptors(typeof(LoggingInterceptor)));
}
}
EmailSender servisini ve interceptor'ı register eden installer'ı tanımladık. Şimdi ise Web Api projemizin controller'ını register eden installer'ı oluşturalım.
public class WebApiControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
public class ApiControllerActivator : IHttpControllerActivator
{
private readonly IWindsorContainer _container;
public ApiControllerActivator(IWindsorContainer container)
{
_container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)this._container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => this._container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
}
Son adım olarak ise oluşturduğumuz bu installer'ları container'a Install edeceğiz. Bunun için projemizde bulunan Global.asax içerisinde bulunan Application_Start metodu aşağıdaki gibi olacak.
protected void Application_Start()
{
var container = new WindsorContainer();
container.Install(new ServiceInstaller());
container.Install(new WebApiControllerInstaller());
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new ApiControllerActivator(container));
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Hepsi bu kadardı :)
Şimdi yazdığımız kodları test edelim. Postman kullanarak controller'da bulunan endpoint'e aşağıdaki gibi bir istek gönderip Output Window dan neler yazdırdığına bir bakalım.
Request sonrasında Interceptor araya girerek loglama işlemini aşağıdaki görselde olduğu gibi yapmakta.
Örneğimiz şimdilik burada bitiyor, sizlerde projeleriniz için bir çile haline gelebilme potansiyeli olan Loglama konusunu interceptor kullanarak son derece basit ve reusable hale getirebilirsiniz.
Sonraki yazılarımızda Interceptor kullanarak daha başka neler yapabiliriz fırsat buldukça inceleyeceğiz.