Está en la página 1de 21

Page | 1

Hands-On Lab
LAB 02 - Implementando desacoplamiento
IoC DI con UNITY
Objetivos
El objetivo de este Lab es analizar de forma prctica los diferentes puntos de desarrollo relacionados con
el desacoplamiento de componentes mediante Inyeccin de Dependencias con Microsoft UNITY.
La mayora de los siguientes LABs estn relacionados con la implementacin de la aplicacin ejemplo
NLAYERAPP (http://microsoftnlayerapp.codeplex.com/ ).
Introduccin a Unity
El Application Block denominado Unity (implementado por Microsoft Patterns & Practices), es un
contenedor de inyeccin de dependencias extensible y ligero (Unity no es un gran framework pesado).
Soporta inyeccin en el constructor, inyeccin de propiedades, inyeccin en llamadas a mtodos y
contenedores anidados.
Bsicamente, Unity es un contenedor donde podemos registrar tipos (clases, i nterfaces) y tambin
mapeos entre dichos tipos (como un mapeo de un interfaz hacia una clase) y adems el contenedor de
Unity puede instanciar bajo demanda los tipos concretos requeridos.
Page | 2
Unity est disponible como un download pblico desde el site de Microsoft (es gratuito) y tambin est
incluido en la Enterprise Library 4.0/5.0 y en PRISM (Composite Applications Framework), los cuales
hacen uso extensivo de Unity.
Para hacer uso de Unity, normalmente registramos tipos y mapeos en un contenedor de forma que
especificamos las dependencias entre interfaces, clases base y tipos concretos de objetos. Podemos
definir estos registros y mapeos directamente por cdigo fuente o bien, como normalmente se har en
una aplicacin real, mediante XML de ficheros de configuracin. Tambin se puede especificar inyeccin
de objetos en nuestras propias clases haciendo uso de atributos que indican las propiedades y mtodos
que requieren inyeccin de objetos dependientes, as como los objetos especificados en los parme tros
del constructor de una clase, que se inyectan automticamente.
Unity proporciona las siguientes ventajas al desarrollo de aplicaciones:
- Soporta abstraccin de requerimientos; esto permite a los desarrolladores el especificar
dependencias en tiempo de ejecucin o en configuracin y simplifica la gestin de aspectos
horizontales (crosscutting concerns), como puede ser el realizar pruebas unitarias contra mocks y
stubs, o contra los objetos reales de la aplicacin.
- Proporciona una creacin de objetos simplificada, especialmente con estructuras de objetos
jerrquicos con dependencias, lo cual simplifica el cdigo de la aplicacin.
- Aumenta la flexibilidad al trasladar la configuracin de los componentes al contenedor IoC.
Proporciona una capacidad de localizacin de servicios; esto permite a los clientes el guardar o cachear
el contenedor. Es por ejemplo especialmente til en aplicaciones web ASP.NET donde los
desarrolladores pueden persistir el contenedor en la sesin o aplicacin ASP.NET.


Page | 3
Ejercicio 1: Registro de Tipos en
contenedor de UNITY
Como ejemplo de uso de los mtodos RegisterType y Resolve, a continuacin realizamos un registro de
un mapeo de un interfaz llamado ICustomerService y especificamos que el contenedor debe devolver
una instancia de la clase CustomerService (la cual tendr implementado el interfaz ICustomerService).
C#
//Registro de tipos en Contenedor de UNITY
IUnityContainer container = new UnityContainer();
container.RegisterType<ICustomerManagementService, CustomerManagementService>();
...
...
//Resolucin de tipo a partir de Interfaz
ICustomerManagementService customerSrv = container.Resolve<IICustomerManagementService>();

Como posibilidad adicional, en la versin final de aplicacin, el registro de clases, interfaces y mapeos en
el contenedor, se puede realizar de forma declarativa en el XML de los ficheros de configuracin,
quedando completamente desacoplado. Sin embargo, tal y como se muestra en las lneas de cdigo
anteriores, durante el desarrollo probamente es ms cmodo realizarlo de forma Hard-coded, pues as
los errores tipogrficos se detectarn en tiempo de compilacin en lugar de en tiempo de ejecucin
(como pasa con el XML).
Con respecto al cdigo anterior, la lnea que siempre estar en el cdigo de la aplicacin, sera la que
instancia propiamente el objeto resolviendo la clase que debe utilizarse mediante el contenedor, es
decir, la llamada al mtodo Resolve() (Independientemente de si se realiza el registro de tipos por XML
o Hard-Coded).

Page | 4
Paso 1 Analizar el Registro de Tipos (Clases e Interfaces) en la aplicacin NLAYERSAMPLEAPP.
1. Abrir el fichero IoCUnityContainer.cs del proyecto Infrastructure.CrossCutting.IoC:

2. Desplegar la seccin Private Methods dentro de dicho fichero:

3. Analizar los distintos registros de tipos realizados en el mtodo
ConfigureRootContainer(IUnityContainer container):
Page | 5


4. El LifeTimeManager es el tipo de instanciacin de clase que se realizar. En la mayora de los
casos (Repositorios, Servicios, etc.) y por defecto si no se le especifica el LifeTimeManager a
Unity, la forma de instanciacin normal ser TransientLifetimeManager, es decir, un objeto
nico por cada referencia. Pero en algunos casos puede interesarnos otros tipos de
instanciacin como del estilo a singleton, compartidos por contextos de ejecucin, etc.
Podemos tener los siguientes tipos de vida de objetos instanciados:
o TransientLifetimeManager: Este LifeTimeManager asegura que las instancias de objetos
se crean nuevas cada vez (no reutilizacin de objetos entre diferentes llamadas).
o PerResolveLifetimeManager (Nuevo en Unity 2.0): Asegura que las instancias de un
tipo de objeto se reutilizan a lo largo de todo un grafo de dependencias de objetos
creados por Unity.
o ContainerControlledLifetimeManager: Implementa un comportamiento singleton para
cada objeto creado. El contenedor si mantiene referencias a los objetos creados y se
hace un dispose automtico cuando se hace un dispose del contenedor.
o ExternallyControlledLifetimeManager: Este LifeTimeManager mantiene una referencia
dbil a su instancia manejada. Es decir, implementa un comportamiento singleton pero
el contenedor no mantiene una referencia al objeto que deber ser eliminado
(disposed) cuando se salga del mbito.
o PerThreadLifetimeManager: Reutiliza una nica instancia de cada clase por thread que
accede al grafo de objetos de dependencias creado por Unity.
Interfaz por el que se preguntar Clase de Implementacin asociada
Tipo de LifeTimeManager
Page | 6
o HierarchicalifetimeManager (Nuevo en Unity 2.0): Implementa un comportamiento
singleton, pero los contenedores hijos no comparten instancias con los contenedores
padres.
o PerExecutionContextLifetimeManager (Custom de NLayerSampleApp): Este
LifeTimeManager es custom creado en la aplicacin ejemplo NLayerApp. Su
comportamiento es parecido a PerResolveLifetimeManager, pero en lugar de ser
compartidas las instancias entre el grafo de objetos de dependencias a partir del primer
resolve(), cuando hacemos uso de PerExecutionContextLifetimeManager, los objetos
se comparten por todo el contexto de ejecucin inicial, por ejemplo, para todas las
operaciones de una peticin WCF (a partir de un WebMethod) o a partir de una peticin
ASP.NET o incluso a partir de una ejecucin de un mtodo de Pruebas Unitarias.
En concreto nos basamos en los siguientes contextos:
OperationContext de WCF
HttpContext de ASP.NET
CallContext para UnitTesting, WinForms, WPF etc.

5. Como alterativa, podemos realizar el registro de tipos de una forma ms desacoplada,
mediante configuracin XML. Analizar el siguiente XML:
(NOTA: El nombre de los tipos no coincide pues este XML procede de una versin antigua de
NLayerSampleApp).
<?xml version="1.0" encoding="utf-8" ?>
<unity>
<typeAliases>
<!-- Lifetime manager types -->
<typeAlias alias="singleton"
type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="perThread"
type="Microsoft.Practices.Unity.PerThreadLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="external"
type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,
Microsoft.Practices.Unity" />
<typeAlias alias="perCall"
type="Microsoft.Practices.Unity.TransientLifetimeManager,
Microsoft.Practices.Unity"/>
<!-- EF Context & Fake-->
<typeAlias alias="IMainModuleContext"
type="Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule.Context.IMainModuleContext,
Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule " />

<typeAlias alias="MainModuleContext"
type="Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule.Context.MainModuleContext,
Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule" />

<typeAlias alias="MainModuleFakeContext"
type="Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule.Mock.MainModuleFakeContext,
Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule.Mock" />

<!-- Repositories-->
...
...
Page | 7
<typeAlias alias="ICustomerRepository"
type="Microsoft.Samples.NLayerApp.Domain.MainModule.Contracts.ICustomerRepository,
Microsoft.Samples.NLayerApp.Domain.MainModule" />
<typeAlias alias="CustomerRepository"
type="Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule.Repositories.CustomerRepository,
Microsoft.Samples.NLayerApp.Infrastructure.Data.MainModule" />

...
...
<!--Domain Services-->

<typeAlias alias="IBankTransfersService"
type="Microsoft.Samples.NLayerApp.Domain.MainModule.Services.IBankTransfersService,
Microsoft.Samples.NLayerApp.Domain.MainModule" />
<typeAlias alias="BankTransfersService"
type="Microsoft.Samples.NLayerApp.Domain.MainModule.Services.BankTransfersService,
Microsoft.Samples.NLayerApp.Domain.MainModule" />
...
...
</typeAliases>

<!-- UNITY CONTAINERS -->
<containers>
<container name="RootContext">
<types>
<!-- MAPPING from Interfaces to Classes -->
<type type="ICustomerRepository" mapTo="CustomerRepository">
<lifetime type="perCall"/>
</type>
...
...
<type type="IBankTransfersService" mapTo="BankTransfersService">
<lifetime type="perCall"/>
</type>
...
...
</types>
</container>
<container name="RealAppContext">
<types>
<type type="IMainModuleContext" mapTo="MainModuleContext">
<lifetime type="perCall" />
</type>
</types>
</container>
<container name="FakeAppContext">
<types>
<type type="IMainModuleContext" mapTo="MainModuleFakeContext">
<lifetime type="perCall" />
</type>
</types>
</container>
</containers>
</unity>


Sin embargo, en tiempo de desarrollo puede ser ms farragoso, pues si nos confundimos en
la escritura de tipos dentro del XML, los errores los obtendremos en tiempo de ejecucin en
lugar de en tiempo de compilacin.
6. En nuestro caso (NLAYERAPP), para abstraernos de la implementacin especfica de UNITY,
estamos utilizando un Interfaz nuestro llamado IContainer. De esta forma, al estar
trabajando mediante abstracciones con el propio contenedor IoC, podramos llegar a
sustituir en el futuro a UNITY por otro contenedor IoC, de una forma ms sencilla.
Analizar el interfaz IContainer dentro del fichero IContainer.cs.
Page | 8


Page | 9
Paso 2 Haciendo uso de Jerarqua de Contenedores UNITY para cambio dinmico a uso de objetos
Fake.
1. Registro de tipos en jerarqua de varios contenedores: Para poder hacer mocking de forma
dinmica como vimos en los Labs anterioes cambiando simplemente una clave de
configuracin, en NLayerSampleApp hacemos uso de diferentes contenedores de Unity, con
la siguiente jerarqua:

Ver en el fichero IoCUnityContainers que en el contenedor RealAppContext tenemos
registrado los tipos del contexto real de Entity Framework y en el contenedor
FakeAppContext registramos los tipos que hacen mocking del contexto de EF. Lgicamente
en ambos contenedores, los interfaces son los mismos, pues cuando se pide un objeto para
un interfaz dado, dicho interfaz estar mapeado de forma diferente en cada uno de los dos
contenedores Unity:


Mismo Interfaz por el que se preguntar
Mismo Interfaz por el que se preguntar
Mapeo a clase de UoW de Entity Fraework
Mapeo a clase Fake de UoW
Page | 10

De esta forma, cuando la propiedad de configuracin AppSettings["defaultIoCContainer"]
es RealAppContext, haremos uso del contenedor RealAppContext aadiendo/solapando sus
tipos al de RootContainer. Y el mismo efecto cuando la propiedad es RealAppContext, pero
entonces solaparemos los tipos del contenedor FakeAppContainer .
Recordamos la propiedad de configuracin utilizada en el LAB 01:

2. La implementacin de los UoW y contextos de EF Fake, se analizarn en los Labs de la Capa
de Infraestructura de Persistencia y Acceso a datos.

OTRAS POSIBILIDADES DEL SISTEMA DINAMICO DE INYECCION DE DEPENDENCIAS
Hay que tener en cuenta que este sistema dinmico de instanciacin de unos u otros objetos como
implementacin de abstracciones (interfaces), puede ser til no solo para hacer mocking de Entity
Framework. Puede utilizarse para otros sistemas de mocking, por ejemplo de acceso o no a un sistema
backend o legacy (ERP, etc.) o bien a un fake que simule dicho acceso, etc. Las posibilidades estn ahora
abiertas a la imaginacin.





Page | 11

Ejercicio 2: Inyeccio n de Dependencias
con Unity en la Aplicacio n ejemplo de la
Arquitectura
La inyeccin de dependencias que hace uso NLayerSampleApp es mayoritariamente basada en
constructores, es decir, especificando las dependencias de los Servicios en los constructores.
Paso 1 Analizar el Servicio BankingManagementService de Application Layer.
1. Abrir el fichero BankingManagementService.cs del proyecto Application.MainModule:

public class BankingManagementService : IBankingManagementService
{
IBankTransferDomainService _bankTransferDomainService;
IBankAccountRepository _bankAccountRepository;

public BankingManagementService(IBankTransferDomainService bankTransferDomainService, IBankAccountRepos
itory bankAccountRepository)
{
...

_bankTransferDomainService = bankTransferDomainService;
_bankAccountRepository = bankAccountRepository;
}

public void PerformTransfer(string fromAccountNumber, string toAccountNumber, decimal amount)
{
//Process: 1 Start Transaction
// 2 Get Accounts objects from Repositories
// 3 Call PerformTransfer method in Domain Service
// 4 If no exceptions, save changes using repositories and Commit Transaction

//Create a transaction context for this operation
TransactionOptions txSettings = new TransactionOptions()
{
Timeout = TransactionManager.DefaultTimeout,
IsolationLevel = IsolationLevel.Serializable // review this option
};

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, txSettin
gs))
{
//Get Unit of Work
IUnitOfWork unitOfWork = _bankAccountRepository.UnitOfWork as IUnitOfWork;

//Create Queries' Specifications
BankAccountNumberSpecification originalAccountQuerySpec = new BankAccountNumberSpecificati
on(fromAccountNumber);
BankAccountNumberSpecification destinationAccountQuerySpec = new BankAccountNumberSpecific
ation(toAccountNumber);

//Query Repositories to get accounts
BankAccount originAccount = _bankAccountRepository.GetBySpec(originalAccountQuerySpec as I
Specification<BankAccount>)
Dependencias especificadas en Constructor, un Repositorio y un Servicio de Dominio
Page | 12
.SingleOrDefault();

BankAccount destinationAccount = _bankAccountRepository.GetBySpec(destinationAccountQueryS
pec as ISpecification<BankAccount>)
.SingleOrDefault();

if (originAccount == null || destinationAccount == null)
throw new InvalidOperationException(Resources.Messages.exception_InvalidAccountsForTra
nsfer);

////Start tracking STE entities (Self Tracking Entities)
originAccount.StartTrackingAll();
destinationAccount.StartTrackingAll();

//Excute Domain Logic for the Transfer (In Domain Service)
_bankTransferDomainService.PerformTransfer(originAccount, destinationAccount, amount);


//Save changes and commit operations.
//This opeation is problematic with concurrency.
//"balance" property in bankAccount is configured
//to FIXED in "WHERE concurrency checked predicates"

_bankAccountRepository.Modify(originAccount);
_bankAccountRepository.Modify(destinationAccount);

//Complete changes in this Unit of Work
unitOfWork.CommitAndRefreshChanges();

//Commit the transaction
scope.Complete();
}
}


2. Es importante destacar que, como se puede observar, no hemos hecho ningn new explcito de
clases de Ropositorios (como BankAccountRepository) o de Servicios. Es el contenedor de Unity el que
automticamente crear el objeto de BankAccountRepository y BankTransferDomainService
proporcionndolos como parmetro de entrada a nuestro constructor. Esa es precisamente la inyeccin
de dependencias en el constructor.

Paso 2 Inicio de resolucin de tipos y creacin de grafo de objetos.
En tiempo de ejecucin, el cdigo de instanciacin de BankingManagementService se realizs utilizando
el mtodo Resolve() del contenedor de Unity, el cual origina la instanciacin generada por el framework
de Unity de la clase BankAccountRepository dentro del mbito de la clase
BankingManagementService.
1. Abrir el fichero MainModuleService.BankingManagement.cs del proyecto WCF de Servicios
Distribuidos (DistributedServices.MainModule) desde donde se arranca la creacin de grafos de objetos
creados por Unity.
Este tipo de cdigo es el que implementaremos normalmente en la capa de primer nivel que consume
objetos de Capa de Aplicacin y del Dominio, es decir, normalmente en la capa de Servicios Distribuidos
(WCF) como este caso o incluso capa de presentacin web ejecutndose en el mismo servidor de
aplicaciones (ASP.NET):
Page | 13
public partial class MainModuleService //Parte de Servicio WCF
{
...
...
public void PerformBankTransfer(TransferInformation transferInformation)
{
try
{
IBankingManagementService bankingManagement = IoCFactory.Instance.CurrentCo
ntainer.Resolve<IBankingManagementService>();



bankingManagement.PerformTransfer(transferInformation.OriginAccountNumber,
transferInformation.DestinationAccountNumber, transferInformation.Amount);
}
catch()
...
}
}

Como se puede observar en el uso de Resolve<>(), en ningn momento hemos creado nosotros una
instancia de las clases de los tipos que dependemos (IBankTransferDomainService y
IBankAccountRepository) y por lo tanto nosotros no hemos pasado explcitamente dichos objetos al
constructor de nuestra clase BankingManagementService. Y sin embargo, cuando se instancie la clase
de servicio (BankingManagementService), automticamente se nos habr proporcionado en el
constructor las instancias de las dependencias (IBankTransferDomainService y
IBankAccountRepository). Eso lo habr hecho precisamente el contenedor de Unity al detectar la
dependencia. Esta es la inyeccin de dependencia y nos proporciona la flexibilidad de poder cambiar la
dependencia en tiempo de configuracin y/o ejecucin. Por ejemplo, si en el fichero XML de
configuracin hemos especificado que se creen objetos Mock (simulacin) en lugar de objetos reales de
acceso a datos (Repository), la instanciacin de las clases de implementacin sera diferente.

2. Observar las definiciones internas de interfaces y clases que se utilizan en el cdigo anterior, como la
definicin de la clase de Servicio de AppLayer BankingManagementService y el resto de dependencias en
su grafo.

Interfaz de Servicio de Application Layer, a resolver. A partir de aqu se crea el grafo de objetos
Page | 14

Ejercicio 3 (OPCIONAL): Inyeccio n de
Factoras (Injection-Factory)
La inyeccin de factoras es una caracterstica nueva en UNITY 2.0. En la versin actual de
NLayerSampleApp no lo estamos utilizando porque no lo hemos necesitado, pero puede ser algo muy
til cuando la creacin de un objeto debe ser realizada por una Factory que debe tener en cuenta
aspectos externos a dicho objeto y no nos es suficiente con apoyarnos solamente en el constructor.
As pues, InjectionFactory es un mecanismo que permite indicarle a Unity un mtodo (una
Func<IUnityContainer, object>, usualmente una lambda expresion) a usar cada vez que deba resolver un
objeto especificado. Como decamos antes, permite que Unity use nuestras propias factoras.
Si tenemos la siguiente factora para crear objetos del tipo IComplexService:
interface IComplexServiceFactory
{
IComplexService GetNewInstance();
}

class ComplexServiceFactory : IComplexServiceFactory
{
public IComplexService GetNewInstance()
{
IComplexService complexService = new ComplexService();
// Do required actions by our factory...
complexService.Initialize("dato 3", "dato 4", "dato 5");

return new complexService();
}
}


A la hora de hacer uso con UNITY para resolver el tipo y crear el grafo de objetos, primero tenemos que
realizar el siguiente registro:

//Register Complex-Service using a Factory
container.RegisterType<IComplexServiceFactory, ComplexServiceFactory>(new ContainerControlledLifetimeManager());
container.RegisterType<IComplexService>(new InjectionFactory(x => x.Resolve<IComplexServiceFactory>().GetNewInstance()));


Page | 15
En la ltima lnea le indicamos a Unity que cada vez que alguien haga un Resolve<IComplexService>
ejecute el delegate que le indicamos, en este caso que obtenga una IComplexServiceFactory y llame al
mtodo GetNewInstance().
El Resolve() se hara de forma normal, pues el uso de la factora es interno:

IComplexService complexService = IoCFactory.Instance.CurrentContainer.Resolve<IComplexService>();




NOTA AL MARGEN:
En el caso de necesitar parmetros de entrada en el constructor de nuestra clase a resolver, esto
tambin se puede realizar con UNITY 2.0, de forma similar a la siguiente:


IComplexService complexService = IoCFactory.Instance.CurrentContainer.Resolve<IComplexService>(
new ParameterOverride("param1", 3));




Page | 16


Ejercicio 4 (OPCIONAL): AOP e
intercepcio n de llamadas con UNITY
Uno de los usos fundamentales de AOP (Aspect Oriented Programming) consiste en eliminar
aparentemente cdigo explcito utilizado para implementar aspectos 'Cross-Cutting'. Estos aspectos
normalmente suelen ser cosas como Logging, Validaciones, Gestin de Excepciones, etc. Esto se realiza
extrayendo dichos aspectos a un punto central reutilizable por todas las capas, de forma que los
desarrolladores puedan aplicarlo de una forma ms transparente ( aplicando aspectos o 'marcas' en
forma de atributos). De esta forma, el desarrollador puede focalizar ms y de una forma mas clara en la
lgica del Dominio y de su aplicacin concreta.
Hay diferentes formas de inyectar estas acciones de una forma transparente. Es lo que en AOP se
denomina Aspect Waiver. Una forma puede ser generando cdigo (C# o incluso IL) en tiempo de
compilacin. Otra forma puede ser realizando intercepcin de llamadas entre objetos e inyectando
ejecucin de cdigo entre dichas intercepciones de llamadas.
El mecanismo de intercepcin captura la llamada realizada a un objeto (en tiempo de ejecucin) y
proporciona la implementacin completa de dicho objeto. Unity utiliza la clase 'Interceptor' para
especificar el mecanismo de intercepcin a utilizar y como ocurre la intercepcin. Por otro lado, utiliza la
clase InterceptionBehavior para describir qu hacer cuando un objeto se ha interceptado.
La intercepcin de Unity est diseada para ejecutar sus comportamientos sobre todo el objeto
completo y todos sus mtodos.
Los Interceptadores juegan un rol solo en tiempo de creacin del proxy (o tipo derivado). Una vez que el
proxy o tipo derivado se ha creado, el interceptador habr proporcionado todos los componentes
requeridos por el objeto interceptado y lo habr incorporado al procesamiento del proxy.

Page | 17


NOTA: Unity proporciona intercepcin de llamadas a nivel de instancia y de tipo. Adems esta
intercepcin de llamadas puede realizarse con objetos contenidos en el contenedor IoC de Unity o bien
haciendo uso del API 'standalone' de UNITY (static intercept class) sin estar haciendo uso del contenedor
DI/IoC de Unity.
En el caso de hacer uso de Intercepcin de llamadas cuando utilizamos el contenedor IoC de Unity,
deberemos seguir los siguientes pasos:
3. Aadir referencia al assembly de intercepcin en UNITY:

4. Despus de la creacin del contenedor a utilizar, deberemos extenderlo para que soporte la
intercepcin de llamadas. As por ejemplo, dentro del constructor de nuestro
IoCUnityContainer, extenderamos el cdigo de la siguiente forma:
//Add this using
using Microsoft.Practices.Unity.InterceptionExtension;
...
...
public IoCUnityContainer()
{
...
//Create root container
IUnityContainer rootContainer = new UnityContainer();
//Configure container to support Interception
rootContainer.AddNewExtension<Interception>();

...
}


Page | 18
5. Configurar al contenedor de forma que realice intercepcin cuando resuelva la clase donde
queremos realizar intercepcin de llamadas. En este caso, por ejemplo, para nuestra clase
del Servicio del dominio 'BankTransferDomainService'.
Para ello, debemos indicar el mecanismo de intercepcin a utilizar con el objeto Interceptor
y el comportamiento de intercepcin a utilizar con un objeto InterceptionBehavior. Modificar
nuestro cdigo, en el fichero IoCUnityContainer.cs (donde registramos los tipos y
especificamos los mapeos), de la siguiente forma:

//Register domain services mappings
//(CDLTLL) Extending with Calls Interception
container.RegisterType<IBankTransferDomainService, BankTransferDomainService>(
new TransientLifetimeManager(),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior(new AuditBehavior(new
TraceSource("interception-audit-source"))));


6. Lgicamente, para que este cdigo nos funcione, primero deberemos de haber definido
tanto en TraceSource "interception-audit" en el Web.config, como nuestra clase de custom
behavior que hemos llamado AuditBehavior.
7. En el Web.config aadiramos lo siguiente, para definir la fuente a utilizar:


<sources>
...
<source name="interception-audit-source" switchValue="All">
<listeners>
<add name="interception-audit-listener"/>
</listeners>
</source>

</sources>
...
...
<sharedListeners>
...
...
<add name="interception-audit-listener"
initializeData="interception-audit.log"
traceOutputOptions="DateTime"
type="System.Diagnostics.TextWriterTraceListener, System, Version=
2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</sharedListeners>



8. Y aadiramos la siguiente clase de Behavior al proyecto de UNITY (Puesto que un Behaviour
es exclusivamente para Intercepcin de llamadas en UNITY):
Page | 19

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace Microsoft.Samples.NLayerApp.Infrastructure.CrossCutting.IoC.Unity
{
class AuditBehavior : IInterceptionBehavior, IDisposable
{
private TraceSource source;

public AuditBehavior(TraceSource source)
{
if (source == null) throw new ArgumentNullException("source");
this.source = source;
}

public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}

public IMethodReturn Invoke(IMethodInvocation input, GetNextIntercept
ionBehaviorDelegate getNext)
{
this.source.TraceInformation(
"Invoking {0}",
input.MethodBase.ToString());

IMethodReturn methodReturn = getNext().Invoke(input, getNext);

if (methodReturn.Exception == null)
{
this.source.TraceInformation(
"Successfully finished {0}",
input.MethodBase.ToString());
}
else
{
this.source.TraceInformation(
"Finished {0} with exception {1}: {2}",
input.MethodBase.ToString(),
methodReturn.Exception.GetType().Name,
methodReturn.Exception.Message);
}

this.source.Flush();

return methodReturn;
}

public bool WillExecute
{
Page | 20
get { return true; }
}

public void Dispose()
{
this.source.Close();
}
}
}



8. Tambin podramos implementar todo este sistema de Intercepcin de llamadas mediante
XML, extendiendo el XML de configuracin de UNITY. Sin embargo, pasa lo mismo que
advertimos anteriormente. Si se comente un error tipogrfico, el error se detectar en
tiempo de ejecucin en lugar de en tiempo de compilacin, lo cual es mucho peor. En
versiones finalizadas de la aplicacin, si es una opcin viable.
9. Tambin se puede hacer uso de atributos e inyeccin de POLICIES para aspectos ms
avanzados de intercepcin de llamadas.
Por ejemplo, en el mtodo del Dominio de la clase , podramos aplicar un atributo
diciendo que para ese mtodo aplique la auditora, y queiens no tengan dicho atributo, no
apliquen la auditora (o la lgica que ms conveniente se vea). Por ejemplo:

public class BankTransferDomainService
: IBankTransferDomainService
{
[SetAuditSystem("interception-audit-source")]
public void PerformTransfer(BankAccount originAccount,
BankAccount destinationAccount,
decimal amount)
{

...
...


Este sistema de atributos y polticas no explicamos aqu como se implementara y lo dejamos
a la curiosidad del lector estudiando los siguientes enlaces de Atributos y Polticas de UNITY:
http://207.46.16.251/en-us/library/ff660860(PandP.20).aspx
http://207.46.16.248/en-us/library/ff660915(PandP.20).aspx
http://blog.samstephens.co.nz/2010-11-15/policy-injection-attributes-preempt-calls-
functioning-systems/


Page | 21


APENDICE 1: Unity vs. MEF
MEF (Microsoft Extensibility Framework) no es un Full IoC container, aun cuando utiliza
conceptos IoC. Es un rfamework orientado a dar extensibilidad.
MEF focaliza en extensibilidad de aplicaciones con descubrimiento de componentes y
composicin.
Unity si es un IoC container tradicional, es su principal propsito.
Hasta la fecha (Febrero 2011), el posicionamiento de ambas tecnologas es el anterior. Y la
recomendacin para realizar Inyeccin de Dependencias entre componentes de una Arquitectura N-
Layer es ms recomendable hacerlo con Unity que con MEF. Unity es ms potente que MEF en muchos
aspectos IoC MEF, y por el contrario, MEF est ms indicado para extensibilidad de aplicaciones
(especialmente en capa de presentacin) a realizar incluso por terceras partes que no son quienes han
creado la aplicacin.
En futuras versiones de MEF si es posible que vaya realizando un crecimiento y absorcin de
capacidades de Unity. Las capacidades de MEF sern mucho mayores en el futuro. Pero esto es un
futurible, la realidad actual es lo especificado en los anteriores puntos.

Blog Posts interesantes al respecto:
http://gorskib.wordpress.com/2010/12/04/is-mef-a-next-dependency-injection-container-%E2%80%93-
my-vote-no/
http://stackoverflow.com/questions/293051/is-mef-a-dependency-injection-framework

También podría gustarte