Integración de Sistemas
Transcripción
Integración de Sistemas
Integración de Sistemas Unity Integración de Sistemas Parte II. Diseño e implementación de aplicaciones Web con .NET Unity Dependencias a alto nivel Interfaz de Usuario Depende de Capa lógica / Capa de Negocio Depende de Capa de Acceso a Datos Depende de Database Curso 2008 - 2009 1 Integración de Sistemas Unity Ejemplo de dependencia public void RegisterUser(String loginName, String clearPassword, UserProfileDetailsVO userProfileDetailsVO) { <...> DbConnection connection = (DbConnection) new SQLConnection(); <...> IUserProfileDAO dao = (IUserProfileDAO) new UserProfileDAO(); String encryptedPassword = Crypto.crypt(clearPassword); UserProfileVO userProfileVO = new UserProfileVO(loginName, encryptedPassword, userProfileDetailsVO); dao.Create(connection, transaction, userProfileVO); <...> } Unity Problemas originados por las dependencias Código altamente acoplado Aislamiento de código se complica Mantenimiento complejo Curso 2008 - 2009 Se dificulta la realización de las pruebas Desconocimiento acerca de los efectos colaterales de la modificación de código. 2 Integración de Sistemas Unity Problemas originados por las dependencias: soluciones Solución 1: Delegar en factorías la generación de instancias que puedan derivar en dependencias public void RegisterUser(String loginName, String clearPassword, UserProfileDetailsVO userProfileDetailsVO) { <...> DbDconnection connection = dbProviderFactory.CreateConnection(); <...> IUserProfileDAO dao = UserProfileDAOFactory.GetDAO(); String encryptedPassword = Crypto.crypt(clearPassword); UserProfileVO userProfileVO = new UserProfileVO(loginName, encryptedPassword, userProfileDetailsVO); Leerá la de un fichero de configuración el nombre de la instancia correcta dao.Create(connection, transaction, userProfileVO); <...> } Unity Problemas originados por las dependencias: soluciones Solución 1: Delegar en factorías la generación de instancias que puedan derivar en dependencias Inconvenientes: o Permanece la dependencia con respecto a la propia factoría o o Curso 2008 - 2009 Además, el código es dependiente de la Interfaz proporcionada por la factoría Distribución código implica la distribución de la factoría o Externo a la lógica del negocio o Codificación de la factoría es específica a cada problema 3 Integración de Sistemas Unity Problemas originados por las dependencias: soluciones Solución 2: Inyección de Dependencias / Inversión de Control (IoC) Principio Hollywoold Don`t call us, we’ll call you No nos llame, nosotros le llamaremos Los propios objetos conocen los recursos de los que deben hacer uso para su correcto funcionamiento Delegan en el entorno para acceder a dichos recursos entorno = framework de inversión de control (IoC container) Unity Problemas originados por las dependencias: soluciones Solución 2: Inyección de Dependencias public void RegisterUser(String loginName, String clearPassword, UserProfileDetailsVO userProfileDetailsVO) { <...> IUserProfileDAO dao = container.Resolve(<IUserProfileDAO>); <...> } Leerá la de un fichero de configuración (o se indicará al container por código) el mapeado de clases correcto Curso 2008 - 2009 4 Integración de Sistemas Unity Problemas originados por las dependencias: soluciones public interface IUserService { [Dependency] IUserProfileDao UserProfileDAO { set; } <...> } public class TestUserProfile { public static void Main(string[] args) { <...> IUserService userService = container.Resolve<IUserService>(); /* * The dao used within the UserService object is * created by means of IoC, so it is not necessary to resolve it * * userService.dao = container.Resolve<IUserProfileDao>(); */ <...> } } Unity Instanciación y configuración del Contedor Contenedor almacenará las referencias a las clases o instancias que posteriormente se inyectarán Permitirá configurar la inyección de cada dependencia Configuración posible directamente a través de código o bien a través t é d de xmll ¿Cuándo se crea el contenedor? Curso 2008 - 2009 Al inicio de la ejecución: global.asax 5 Integración de Sistemas Unity Instanciación y configuración del Contedor Configuración a través de código: registro de tipos #region Get DAO (Option 2): Configure DAO Injection by code. // Instanciación del contenedor IUnityContainer container = new UnityContainer(); // Registro de instancias container.RegisterType<IUserProfileDao, UserProfileDaoEntityFramework>(); container.RegisterType<IUserService, UserService>(); container.RegisterType<ObjectContext, ObjectContext> (new ContainerControlledLifetimeManager()); <...> #endregion Resolución de dependencias tratará ObjectContext como un singleton El registro de instancias se haría a través de: container.RegisterInstance<IGenericType>(concreteInstance) Unity Instanciación y configuración del Contedor Configuración a través fichero de configuración: registro de tipos <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> <...> <unity> <typeAliases> <!-- <typeAlias alias="aliasName" type="Class FullName, Assembly Name" /> --> <typeAlias alias="IUserProfileDAO” type="Es.Udc.DotNet.MiniPortal.Model.UserProfileDAL.IUserProfileDao, MiniPortal" /> <typeAlias alias="UserProfileDAOEntityFramework" type="Es.Udc.DotNet.MiniPortal.Model.UserProfileDAL.UserProfileDaoEntityFramework, MiniPortal" /> <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" /> </typeAliases> <containers> <container> <types><type type="IUserProfileDAO" mapTo="UserProfileDAOEntityFramework"></type> <…> </container> </containers> </unity> Curso 2008 - 2009 6 Integración de Sistemas Unity Instanciación y configuración del Contedor Configuración a través fichero de configuración: creación contenedor #region Get UserService (Option 3): Configure UserService Injection config file /* * We read the UnityConfigurationSection from the default * configuration file, Web.config, and then populate the * UnityContainer. */ IUnityContainer container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers.Default.Configure(container); <…> #endregion Unity ¿En qué consiste la inyección de dependencias? Curso 2008 - 2009 La inyección de dependencias consiste en la posibilidad de p proporcionar p ((inyectar) y ) una dependencia p externa en un componente software dado Tipos de Inyección de Dependencias comúnmente usados en Unity C Constructor t t Propiedad 7 Integración de Sistemas Unity Inyección de dependencias mediante constructor D Dependencia d i public class ObjectContext { private String connectionString; public String ConnectionString { get; private set; } public ObjectContext(String connectionString) { <...> } <...> } Parámetro, clase, etc. Se inyecta a través del constructor Unity Inyección de dependencias mediante constructor Configuración mediante código String connectionString = <...> // Data should be read from configuration file container.RegisterType<ObjetContexct, ObjectContext>( new ContainerControlledLifetimeManager()); // Optional: created as singleton container.Configure<InjectedMembers>() .ConfigureInjectionFor<ObjectContext>( new InjectionConstructor(connectionString)); Configuración mediante fichero de configuración <type type="ObjectContext" mapTo="ObjectContext"> <lifetime type="singleton" /> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="connectionString" parameterType="System.String"> <value value="<...>" /> </param> </constructor> </typeConfig> </type> Curso 2008 - 2009 8 Integración de Sistemas Unity Inyección de dependencias mediante propiedad namespace Es.Udc.DotNet.MiniPortal.Model.UserService { public interface IUserService { [Dependency] IUserProfileDao UserProfileDao { set; } <...> } } Dependencia se inyecta a través de una propiedad Unity Inyección de dependencias mediante constructor Configuración mediante código container.RegisterType<IUserProfileDao, UserProfileDaoEntityFramework>(); Configuración mediante fichero de configuración <types> <!-- ************ Mappings for Bussiness Objects ************* --> <!-- IUserProfileDAO --> <type type="IUserProfileDAO" mapTo="UserProfileDAOEntityFramework"> </type> <!-- IUserService --> <type type="IUserService" mapTo="UserService"> </type> </type> Curso 2008 - 2009 9 Integración de Sistemas Unity Unity ofrece framework de inversión de control Inyección de Dependencias Ofrece soporte a otros puntos de la Programación Orientada a Aspectos Intercepción Permite interceptar la llamada a un método, analizar los contenidos de dicha llamada y o bien continuar con la misma sin modificación o bien modificar su comportamiento. Intercepción útil para la gestión de transacciones Unity Transacciones Estructura típica de un método transaccional (ver DotNet-Examples-src-1.5) void RegisterUser(String g ( g loginName, g , String g clearPassword, , UserProfileDetailsVO userProfileDetailsVO) ) { <...> try { /* Creates the connection. */ <...> /* Starts a new transaction. */ DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable); <...> } catch (...) { <...> } finally { if (rollback) transaction.Rollback(); else transaction.Commit(); } Código idéntico en todos los casos de uso transaccionales <...> } Curso 2008 - 2009 10 Integración de Sistemas Unity Transacciones Soluciones para no repetir código C Casos d de uso iimplementados l d a partir i d de un P Procesador d d de A Acciones i (DotNet-Examples-src-1.5) Acciones Transaccionales Acciones no Transaccionales Procesador Acciones crearía entorno transaccional y ejecutaría la acción Procesador Acciones ejecutaría directamente la acción Intercepción de métodos transaccionales Etiquetado métodos con atributo [Transactional] Unity Transacciones Creación atributo namespace Es.Udc.DotNet.ModelUtil.Transactions { public class TransactionalAttribute : HandlerAttribute { public override ICallHandler CreateHandler( IUnityContainer container) { return new TransactionalHandler(); } } } Uso: [Transactional] LoginResult Login(String loginName, String password, Boolean passwordIsEncrypted); Curso 2008 - 2009 11 Integración de Sistemas Unity Transacciones Creación interceptor (handler) public class TransactionalHandler : ICallHandler { public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { IMethodReturn result; using (TransactionScope transaction = new TransactionScope()) { result = getNext()(input, getNext); Creación entorno transaccional transaction.Complete(); } return result; } } Llamada al método mediante delegado } Unity Transacciones Configuración para el uso de la intercepción en Unity <extensions> <add type="Microsoft.Practices.Unity.InterceptionExtension.Interception, Microsoft.Practices.Unity.Interception" /> </extensions> <!-- Interception schema for transactional methods --> <extensionConfig> <add name name="TransactionalIntercepcion" TransactionalIntercepcion type=“<...>"> <interceptors> <interceptor type="InterfaceInterceptor"> <key type="IUserService" /> </interceptor> </interceptors> </add> Interfaz que será </extensionConfig> Curso 2008 - 2009 interceptada 12 Integración de Sistemas Unity Transacciones Configuración para el uso de la intercepción en Unity container.RegisterType<IUserService, UserService>(); container.AddNewExtension<Interception>(); container.Configure<Interception>(). SetDefaultInterceptorFor<IUserService>( new InterfaceInterceptor()); Curso 2008 - 2009 13