[Patrones] Intercepción de llamadas a métodos (III) IoC containers
Continuando y para cerrar ya la serie de posts sobre la intercepción de llamadas a métodos (Aquí está el primero y segundo) vamos a terminar con un ejemplo usando un contenedor de dependencias.
Para este ejemplo vamos a usar Castle Windsor. Si intentamos instalarlo usando la consola de NuGet recibiremos este error:

La solución a este error la he encontrado en stackoverflow y es usando el pipeline de powershell para instalar todos los paquetes que Castle.Windsor necesita:

Una vez instalado, vamos a crear el interceptor y para ello vamos a implementar la interfaz IInterceptor:
{
private readonly ISecurityValidation _securityValidation;
public SecurityInterceptor(ISecurityValidation securityValidation)
{
if (securityValidation == null)
throw new ArgumentNullException("securityValidation");
_securityValidation = securityValidation;
}
public void Intercept(IInvocation invocation)
{
if (_securityValidation.Validate())
invocation.Proceed();
else
{
throw new SecurityException("No tienes permisos!");
}
}
}
Creamos un constructor parametrizado al que le vamos a inyectar nuestra implementación para la controlar la seguridad de nuestra aplicación e implementamos el método Intercept, que será donde ejecutemos la llamada a nuestro servicio o proveedor de validación que vamos a implementar.
La interfaz ISecureValidacion y su implementación son muy sencillas para no complicar el ejemplo:
public interface ISecurityValidation
{
bool Validate();
}
// Para no complicar la demo he optado por implementar un proveedor de validación
// sencillo, aquí podrías implementar tu validación personalizada
public class SecurityValidation : ISecurityValidation
{
public bool Validate()
{
return true;
}
}
Ahí podriamos añadir una lógica de validación controlando el método al que se está llamandoy quién lo está llamando, que se lo podemos pasar desde el parametro IInvocation que recibe el método Intercept del interceptor. Esto ya a gusto del programador y además todo esto nos sirve para implementar auditoría, trazas, logging… no solo seguridad.
Por último la aplicación de consola:
static void Main(string[] args)
{
IWindsorContainer windsorContainer = new WindsorContainer();
windsorContainer.Register(
Component.For<SecurityInterceptor>());
windsorContainer.Register(
Component.For<IOrderRepository>().ImplementedBy<SqlOrderRepository>());
windsorContainer.Register(
Component.For<IOrderService>().ImplementedBy<OrderService>().
Interceptors<SecurityInterceptor>());
windsorContainer.Register(
Component.For<ISecurityValidation>().ImplementedBy<SecurityValidation>());
var orderService = windsorContainer.Kernel.Resolve<IOrderService>();
var order = new Order
{
Id = Guid.NewGuid(),
Total = 102.4M
};
try
{
orderService.Submit(order);
}
catch (SecurityException securityException)
{
Console.WriteLine(securityException.Message);
}
Console.Read();
}
Como podéis observar, registramos las dependencias, el interceptor y el punto interesante es cuando añadimos el interceptor al servicio:
windsorContainer.Register(
Component.For<IOrderService>().ImplementedBy<OrderService>().
Interceptors<SecurityInterceptor>());
Además Castle Windsor nos inyectará la implementación del proveedor/servicio de validación en nuestro interceptor.
Nota: Los contenedores ahora permiten registrar las dependencias utilizando expresiones lambdas con lo que podemos casi automatizar el proceso de registro de dependencias sin utilizar mucho código.
Si ejecutamos la aplicación podemos observar como se está interceptando la llamada:

y al final, como no tenemos permisos:

Pues con esto finalizamos la serie de intercepción de llamadas. En este caso lo hemos hecho con la seguridad pero como he mencionado ante se utilizar para otras cosas. A mí personalmente me gusta mucho esta manera de interceptar las llamadas me parece la más elegante aunque claro está necesitas de un contenedor de dependencias y pagar un pequeño precio por el rendimiento que en algunos casos será asumible y necesario y en otros no.
Un saludo y espero que os haya gustado.