Está en la página 1de 21

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 | 1

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 | 2

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 | 3

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 | 4

Interfaz por el que se preguntar

Clase de Implementacin asociada

Tipo de LifeTimeManager

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 o TransientLifetimeManager: Este LifeTimeManager asegura que las instancias de objetos se crean nuevas cada vez (no reutilizacin de objetos entre diferentes llamadas). 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. 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. 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. PerThreadLifetimeManager: Reutiliza una nica instancia de cada clase por thread que accede al grafo de objetos de dependencias creado por Unity.

Page | 5

HierarchicalifetimeManager (Nuevo en Unity 2.0) : Implementa un comportamiento singleton, pero los contenedores hijos no comparten instancias con los contenedores padres. 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 de pendencias 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 versi on="1.0 " encodi ng="utf -8" ?> <unity> <typeAlia ses> <!-- Li fetime manager types - -> <typeAl ias ali as="sing leton" ty pe="Mic rosoft.P ractice s.Unity. Contain erContr olledLif etimeMa nager, Mic rosoft.P ractice s.Unity" /> <typeAl ias ali as="perT hread" ty pe="Mic rosoft.P ractice s.Unity. PerThre adLifet imeManag er, Mic rosoft.P ractice s.Unity" /> <typeAl ias ali as="exte rnal" ty pe="Mic rosoft.P ractice s.Unity. Externa llyCont rolledLi fetimeM anager, Mic rosoft.P ractice s.Unity" /> <typeAl ias ali as="perC all" ty pe="Mic rosoft.P ractice s.Unity. Transie ntLifet imeManag er , Mic rosoft.P ractice s.Unity" /> <!-- EF Contex t & Fake --> <typeAl ias ali as="IMai nModule Context " type="M icrosof t.Sample s.NLaye rApp.Inf rastruc ture.Da ta.MainM odule.C ontext.I MainMod uleConte xt, Micros oft.Samp les.NLa yerApp.I nfrastr ucture. Data.Mai nModule " /> <typeAl ias ali as="Main ModuleC ontext" ty pe="Mic rosoft.S amples. NLayerAp p.Infra structu re.Data. MainMod ule.Cont ext.Mai nModuleC ontext, M icrosoft .Sample s.NLayer App.Inf rastruc ture.Dat a.MainM odule" / > <typeAl ias ali as="Main ModuleF akeConte xt " ty pe="Mic rosoft.S amples. NLayerAp p.Infra structu re.Data. MainMod ule.Mock .MainMo duleFake Context , Mi crosoft .Samples .NLayer App.Infr astruct ure.Dat a.MainMo dule.Mo ck" /> <!-- Re positor ies--> ... ...

Page | 6

<typeAl ias ali as="ICus tomerRe pository " ty pe="Mic rosoft.S amples. NLayerAp p.Domai n.MainM odule.Co ntracts .ICustom erRepos itory, Mi crosoft .Samples .NLayer App.Doma in.Main Module" /> <typeAl ias ali as="Cust omerRep ository " ty pe="Mic rosoft.S amples. NLayerAp p.Infra structu re.Data. MainMod ule.Repo sitorie s.Custom erRepos itory, Mi crosoft .Samples .NLayer App.Infr astruct ure.Dat a.MainMo dule" / > ... ... <!--Dom ain Ser vices--> <typeAl ias ali as="IBan kTransf ersServi ce " type= "Micros oft.Samp les.NLa yerApp.D omain.M ainModu le.Servi ces.IBa nkTransf ersServ ice, Mi crosoft .Samples .NLayer App.Doma in.Main Module" /> <typeAl ias ali as="Bank Transfe rsServic e " typ e="Micr osoft.Sa mples.N LayerApp .Domain .MainMo dule.Ser vices.B ankTrans fersSer vice, Mi crosoft .Samples .NLayer App.Doma in.Main Module" /> ... ... </typeAli ases> <!-- UNIT Y CONTA INERS -- > <containe rs> <contai ner nam e="RootC ontext" > <type s> <!- - MAPPI NG from Interfa ces to C lasses --> <ty pe type ="ICusto merRepo sitory" mapTo=" Custome rReposit ory "> < lifetim e type=" perCall "/> </t ype> ... ... <ty pe type ="IBankT ransfer sService " mapTo ="BankT ransfers Service "> < lifetim e type=" perCall "/> </t ype> ... ... </typ es> </conta iner> <contai ner nam e="RealA ppConte xt"> <type s> <ty pe type ="IMainM oduleCo ntext" m apTo="M ainModu leContex t"> < lifetim e type=" perCall " /> </t ype> </typ es> </conta iner> <contai ner nam e="FakeA ppConte xt"> <type s> <ty pe type ="IMainM oduleCo ntext" m apTo="M ainModu leFakeCo ntext "> < lifetim e type=" perCall " /> </t ype> </typ es> </conta iner> </contain ers> </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 | 7

Page | 8

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 h acen 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 Mapeo a clase de UoW de Entity Fraework

Mapeo a clase Fake de UoW

Mismo Interfaz por el que se preguntar

Page | 9

De esta forma, cuando la propiedad de configuracin AppSettings["defaultIoCContainer"] es RealAppContext, haremos uso del contenedor RealAppContext aadiendo/sola pando 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 | 10

Ejercicio 2: Inyeccion de Dependencias con Unity en la Aplicacion 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) { Dependencias especificadas en Constructor, un Repositorio y un Servicio de Dominio ... _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>)

Page | 11

.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 | 12

public partial class MainModuleService //Parte de Servicio WCF { ... ... public void PerformBankTransfer (TransferInformation transferInformation) { try { IBankingManagementService bankingManagement = IoCFactory.Instance.CurrentCo ntainer.Resolve<IBankingManagementService>();
Interfaz de Servicio de Application Layer, a resolver. A partir de aqu se crea el grafo de objetos

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.

Page | 13

Ejercicio 3 (OPCIONAL): Inyeccion 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 Factor y container.R egister Type<ICo mplexSe rviceFac tory, C omplexS erviceFa ctory>( new Cont ainerCo ntrolled Lifetim eManager ()); container.R egister Type<ICo mplexSe rvice>(n ew Inje ctionFa ctory(x => x.Re solve<IC omplexS erviceFa ctory>( ).GetNew Instanc e()));

Page | 14

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 | 15

Ejercicio 4 (OPCIONAL): AOP e intercepcion 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 | 16

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 | 17

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, e n 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 | 18

using using using using

System; System.Collections.Generic; System.Diagnostics; 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 | 19

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-callsfunctioning-systems/

Page | 20

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%93my-vote-no/ http://stackoverflow.com/questions/293051/is-mef-a-dependency-injection-framework

Page | 21

También podría gustarte