Hands-On Lab LAB 02 - Implementando desacoplamiento IoC DI con UNITY Objetivos El obj etivo etiv o de este Lab es anali analizar zar de forma práctica práctica los di ferentes puntos de desarrollo relacionados relacionados co con el desacoplamiento de componentes componentes mediante Inyecc In yección ión de Dependencias Dependencias con Microsoft UNITY. La mayoría de los siguientes si guientes LABs están relacionados con la implementac imple mentación ión de l a aplicación ejemplo NLAYERAPP ( http://microsoftnlayerapp.codeplex.com/ ).
Introducción a Unity Microsoft Patterns & Practices Practices ), es un El Application Block denominado Unity (impl ementa ementado do por Microsoft
contenedor de inye cción de dependencias dependencias extensible extensible y ligero lige ro (Unity no es un gran framework pesado). Soporta inyección en e l constructor, inyección de propi edades, edades, inyección en llamadas a métodos y contenedores anidad ani dados. os. Básicamente, Unity es un contenedor donde podemos registrar registrar tipos (clases, i nterfaces) nterfaces) y también tambié n mapeos entre dichos tipos (como ( como un mapeo mapeo de un interfaz interf az hacia hacia una clase) y además el contene dor de Unity puede i nstanciar bajo demanda los tipos concretos requeridos.
Page | 1
Unity está disponi ble como un download público público desde el site de Microsoft (es gratuito) y también e stá (Compo site Applications Framework), Framework), los cuales inclui do en la Enterprise Library 4.0/5.0 4.0/5.0 y en PRISM (Composite hacen uso extensivo exten sivo de Unity .
Para hacer uso de Unity , normalmente registramos registramos tipos y mapeos e n un contenedor de forma que especif icamos icamos las depende depe ndencias ncias entre interfaces, clases base base y tipos tipo s concretos de objetos. Podemos Po demos defi nir estos regi stros stros y mapeos directamente por código fuente o bien, como normalmente se hará en una apli cación real, mediante XML XML de ficheros de configuración. También se puede especificar inyección de objetos en e n nuestras propias clases haciendo uso de atributos que indican las propiedades y métodos que requieren requi eren inyecc i nyección ión de objetos dependientes, dependientes, así como los objetos obje tos especificados en los paráme tros del constructor de una clase, que se inyectan inye ctan automáticamente. automáticamente. Unity proporciona las sigui entes ventajas al desarrollo de aplicacione apl icaciones: s:
-
Soporta abstracción abstracción de requerimientos; esto permite a los l os desarrolladores el especificar especificar dependenc depende ncias ias en tie mpo mpo de ej ecución o en confi configuración guración y simplifica la gestión de aspectos horizontales ( crosscutting concerns ), como puede ser el realizar reali zar pruebas unitarias unitarias contra mocks y stubs, o contra contra los obj etos reales de la aplicación.
-
Proporciona una creación creación de obj etos simp lificad li ficada, a, especialmente especialmente con estructuras de objetos jerárquicos con dependenc depende ncias, ias, lo cual simplifica el código de la aplicación.
-
Aumenta la flex f lexibilidad ibilidad al al trasladar la configuración de los componentes al contenedor IoC.
Proporciona una capacidad capacidad de localiz l ocaliz ación de servicios; esto permite a los clie ntes el guardar o cachear cachear el contenedor. contene dor. Es por eje mplo especialmente especialmente útil en aplicaciones web ASP.NET donde los desarrolladores pueden persistir persistir el contenedor contene dor en la l a sesión o aplicación apl icación ASP.NET. ASP. NET.
Page | 2
Ejercicio 1: Registro de Tipos en contenedor de UNITY Como ejemplo de uso de l os métodos RegisterType y Resolve, a continuación reali zamos 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).
Como posibil idad adicional, en la versión final de aplicación, el registro de clases, interfaces y mapeos en el contenedor, se puede realizar de forma declarativa en el XML de los ficheros de configuración, quedando completamente desacoplado. Sin embargo, tal y como se muestra en las líneas de código anteriores, durante el desarrollo probamente es más cómodo realizarlo de forma ‘ Hard-coded ’, pues así los errores tipográfi cos se detectarán en tiempo de compilación en lugar de en tie mpo de ejecución (como pasa con el XML). Con respecto al código anterior, la línea que siempre estará en el código de la aplicación, sería la que instancia propiamente el obj eto resolviendo la clase que debe utilizarse mediante el contenedor, es decir, la llamada al método Resolve() (Independientemente de si se reali za el regi stro de tipos por XML o ‘Hard-Coded ’).
Page | 3
Paso 1 – Analizar el Registro de Tipos (Cl ases e Interfaces) en la aplicación NLAYERSAMPLEAPP.
1. Abrir el fichero ‘ IoCUnityContainer.cs ’ del proyecto Infrastructure.CrossCutting.IoC:
2. Desplegar la sección ‘Private Methods’ dentro de dicho fichero:
3. Analizar los distintos regi stros de tipos realizados en el método ‘ConfigureRootContainer(IUnityContainer container)’:
Page | 4
Interfaz por el que se ‘preguntará’
Clase de Implementación asociada
Tipo de ‘LifeTimeManager’
4. El LifeTimeManager es el tipo de instanciación de clase que se realizará. En la mayoría de los casos (Reposi torios, Servicios, etc.) y por defecto si no se le especifica el LifeTimeManager a Unity, la forma de instanciación normal será TransientLifetimeManager , es decir, un objeto único por cada ref erencia. Pero en algunos casos puede interesarnos otros tipos de instanciación como del estil o a ‘singleton’ , compartidos por contextos de ejecución, 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 reutili zación 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 comportamie nto ‘ singleton’ para
cada objeto creado. El contenedor si mantiene referencias a los objetos creados y se hace un dispose automático cuando se hace un dispose del contenedor. o
ExternallyControlledLifetimeManager : Este LifeTimeManager mantiene una referencia
débil a su i nstancia manejada. Es decir, implementa un comportamiento ‘singleton’ pero el contenedor no mantiene una referencia al objeto que de berá ser eli minado ( disposed ) cuando se salga del ámbito. o
PerThreadLifetimeManager: Reutiliza una única instancia de cada clase por thread que
accede al grafo de objetos de de pendencias creado por Unity.
Page | 5
o
HierarchicalifetimeManager (Nuevo en Unity 2.0) : Implementa un comportamiento singleton, pero los contene dores hijos no comparten instancias con los contenedores
padres. o
PerExecutionContextLifetimeManager (Custom de NLayerSampleApp): Este
LifeTimeManager es ‘custom’ creado en la aplicación ejemplo NLayerApp. Su comportamiento es parecido a ‘PerResolveLifetimeManager’, pero en lugar de ser compartidas las instancias entre el grafo de obje tos de de pendencias a partir del primer resolve(), cuando hacemos uso de ‘ PerExecutionContextLifetimeManager’, los objetos se comparten por todo el contex to de ejecución inicial, por eje mplo, para todas las operaciones de una petición WCF (a partir de un WebMethod) o a partir de una petición ASP.NET o incluso a partir de una ejecución de un método de Pruebas Unitarias. En concreto nos basamos en los si guientes contextos:
OperationContext de WCF
HttpContext de ASP.NET
CallContext para UnitTesting, WinForms, WPF etc.
5. Como alterativa, podemos realizar el regis tro de tipos de una forma más desacoplada, mediante configuración XML. Analizar el siguiente XML: (NOTA: El nombre de los tipos no coi ncide pues este XML procede de una versión antigua de NLayerSampleApp).
Sin embargo, en tie mpo de desarrollo puede ser más farragoso, pues si nos confundimos en la escritura de tipos dentro del XML, los errores los obtendremos en tiempo de ejecución en lugar de en tiempo de compilación. 6. En nuestro caso (NLAYERAPP), para abstraernos de la implementación específica de UNITY, estamos utili zando un Interfaz nuestro llamado ‘IContainer’. De esta forma, al estar trabajando mediante abstracciones con el propio contenedor IoC, podríamos lle gar a sustituir en el futuro a UNITY por otro contenedor IoC, de una forma más sencill a. Analizar el interfaz IContainer dentro del fichero IContainer.cs.
Page | 7
Page | 8
Paso 2 – Haciendo uso de Jerarquía de Contenedores UNITY para cambio dinámico a uso de objetos ‘Fake’.
1. Registro de tipos en jerarquía de varios contenedores : Para poder hacer mocking de forma dinámica como vimos en l os Labs anterioe s cambiando simplemente una clave de configuración, en NLayerSampleApp hacemos uso de diferentes contenedores de Unity, con la siguiente jerarquía:
Ver en el f ichero IoCUnityContainers que en el contenedor ‘Real AppContext’ tenemos registrado los tipos del contex to real de Entity Framework y en el contenedor ‘FakeAppContext’ registramos los tipos que h acen mocking del contexto de EF. Lógicamente en ambos contenedores, los interfaces son los mismos, pues cuando se pide un objeto para un interfaz dado, dicho interfaz estará mapeado de forma dife rente en cada uno de los dos contenedores Unity: Mismo Interfaz por el que se ‘preguntará’
Mapeo a clase d e UoW de Entity Fraework
Mapeo a clase Fake de UoW
Mismo Interfaz por el que se ‘preguntará’
Page | 9
De esta forma, cuando la propie dad de configuración AppSettings["defaultIoCContainer"] es ‘RealAppContext’, haremos uso del contenedor RealAppContext añadiendo/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 confi guración utilizada en el LAB 01:
2. La i mplementación de los UoW y contextos de EF ó Fake, se analizarán 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 dinámico de i nstanciación de unos u otros objetos como implementación 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 posibi lidades están ahora
abiertas a la imaginación.
Page | 10
Ejercicio 2: Inyeccio n de Dependencias con Unity en la Aplicacio n ejemplo de la Arquitectura La inyección 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 itory bankAccountRepository )
bankTransferDomainService, IBankAccountRepos
{ ...
Depe ndencias espe cificadas 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)
Page | 11
.SingleOrDefault(); BankAccount destinationAccount = _bankAccountRepository.GetBySpec(destinationAccountQueryS pec as ISpecification) .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 ningún ‘new’ explícito de clases de Ropositorios (como BankAccountRepository ) o de Servicios. Es el contenedor de Unity el que automáticamente creará el objeto de BankAccountRepository y BankTransferDomainService proporcionándolos como parámetro de entrada a nuestro constructor. Esa es precisamente la inyección de dependencias en el constructor.
Paso 2 – Inicio de resolución de tipos y creación de grafo de objetos.
En tiempo de ejecución, el código de instanciación de BankingManagementService se reali zás utilizando el método Resolve() del contenedor de Unity, el cual origina la instanciación generada por el framework de Unity de la clase BankAccountRepository dentro del ámbito de l a clase BankingManagementService . 1. Abrir el fichero MainModuleService.BankingManagement.cs del proyecto WCF de Servicios
Distribuidos ( DistributedServices.MainModule) desde donde se arranca la creación de grafos de objetos creados por Unity. Este tipo de código es el que i mplementaremos normalmente en la capa de primer nivel que consume objetos de Capa de Aplicación y del Dominio, es decir, normalmente en la capa de Servicios Distribuidos (WCF) como este caso o incluso capa de presentación web ejecutándose en el mi smo servidor de aplicaciones ( ASP.NET): Page | 12
//Parte de Servicio WCF public partial class MainModuleService { ... ... 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 obje tos
Como se puede obse rvar en el uso de Resolve<>(), en ningún 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 expl ícitamente dichos objetos al constructor de nuestra clase BankingManagementService . Y sin embargo, cuando se instancie l a clase de servicio ( BankingManagementService ), automáticamente se nos habrá proporcionado en el constructor las instancias de las dependencias ( IBankTransferDomainService y IBankAccountRepository). Eso lo habrá hecho precisamente e l contenedor de Unity al detectar la
dependencia. Esta es la inyección de depe ndencia y nos proporciona la flexi bilidad de poder cambiar la dependencia en tiempo de configuración y/o ej ecución. Por ejemplo, si en el fiche ro XML de configuración hemos especificado que se creen objetos Mock (simulación) en lugar de objetos reales de acceso a datos (Re pository), la instanciación de las clases de i mplementación sería diferente.
2. Observar las defini ciones internas de interfaces y clases que se utilizan en el código anterior, como la
definición de la clase de Servicio de AppLayer ‘ BankingManagementService’ y el resto de dependencias en su grafo.
Page | 13
Ejercicio 3 (OPCIONAL): Inyeccio n de Factorías (Injection -Factory) La inyección de factorías es una característica nueva en UNITY 2.0. En la versión actual de NLayerSampleApp no lo estamos utilizando porque no lo he mos necesitado, pero puede ser algo muy útil cuando la creación de un o bjeto 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 pe rmite indicarle a Unity un método ( una Func, usualmente una lambda expresion) a usar cada vez que de ba resolver un objeto especificado. Como decíamos antes, permite que Unity use nuestras propias f actorías. Si tenemos la siguiente factoría para crear objetos de l tipo IComplexService:
interface IComplexServiceFactory { IComplexService GetNewInstance(); } class ComplexServiceFactory : IComplexServiceFactory { public IComplexService GetNewInstance() { IComplexService complexService = new ComplexService(); // Do r equired 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 obj etos, primero tenemos que realizar el sigui ente registro: //Register Complex-Service using a Factory container.RegisterType( new ContainerControlledLifetimeManager ()); container.RegisterType(n ew InjectionFactory(x => x.Resolve().GetNewInstance()));
Page | 14
En la última línea le indicamos a Unity que cada vez que alguien haga un Resol ve ejecute el delegate que le i ndicamos, en este caso que obtenga una IComplexServiceFactory y llame al método GetNewInstance(). El Resol ve() se haría de forma normal, pues el uso de la factoría es interno: IComplexService complexService = IoCFactory.Instance.CurrentContainer.Resolve< IComplexService >();
NOTA AL MARGEN:
En el caso de necesitar parámetros de entrada en el constructor de nuestra clase a resolver , esto también se puede realizar con UNITY 2.0, de forma simil ar a la siguiente:
IComplexService complexService = IoCFactory.Instance.CurrentContainer.Resolve< IComplexService >( new ParameterOverride("param1", 3) );
Page | 15
Ejercicio 4 (OPCIONAL): AOP e intercepcio n de llamadas con UNITY Uno de l os usos fundamentales de AOP ( Aspect Oriented Programming) consiste en el iminar ‘aparentemente’ código explícito utilizado para implementar aspectos 'Cross-Cutting '. Estos aspectos normalmente suelen ser cosas como Logging, Vali daciones, Gestión de Excepciones, etc. Esto se realiza extrayendo di chos aspectos a un punto central reutilizable por todas las capas, de forma que los desarrolladores puedan aplicarlo de una f orma más transparente ( aplicando aspectos o 'marcas' en forma de atributos). De esta forma, el desarrollador puede focalizar más y de una forma mas clara en la lógica del Dominio y de su apli cación 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 código (C# o incluso IL) en ti empo de compilación. Otra forma puede ser realizando intercepción de llamadas entre objetos e inyectando ejecución de código entre dichas inte rcepciones de llamadas. El mecanismo de intercepción captura la llamada realizada a un objeto (e n tiempo de ejecución) y proporciona la imple mentación completa de dicho obje to. Unity utiliza la clase 'Interceptor' para especif icar el mecanismo de i ntercepción a utilizar y como ocurre la intercepción. Por otro lado, utili za la clase InterceptionBehavior para describir qué hacer cuando un objeto se ha i nterceptado. La intercepción de Unity está diseñada para ejecutar sus comportamientos sobre todo el objeto completo y todos sus métodos. Los Interceptadores juegan un rol solo en tiempo de creación 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 intercepción de ll amadas a nivel de instancia y de tipo. Además esta
intercepción de llamadas puede realizarse con objetos contenidos en el contenedor IoC de Unity o bien haciendo uso del A PI 'standalone' de UNITY (static intercept class) sin estar haciendo uso del contenedor DI/IoC de Unity. En el caso de hacer uso de Intercepción de llamadas cuando utilizamos el contenedor IoC de Unity, deberemos seguir los siguientes pasos: 3. Añadir referencia al assembly de i ntercepción en UNITY:
4. Después de la creación del contenedor a utili zar, deberemos extenderlo para que soporte la intercepción de l lamadas. Así por ejemplo, dentro del constructor de nuestro IoCUnityContainer, extenderíamos el código 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 reali ce intercepción cuando resuelva la clase donde queremos realizar intercepción de llamadas. En este caso, por ejemplo, para nuestra clase del Servicio del dominio ' BankTransferDomainService '. Para ello, debemos indicar el mecanismo de intercepción a utilizar con el objeto Interceptor y el comportamiento de intercepción a utilizar con un objeto InterceptionBehavior . Modificar nuestro código, en el fichero ‘IoCUnityContainer.cs’ (donde registramos los tipos y especif icamos los mapeos), de la siguiente forma: //Register domain services mappings //(CDLTLL) Extending with Calls Interception container.RegisterType< IBankTransferDomainService , BankTransferDomainService >( new TransientLifetimeManager(), new Interceptor(), new InterceptionBehavior(new AuditBehavior(new TraceSource("interception-audit-source"))) );
6. Lógicamente, para que este código nos funcione, primero deberemos de haber def inido tanto en TraceSource "interception-audit" en el Web.config, como nuestra clase de ‘ custom behavior ’ que hemos ll amado ‘ AuditBehavior’.
7. En el Web.config añadiríamos lo siguiente, para definir la fuente a utili zar:
...
... ...
... ...
8. Y añadiríamos la si guiente clase de Behavior al proyecto de UNITY (Puesto que un Behaviour es ex clusivamente para Intercepción de llamadas en UNITY):
get { return true; } } public void Dispose() { this.source.Close(); } } }
8. También podríamos implementar todo este si stema de Intercepción de llamadas mediante XML, extendiendo el XML de configuración de UNITY. Sin embargo, pasa lo mismo que advertimos anteriormente. Si se comente un error tipográfico, el error se detectará en tiempo de ejecución en l ugar de en tiempo de compil ación, lo cual es mucho peor. En versiones finalizadas de la aplicación, si es una opción viabl e. 9. También se puede hacer uso de atributos e i nyección de POLICIES para aspectos más avanzados de intercepción de llamadas. Por ejemplo, en el método del Dominio ‘’ de la clase ‘’, podríamos aplicar un atributo diciendo que para ese método apli que la auditoría, y queiens no teng an dicho atributo, no apliquen la auditoría (o la lógica que más 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 políticas no explicamos aquí como se implementaría y lo dejamos a la curiosidad del lector estudiando los siguientes enlaces de Atributos y Pol íticas 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 ‘composición’.
Unity si es un ‘IoC container’ tradicional, es su principal propósito.
Hasta la fecha (Febrero 2011), el posicionamiento de ambas tecnologías es el anterior . Y la recomendación para realizar Inyección de Dependencias entre componentes de una Arquitectura N Layer es más recomendable hacerlo con Unity que con MEF. Unity es más potente que MEF en muchos aspectos IoC MEF, y por el contrario, MEF está más indicado para extensibilidad de aplicaciones (especialmente en capa de presentación) a realizar incluso por terceras partes que no son qui enes han creado la aplicación. En futuras versiones de MEF si es posible que vaya realizando un crecimiento y ‘absorción’ de capacidades de Unity. Las capacidades de MEF serán mucho mayores en el f uturo. Pero esto es un futurible, la realidad actual es lo especi ficado en los anteriores puntos.