03.2.- MiniPortal - MiniBank - UDC

49
1 MiniPortal Integración de Sistemas Integración de Sistemas Diseño e implementación con .NET MiniPortal Implementación en .NET de la aplicación con el mismo nombre, vista en la primera parte de la asignatura Casos de uso Registrar usuario Autenticarse Recuperar información de registro Actualizar información de registro Cambiar contraseña

Transcript of 03.2.- MiniPortal - MiniBank - UDC

Page 1: 03.2.- MiniPortal - MiniBank - UDC

1

MiniPortal

Integración de SistemasIntegración de SistemasDiseño e implementación con .NET

MiniPortal

Implementación en .NET de la aplicación con el mismo nombre, vista en la primera parte de la asignatura

Casos de uso

Registrar usuario

Autenticarse

Recuperar información de registro

Actualizar información de registro

Cambiar contraseña

Page 2: 03.2.- MiniPortal - MiniBank - UDC

2

Estructura de paquetes del modelo

Es.UDC.DotNet.MiniPortal.Model

UserProfile

UserFacade

Exceptions

VO

Delegate

VO

DAO

Es.UDC.DotNet.MiniPortal.Model.UserProfile.VO

+FirstName : String+Surname : String+Email : String

UserProfileDetailsVO

+LoginName : String+EncryptedPassword : String

UserProfileVO

Ambas clases parametrizadas con el atributo [Serializable()]

+UserProfileDetailsVO()+ToString() : String

g+Language : String+Country : String+UserProfileVO()

+ToString()

yp g+UserProfileDetailsVO : UserProfileDetailsVO

1

Page 3: 03.2.- MiniPortal - MiniBank - UDC

3

Patrón Value Object

Representa estado/valor

El estado se almacena en PropiedadesEl estado se almacena en PropiedadesIncluyen métodos get y set implícitos

Sobrescribiremos (override) el método ToString()para imprimir el estado

VOs deben ser objetos serializablesS i di l t ib t [S i li bl ()] di d lSe indica con el atributo [Serializable()] precediendo a la declaración de la clase

Usaremos la notación xxxVO

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO

Page 4: 03.2.- MiniPortal - MiniBank - UDC

4

Patrón Data Access Object

Oculta cómo se hace el acceso a la BD

Sus métodos necesitan recibirSus métodos necesitan recibirLa conexión (DbConnection)

Para crear los comandos a partir de ella

command = connection.CreateCommand()

La transacción (DbTransaction)Si hay una transacción iniciada los comandos deben añadirse aSi hay una transacción iniciada, los comandos deben añadirse a ella (obligatoriamente)

/* If transaction exists, command will be added */if (transaction != null) {

command.Transaction = transaction;}

Patrón Data Access Object

IUserProfileDAO (Adapter)

Define una interfaz para insertar, borrar, actualizar y encontrar p , , yUserProfileVOs

Permite implementar adaptadores para distintas BD (dialectos de SQL)

UserProfileDAOFactory (Factory)

Permite obtener una instancia de un adaptador apropiado para la aplicaciónp

Page 5: 03.2.- MiniPortal - MiniBank - UDC

5

Patrón Data Access Object

IUserProfileDAO + UserProfileDAOFactoryEs posible hacer plug-n-play (sin recompilar) de adaptadoresEs posible hacer plug-n-play (sin recompilar) de adaptadores cuando se cambia de BD

Facilita la instalación/configuración de la aplicación

Usaremos la notación xxxDAOEl prefijo SQL en el entorno .NET se usa para hacer referencia a SQL Server, no para referirse a SQL estándarPara evitar confusiones, no utilizaremos el prefijo SQL (siempre , p j Q ( ptrabajaremos con SQL estándar) y utilizaremos SQLServer para referirnos a la BD de Microsoft

Carga Dinámica de Clases

Implementación de Factorías

Clases que se desean instanciar puedenPertenecer al assembly activo

Estar situadas en un assembly independiente (fichero .dll)

Namespaces

System.Reflection

System.Runtime.Remoting

Page 6: 03.2.- MiniPortal - MiniBank - UDC

6

Carga Dinámica de ClaseClase pertenece al assembly activo

// Nombre completo de la clase que se desea instanciarString daoClassName =

"Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.SQLServerUserProfileDAO";

// Recuperamos el assembly actualmente en ejecucionAssembly assembly = Assembly.GetExecutingAssembly();

// Creamos instancia del tipo especificado// Parametros: // * nombre del assembly en el que se define el tipo// * tipo que deseamos instanciarObject theObject = AppDomain CurrentDomainObject theObject = AppDomain.CurrentDomain.

CreateInstanceAndUnwrap(assembly.FullName, daoClassName);

return (IUserProfileDAO)theObject;

Carga Dinámica de ClaseClase pertenece al assembly independiente

// Nombre completo de la clase que se desea instanciarString className = "MySql.Data.MySqlClient.MySqlConnection";

// Nombre de la libreria en la que esta definida la claseString driverFile =

"c:\\MySQL Connector Net 1.0.9\\Binaries\\.NET 1.1\\MySql.Data.dll";

// Cargamos el assembly a partir de su nombreAssembly assembly = Assembly.LoadFrom(driverFile);

// Creamos instancia tipo especificado// Parametros: // * nombre del assembly en el que se define el tipo// nombre del assembly en el que se define el tipo// * tipo que deseamos instanciarObject obj = AppDomain.CurrentDomain.

CreateInstanceAndUnwrap(assembly.FullName, className);

return (DbConnection) obj;

Page 7: 03.2.- MiniPortal - MiniBank - UDC

7

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.UserProfileDAOFactory

public sealed class UserProfileDAOFactory{

/// <summary>/// Initializes a new instance of the /// <see cref="UserProfileDAOFactory"/> class./// </summary>/// <remarks>Class constructor must be private, so nobody will be /// allowed to instantiate it </remarks>private UserProfileDAOFactory() { }

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.UserProfileDAOFactory

/// <exception cref="ConfigurationParameterException"/> /// <exception cref="InternalErrorException"/> public static IUserProfileDAO GetDAO() {

try {

String daoClassName =Settings.Default.UserProfileDAOFactory_daoClassName;

Assembly assembly = Assembly.GetExecutingAssembly();

Object theObject = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assembly FullName daoClassName);CreateInstanceAndUnwrap(assembly.FullName, daoClassName);

return (IUserProfileDAO)theObject;

} catch (Exception e) {

throw new InternalErrorException(e);}

}}

Page 8: 03.2.- MiniPortal - MiniBank - UDC

8

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.UserProfileDAOFactory

Ejemplo de uso

DbProviderFactory dbFactory = DbProviderFactories.GetFactory(providerInvariantName);

/* Create and open the connection */connection = dbFactory.CreateConnection();connection.ConnectionString = connectionString;connection.Open();

/* Get DAO */IUserProfileDAO dao = UserProfileDAOFactory.GetDAO();

/* Test DAO.Exists */Boolean userExist = dao.Exists(connection, transaction,

userProfileVO.LoginName);

Es.UDC.DotNet.Util

Es.UDC.DotNetEs.UDC.DotNet

Crypto

MiniPortal

Util

Exceptions

Log

Page 9: 03.2.- MiniPortal - MiniBank - UDC

9

Es.UDC.DotNet.Util.Exceptions

Es.UDC.DotNet.Util.Exceptions

InternalErrorException

Error grave durante la ejecución de un métodog jCaída de la BD, carga errónea de clases, etc.

Oculta el API empleada en la implementación

Encapsula la excepción real que se ha producidoÚtil para depuración

ModelException

Errores Lógicos en el modelo

Page 10: 03.2.- MiniPortal - MiniBank - UDC

10

Es.UDC.DotNet.Util.Exceptionsusing System;

namespace Es.UDC.DotNet.Util.Exceptions{

public class InternalErrorException : Exception{

private Exception encapsulatedException = null;

public InternalErrorException(Exception exception) {

encapsulatedException = exception;}}

public InternalErrorException(String msg) : base(msg) { }

Es.UDC.DotNet.Util.Exceptionspublic override String Message{

get{

if (encapsulatedException == null)return this.Message;

elseencapsulatedException.Message;

}}

public Exception EncapsulatedException{

get{{

return encapsulatedException; }

}}

}

Page 11: 03.2.- MiniPortal - MiniBank - UDC

11

Es.UDC.DotNet.Util.Exceptionsusing System;

namespace Es.UDC.DotNet.Util.Exceptions {

public class InstanceException : ModelException {

private Object key;private String className;

protected InstanceException(String specificMessage, Object key, String className): base(specificMessage + " (key = '" + key +: base(specificMessage + (key = + key +

"' - className = '" + className + "')") {

this.key = key;this.className = className;

}

Es.UDC.DotNet.Util.Exceptions

#region Properties

public Object Key {

get { return key; }}

public String ClassName {

get { return className; }}

#endregion

}

}

Page 12: 03.2.- MiniPortal - MiniBank - UDC

12

Es.UDC.DotNet.Util.LogProporciona log de mensajes a pantalla y/o fichero

Contenido:LogManager.cs

App.config: parámetros de configuraciónLogDestination: destino de los mensajes (SCREEN / FILE / ALL)SeverityLevel: tipo de mensajes de los que se hará log (INFO / WARNING / ERROR)FileLocation: ruta al fichero de logFilePartialName y FileExtension: nombre del fichero de log con la sintaxis:

{FilePartialName}_DATE.{FileExtension}

Ejemplo de uso:

LogManager.RecordMessage("Example Message", LogManager.MessageType.INFO, this);

Resultado:

[13/11/2006 17:26:56] Es.UDC.DotNet.MiniPortal.Model.UserProfile.VO: INFO: Example Message

Sustituto de Console.WriteLine("…")

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

Page 13: 03.2.- MiniPortal - MiniBank - UDC

13

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

AbstractUserProfileDAO

Implementación de IUserProfileDAO independiente del DataImplementación de IUserProfileDAO independiente del Data Provider

Deja sin implementar los métodos: String GetParameterSyntax(String parameterName)

String GetParameterName(String parameterName)

SQLServerUserProfileDAO, l fil filOracleUserProfileDAO, MySQLUserProfileDAO,

etc.Implementaciones para un Data Provider específico

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

public abstract class AbstractUserProfileDAO : IUserProfileDAO{

#region IUserProfileDAO Members

/// <summary>/// Create a new <code>UserProfile</code>/// </summary>/// <exception cref="DuplicateInstanceException"/> /// <exception cref="InternalErrorException"/> public void Create(DbConnection connection, DbTransaction transaction,

UserProfileVO userProfileVO) {

/* Check if the user already exists *// Check if the user already exists. /if (Exists(connection, transaction, userProfileVO.LoginName)) {

throw new DuplicateInstanceException(userProfileVO.LoginName, typeof(UserProfileVO).FullName);

}

Page 14: 03.2.- MiniPortal - MiniBank - UDC

14

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

try {

/* Create the command. */DbCommand command = connection.CreateCommand();

/* If transaction exists, command will be added */if (transaction != null) {

command.Transaction = transaction;}

command.CommandText ="INSERT INTO UserProfile (loginName, enPassword, " +

"firstName surname email language country) " +firstName, surname, email, language, country) +"VALUES (" + GetParameterSyntax("loginName") +

", " + GetParameterSyntax("enPassword") +", " + GetParameterSyntax("firstname") +", " + GetParameterSyntax("surname") +", " + GetParameterSyntax("email") +", " + GetParameterSyntax("language") +", " + GetParameterSyntax("country") + ")";

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

DbParameter loginNameParam = command.CreateParameter();loginNameParam.ParameterName = GetParameterName("loginName");loginNameParam.DbType = DbType.String;loginNameParam.Size = 30;loginNameParam.Value = userProfileVO.LoginName;command.Parameters.Add(loginNameParam);

DbParameter encryptedPasswordParam = command.CreateParameter();<< ... >>

DbParameter firstNameParam = command.CreateParameter();<< ... >>

DbParameter surnameParam = command CreateParameter();DbParameter surnameParam = command.CreateParameter();<< ... >>

DbParameter emailParam = command.CreateParameter();<< ... >>

DbParameter languageParam = command.CreateParameter();<< ... >>

DbParameter countryParam = command.CreateParameter();<< ... >>

Page 15: 03.2.- MiniPortal - MiniBank - UDC

15

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

command.Prepare();

int insertedRows = command.ExecuteNonQuery();

if (insertedRows == 0) {

throw new SQLException("Can not add row to table" +" 'UserProfile'");

}

if (insertedRows > 1) {

throw new SQLException("Duplicate row for login name = '" +throw new SQLException( Duplicate row for login name = +userProfileVO.LoginName + "' in table 'UserProfile'");

}

} catch (SQLException e) {

throw new InternalErrorException(e);}

} // Create

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

/// <summary>/// Looks if an <code>UserProfile</code> with/// this <paramref name="loginName"/> exists/// </summary>/// <returns>True if the <code>UserProfile</code> exists</returns>/// <exception cref="InternalErrorException"/> public Boolean Exists(DbConnection connection,

DbTransaction transaction, String loginName) {

DbDataReader dataReader = null;

try {{

/* Create the command. */DbCommand command = connection.CreateCommand();

/* If transaction exists, command will be added */

command.CommandText ="SELECT loginName FROM UserProfile " +"WHERE loginName = " + GetParameterSyntax("loginName");

Page 16: 03.2.- MiniPortal - MiniBank - UDC

16

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

DbParameter loginNameParam = command.CreateParameter();loginNameParam.ParameterName = GetParameterName("loginName");loginNameParam.DbType = DbType.String;loginNameParam.Value = loginName;loginNameParam.Size = 30;command.Parameters.Add(loginNameParam);

command.Prepare();

dataReader = command.ExecuteReader();

return (dataReader.Read());

}} catch (SQLException e) {

throw new InternalErrorException(e);

} finally{

dataReader.Close();}

} // Exists

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

/// <exception cref="InstanceNotFoundException"/> /// <exception cref="InternalErrorException"/> public UserProfileVO Find(DbConnection connection,

DbTransaction transaction, String loginName) {

DbDataReader dataReader = null;

try{

/* Create the command. */DbCommand command = connection.CreateCommand();

/* If transaction exists, command will be added */

command.CommandText ="SELECT enPassword, firstName, surname, email, " +

"language, country " +"FROM UserProfile " +"WHERE loginName = " + GetParameterSyntax("loginName");

Page 17: 03.2.- MiniPortal - MiniBank - UDC

17

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

DbParameter loginNameParam = command.CreateParameter();loginNameParam.ParameterName = GetParameterName("loginName");loginNameParam.DbType = DbType.String;loginNameParam.Size = 30;loginNameParam.Value = loginName;command.Parameters.Add(loginNameParam);

command.Prepare();

dataReader = command.ExecuteReader();

if (!dataReader.Read()) {{

throw new InstanceNotFoundException(loginName,typeof(UserProfileVO).FullName);

}

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

String encryptedPassword = dataReader.GetString(0);String firstname = dataReader.GetString(1);<< ... >>

UserProfileDetailsVO userProfileDetailsVO =new UserProfileDetailsVO(firstname,

surname, email, country, language);

/* Return the value object. */return new UserProfileVO(loginName, encryptedPassword,

userProfileDetailsVO);

} catch (DbException e)catch (DbException e) {

throw new InternalErrorException(e);

} finally{

dataReader.Close();}

} // Find

Page 18: 03.2.- MiniPortal - MiniBank - UDC

18

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

/// <exception cref="InstanceNotFoundException"/> /// <exception cref="InternalErrorException"/> public void Update(DbConnection connection, DbTransaction transaction,

UserProfileVO userProfileVO) {

try {

/* Create the command. */

/* If transaction exists, command will be added */

command CommandText =command.CommandText ="UPDATE UserProfile " +"SET enPassword = " + GetParameterSyntax("enPassword") +

", firstName = " + GetParameterSyntax("firstname") +", surname = " + GetParameterSyntax("surname") +", email = " + GetParameterSyntax("email") +", language = " + GetParameterSyntax("language") +", country = " + GetParameterSyntax("country") +

" WHERE loginName = " + GetParameterSyntax("loginName");

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

DbParameter loginNameParam = command.CreateParameter();loginNameParam.ParameterName = GetParameterName("loginName");loginNameParam.DbType = DbType.String;loginNameParam.Size = 30;loginNameParam.Value = userProfileVO.LoginName;command.Parameters.Add(loginNameParam);

/* Crear el resto de parametros:* encryptedPasswordParam, firstNameParam, surnameParam,* emailParam, languageParam y countryParam*/

command.Prepare();

Page 19: 03.2.- MiniPortal - MiniBank - UDC

19

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

int updatedRows = command.ExecuteNonQuery();

if (updatedRows == 0) {

throw new InstanceNotFoundException(userProfileVO.LoginName, typeof(UserProfileVO).FullName);

}

if (updatedRows > 1) {

throw new SQLException("Duplicate row for login name = '" +userProfileVO LoginName + "' in table 'UserProfile'");userProfileVO.LoginName + in table UserProfile );

}

} catch (DbException e) {

throw new InternalErrorException(e);}

} // Update

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

/// <exception cref="InstanceNotFoundException"/> /// <exception cref="InternalErrorException"/> public void Remove(DbConnection connection,

DbTransaction transaction, String loginName) {

try {

/* Create the command. */DbCommand command = connection.CreateCommand();/* If transaction exists, command will be added. */

command.CommandText ="DELETE FROM UserProfile " +DELETE FROM UserProfile +"WHERE loginName = " + GetParameterSyntax("loginName");

DbParameter loginNameParam = command.CreateParameter();loginNameParam.ParameterName = GetParameterName("loginName");loginNameParam.DbType = DbType.String;loginNameParam.Size = 30;loginNameParam.Value = loginName;command.Parameters.Add(loginNameParam);

Page 20: 03.2.- MiniPortal - MiniBank - UDC

20

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.AbstractUserProfileDAO

command.Prepare();

int removedRows = command.ExecuteNonQuery();

if (removedRows == 0) {

throw new InstanceNotFoundException(loginName,typeof(UserProfileVO).FullName);

}

} catch (DbException e) {

throw new InternalErrorException(e);throw new InternalErrorException(e);}

} // Remove

#endregion

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.SQLServerUserProfileDAO

Page 21: 03.2.- MiniPortal - MiniBank - UDC

21

Es.UDC.DotNet.MiniPortal.Model.UserProfile.DAO.SQLServerUserProfileDAO

/// <summary>/// Class which implements the abstract class AbstractUserProfileDAO to work/// with a SQLServer Provider./// </summary>public class SQLServerUserProfileDAO : AbstractUserProfileDAO{

private static readonly String PARAMETER_PREFIX = "@";

protected override String GetParameterSyntax(string parameterName) {

return PARAMETER_PREFIX + parameterName;

}}

protected override String GetParameterName(string parameterName) {

return PARAMETER_PREFIX + parameterName;}

}

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate

Page 22: 03.2.- MiniPortal - MiniBank - UDC

22

Session Facade y Business Delegate

Patrón Session FacadeNotación XXXFacade

Patrón Business DelegateNotación XXXDelegate

En este caso, el objeto Business Delegate y el Session Facade serán el mismo

No necesitamos hacer plug-n-play del modeloNo necesitamos hacer plug n play del modelo

El Delegate será una clase concreta

Session Facade y Business Delegate

Para facilitar la comprensión del código, las operaciones del Session Facade se han implementado directamente

En una aplicación real, las operaciones del Session Facade deberían implementarse en términos de acciones (implementar cada operación en una clase)

Page 23: 03.2.- MiniPortal - MiniBank - UDC

23

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

[Serializable()]public class UserFacadeDelegate{

private String loginName;

private static readonly String providerInvariantName =Settings.Default.UserProfileDAOFactory_providerInvariantName;

private static readonly String connectionString =Settings.Default.UserProfileDAOFactory_connectionString;

private static readonly DbProviderFactory dbProviderFactory =DbProviderFactories GetFactory(providerInvariantName);DbProviderFactories.GetFactory(providerInvariantName);

/// <summary>/// Initializes a new instance of the <see cref="UserFacadeDelegate"/> /// class and stablishes the facade state./// </summary>public UserFacadeDelegate() {

loginName = null;}

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

/// <exception cref="InstanceNotFoundException">/// This error occurs when this <paramref name="loginName"/> does/// not exist./// </exception>/// <exception cref="IncorrectPasswordException">/// This error occurs when the <paramref name="password"/> does not/// match with the user password stored./// </exception>/// <exception cref="InternalErrorException"/> public LoginResultVO Login(String loginName, String password,

Boolean passwordIsEncrypted) {

DbConnection connection = null;DbConnection connection = null;String encryptedPassword = null;

try {

/* Create the connection. */connection = dbProviderFactory.CreateConnection();connection.ConnectionString = connectionString;connection.Open();

Page 24: 03.2.- MiniPortal - MiniBank - UDC

24

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

IUserProfileDAO dao = UserProfileDAOFactory.GetDAO();

UserProfileVO userProfileVO = dao.Find(connection, null, loginName);

if (passwordIsEncrypted) {

encryptedPassword = password;}else{

encryptedPassword = Crypto.crypt(password);}

if (!userProfileVO.EncryptedPassword.Equals(encryptedPassword)) {

throw new IncorrectPasswordException(loginName);}

this.loginName = loginName;

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

return new LoginResultVO(userProfileVO.LoginName,userProfileVO.EncryptedPassword,userProfileVO.UserProfileDetailsVO.Language,userProfileVO.UserProfileDetailsVO.Country);

} catch (InstanceNotFoundException e) {

throw;}catch (InternalErrorException e) {

throw;}} catch (Exception e) {

throw new InternalErrorException(e);}

Page 25: 03.2.- MiniPortal - MiniBank - UDC

25

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

finally{

try {

if (connection != null) {

connection.Close();}

} catch (Exception e) {

throw new InternalErrorException(e);}

}}

} // Login

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

/// <exception cref="InternalErrorException"/> public UserProfileVO FindUserProfile() {

DbConnection connection = null;

try {

/* Create the connection. */<< ... >>

/* Get a DAO */<< ... >>

/* State Facade. loginName is stored. */return dao.Find(connection, null, this.loginName);

} catch (InstanceNotFoundException e) {

throw new InternalErrorException(e);}

Page 26: 03.2.- MiniPortal - MiniBank - UDC

26

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

catch (InternalErrorException e) {

throw;} catch (Exception e) {

throw new InternalErrorException(e);} finally{

try {

if (connection != null) {{

connection.Close();}

} catch (Exception e) {

throw new InternalErrorException(e);}

}} // FindUserProfile

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

/// <exception cref="DuplicateInstanceException">/// This error occurs when exists a previous instance with the same key./// </exception>/// <exception cref="InternalErrorException"/>public void RegisterUser(String loginName, String clearPassword,

UserProfileDetailsVO userProfileDetailsVO) {

DbConnection connection = null;DbTransaction transaction = null;Boolean rollback = false;

try {{

/* Create the connection. */<< ... >>

/* Starts new transaction. */transaction =

connection.BeginTransaction(IsolationLevel.Serializable);

Page 27: 03.2.- MiniPortal - MiniBank - UDC

27

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

IUserProfileDAO dao = UserProfileDAOFactory.GetDAO();

String encryptedPassword = Crypto.crypt(clearPassword);

UserProfileVO userProfileVO = new UserProfileVO(loginName,encryptedPassword, userProfileDetailsVO);

dao.Create(connection, transaction, userProfileVO);

this.loginName = loginName;

} catch (DuplicateInstanceException e)catch (DuplicateInstanceException e) {

rollback = true;throw;

} catch (InternalErrorException e) {

rollback = true;throw;

}

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

catch (Exception e) {

rollback = true;throw new InternalErrorException(e);

} finally{

try {

/* Commit or rollback, and finally, close connection. */if (connection != null) {

if (rollback) {{

transaction.Rollback();} else{

transaction.Commit();}connection.Close();

}}

Page 28: 03.2.- MiniPortal - MiniBank - UDC

28

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

catch (Exception e) {

throw new InternalErrorException(e);}

}

} // RegisterUser

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

/// <exception cref="InternalErrorException"/> public void UpdateUserProfileDetails(UserProfileDetailsVO

userProfileDetailsVO) {

<< ... >>

try {

/* Create the connection. */<< ... >>

/* Starts new transaction. */<< ... >>

/* Get a DAO *// Get a DAO /<< ... >>

UserProfileVO userProfileVO = dao.Find(connection,transaction, this.loginName);

userProfileVO.UserProfileDetailsVO = userProfileDetailsVO;

dao.Update(connection, transaction, userProfileVO);}

Page 29: 03.2.- MiniPortal - MiniBank - UDC

29

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

catch (InstanceNotFoundException e) {

rollback = true;throw new InternalErrorException(e);

} catch (InternalErrorException e) {

rollback = true;throw;

} catch (Exception e) {

rollback = true;rollback = true;throw new InternalErrorException(e);

}

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

finally{

try {

/* Commit or rollback, and finally, close connection. */<< ... >>

} catch (Exception e) {

throw new InternalErrorException(e);}

}

} // UpdateUserProfileDetails} // UpdateUserProfileDetails

Page 30: 03.2.- MiniPortal - MiniBank - UDC

30

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

/// <exception cref="IncorrectPasswordException">/// This error occurs when the <paramref name="oldClearPassword"/> does/// not match with the user's password stored./// </exception>/// <exception cref="InternalErrorException"/> public void ChangePassword(String oldClearPassword,

String newClearPassword) {

<< ... >>

try {

/* Create the connection. */<< ... >>

/* Starts new transaction. */<< ... >>

/* Get a DAO */<< ... >>

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

UserProfileVO userProfileVO = dao.Find(connection,transaction, this.loginName);

/* Recovery current password. */String storedPassword = userProfileVO.EncryptedPassword;

/* Compare current with oldClearPassword. */if (!storedPassword.Equals(Crypto.crypt(oldClearPassword))) {

throw new IncorrectPasswordException(this.loginName);}

/* Update current password. */storedPassword = Crypto crypt(newClearPassword);storedPassword = Crypto.crypt(newClearPassword);

userProfileVO.EncryptedPassword = storedPassword;

dao.Update(connection, transaction, userProfileVO);

Page 31: 03.2.- MiniPortal - MiniBank - UDC

31

Es.UDC.DotNet.MiniPortal.Model.UserFacade.Delegate.UserFacadeDelegate

} catch (InstanceNotFoundException e) {

rollback = true;throw new InternalErrorException(e);

} catch (InternalErrorException e) {

rollback = true;throw e;

} catch (Exception e) {

rollback = true;rollback = true;throw new InternalErrorException(e);

} finally{

<< ... >>}

} // ChangePassword

Pruebas de unidad

Se han incluido pruebas de unidad para validar clases individuales

Incluyen un método Main (comentado con //) con código de prueba dentro de

#region Test Code Region. Uncomment for testing.

#endregion

Las pruebas de unidad de los DAOs se han ubicado enLas pruebas de unidad de los DAOs se han ubicado en la factoría de DAOs

El Session Facade contiene código de prueba para cada caso de uso

Page 32: 03.2.- MiniPortal - MiniBank - UDC

32

Pruebas de unidad

VStudio Team Suite permite la creación de test project

P t T t Mi iP t lProyecto Test MiniPortalConstructores

Propiedades

MétodosPrueban únicamente código método

d dT t d j BD i t torderedTest dejan BD consistente

Web

Realización opcional en la práctica

Acceso a Parámetros Configurables

App.configFichero que permite almacenar propiedades configurablesFichero que permite almacenar propiedades configurables

Almacena pares (variable/valor)

Formato XML

Accesible en tiempo de ejecución

Acceso a parámetros no definidos implica que se lance ConfigurationErrorExceptionConfigurationErrorException

Aplicaciones Web ASP.NETLectura de propiedades desde un fichero Web.config

Page 33: 03.2.- MiniPortal - MiniBank - UDC

33

Acceso a Parámetros Configurables

Ejemplo de fichero App.config

<?xml version="1.0" encoding="utf-8" ?><configuration>

<appSettings>

<!-- ****** Parameters for DataBase Connection ******** --><!-- Data Provider --><add key="UserProfileDAOFactory/providerInvariantName"

value="System.Data.SqlClient"/>

<!-- Connection String --><add key="UserProfileDAOFactory/connectionString"<add key= UserProfileDAOFactory/connectionString

value="Data Source=localhost\SQLExpress; Initial Catalog=miniportal; User ID=user; Password=password"/>

</appSettings>

</configuration>

Acceso a Parámetros Configurables

Ejemplo de acceso

using System Configuration;using System.Configuration;

try {

// Gets the AppSettings section for the current applicattion’s// default configuration and access to the parameter by keyString connectionString =

ConfigurationSettings.AppSettings[“UserProfileDAOFactory/connectionString”];

<< ... >>

} catch(ConfigurationErrorException e) {

Debug.WriteLine(“Parameter not found”);}

Page 34: 03.2.- MiniPortal - MiniBank - UDC

34

Acceso a Parámetros Configurables

Framework 2.0 introduce nueva forma de acceso a las propiedades

Accesible a través de Propiedades Proyecto > Settingsp y g

FuncionamientoNamespace xxx.Properties

XXX es el namespace por defecto del proyecto

Encapsula app.config en la clase Settings.csSe accede como propiedades (no a elementos de un array)

Accesibles en tiempo de compilación a través del diseñadorEn tiempo de ejecución

Valores iniciales se modifican sobre fichero app.configPueden modificarse desde código

Settings.Default.Save();

Acceso a Parámetros Configurables

Compartición de propiedades entre diferentes proyectos posible

Por defecto se leen las propiedades definidas en el proyecto enlazadop p p y

SobreescrituraAñadir en el app.config de la aplicación principal la propiedad que desea sobreescribirse.

Ejemplo: Sobreescribir LogDestination de Es.UDC.Net.Util.Log

<?xml version="1.0" encoding="utf-8" ?><configuration>

<configSections><sectionGroup name="applicationSettings" ... ><section name="Es.UDC.DotNet.MiniPortal.Properties.Settings" ... /><section name="Es.UDC.DotNet.Util.Properties.Settings" ... />

</sectionGroup>

</configSections>

Page 35: 03.2.- MiniPortal - MiniBank - UDC

35

Acceso a Parámetros Configurables<applicationSettings>

<Es.UDC.DotNet.MiniPortal.Properties.Settings>

<setting name="UserProfileDAOFactory_providerInvariantName" serializeAs="String"><value>System.Data.SqlClient</value>

</setting>

<< ... >>

<Es.UDC.DotNet.MiniPortal.Properties.Settings>

<Es UDC DotNet Util Properties Settings><Es.UDC.DotNet.Util.Properties.Settings>

<setting name="LogManager_FileLocation" serializeAs="String"><value>s:\\MiniPortalLog</value>

</setting>

</Es.UDC.DotNet.Util.Properties.Settings>

</applicationSettings></configuration>

MiniBank

Integración de SistemasIntegración de SistemasDiseño e implementación con .NET

Page 36: 03.2.- MiniPortal - MiniBank - UDC

36

MiniBank

Un sencillo ejemplo de una aplicación bancaria con los siguientes casos de uso

Crear una cuenta bancariaCrear una cuenta bancariaDatos de una cuenta: identificador de la cuenta, identificador del usuario, balanceEl identificador de la cuenta se genera automáticamente

Buscar una cuenta a partir de su identificadorAñadir una cantidad de dinero a una cuentaRetirar una cantidad de dinero de una cuentaBuscar todas las cuentas de un usuarioEli i tEliminar una cuentaHacer una transferencia de dinero de una cuenta a otraBuscar todas las operaciones que se han hecho sobre una cuenta entre dos fechas

Datos de una operación: identificador de la operación, identificador de la cuenta, fecha, tipo (añadir/retirar), cantidad de dinero

Estructura de paquetes del modelo

Es.UDC.DotNet.MiniBank.Model

Account

AccountFacade

Exceptions

Plain

Delegate

DAO

VO

VO

Actions

AccountOperation

VO

DAO

Page 37: 03.2.- MiniPortal - MiniBank - UDC

37

Representación del estado de una cuenta

Representación del estado de una operación bancaria

Page 38: 03.2.- MiniPortal - MiniBank - UDC

38

Page-By-Page Iterator

Patrón Page-by-Page IteratorSolicitar objetos por bloquesSolicitar objetos por bloques

En JavaResultSet.TYPE_SCROLL_INSENSITIVE

Permite mover el cursor hacia adelante, atrás o saltar a una posición absoluta o relativaNo muestra los cambios que se estén haciendo a la BD mientras está abierto

En .NETNo se dispone de un equivalente al ResultSet.TYPE_SCROLL_INSENSITIVE

Es.UDC.DotNet.MiniBank.Model.Account.DAO.CCSqlServerAccountDAO

public override List<AccountVO> FindByUserIdentifier(DbConnection connection, DbTransaction transaction, long userIdentifier, int startIndex, int count)

{DbDataReader dataReader = null;

try{

// Creates the command and add the transaction (if exists)// ...

command.CommandText =String.Format(

"SELECT TOP {0} accId balance FROM Account " +SELECT TOP {0} accId, balance FROM Account +"WHERE usrId = {1} " +"AND accId NOT IN (SELECT TOP {2} accId FROM Account " +" WHERE usrId = {3} ORDER BY accID) " +"ORDER BY accId",count, GetParameterSyntax("usrId"), startIndex - 1,GetParameterSyntax("usrId"));

Page 39: 03.2.- MiniPortal - MiniBank - UDC

39

Es.UDC.DotNet.MiniBank.Model.Account.DAO.CCSqlServerAccountDAO

DbParameter userIdParam = command.CreateParameter();userIdParam.ParameterName = GetParameterName("usrId");userIdParam.DbType = DbType.Int32;userIdParam.Value = userIdentifier;command.Parameters.Add(userIdParam);

command.Prepare();

/* Execute the Query */dataReader = command.ExecuteReader();

Es.UDC.DotNet.MiniBank.Model.Account.DAO.CCSqlServerAccountDAO

/* Read objects. */List<AccountVO> accountVOs = new List<AccountVO>();

while (dataReader.Read()){

int i = 0;Int64 accId = dataReader.GetInt64(i++);Double balance = dataReader.GetDouble(i++);

AccountVO account =new AccountVO(accId, userIdentifier, balance);

accountVOs.Add(account);}}

/* Return value objects. */return accountVOs;

}

Page 40: 03.2.- MiniPortal - MiniBank - UDC

40

Es.UDC.DotNet.MiniBank.Model.Account.DAO.CCSqlServerAccountDAO

catch (DbException e){

throw new InternalErrorException(e);}finally{

if (dataReader != null){

dataReader.Close();}

}}

Un ejemplo de recorrido/* Get value objects in groups of 10. */int startIndex = 1;int groupCount = 10;List<AccountVO> accountVOs;

do{

accountVOs = dao.FindByUserIdentifier(connection,transaction, userId, startIndex, groupCount);

/* Print value objects. */foreach (AccountVO account in accountVOs){

LogManager RecordMessage(account ToString()LogManager.RecordMessage(account.ToString(),LogManager.MessageType.INFO);

}LogManager.RecordMessage("--------------------",

LogManager.MessageType.INFO);

startIndex = startIndex + groupCount;

} while (accountVOs.Count == groupCount);

Page 41: 03.2.- MiniPortal - MiniBank - UDC

41

Page-By-Page Iterator

Otras soluciones:

Usando DataSetDbDataAdapter – Método Fill(DataSet, Int32, Int32, String)

adapter.Fill(dataSet, startIndex, count, "Users");

InconvenienteEficiencia reducida

Usando DataReaderDr.Read()

Solución más eficiente que usando un DataSetSolución más eficiente que usando un DataSetInconveniente

Necesario recorrer todas las filas previas a startIndex

Generación de Identificadores

Basado en Columnas ContadorInserción de cada fila implica la creación automática de un valor numérico empleado como identificadorempleado como identificador

Una vez insertada la fila, puede consultarse el último identificador creado mediante una query

Query dependiente del SGBD

MS SQL Serverselect @@identity

MySQLselect LAST_INSERT_ID()

Page 42: 03.2.- MiniPortal - MiniBank - UDC

42

Generación Identificadores

<<implements>>

Generación IdentificadoresIEntityIdentifierRetrieverusing System;using System.Data.Common;

namespace Es.UDC.DotNet.Util.SQL.EntityIdentifierRetriever {

interface IEntityIdentifierRetriever {

/// <summary>/// Returns the last Entity Identifier generated/// </summary>/// <param name="connection">The connection.</param>/// <param name="transaction">The transaction.</param>/// <returns></returns>Int64 GetGeneratedIdentifier(DbConnection connectionInt64 GetGeneratedIdentifier(DbConnection connection,

DbTransaction transaction);}

}

Page 43: 03.2.- MiniPortal - MiniBank - UDC

43

Generación IdentificadoresGenericEntityIdentifierRetriever (I)using System;using System.Data;using System.Data.Common;using System.Configuration;

using Es.UDC.DotNet.Util.Exceptions;

namespace Es.UDC.DotNet.Util.SQL.EntityIdentifierRetriever {

public class GenericEntityIdentifierRetriever : IEntityIdentifierRetriever {

private static String queryString =private static String queryString =Settings.Default.GenericEntityIdentifierRetriever_query;

Generación IdentificadoresGenericEntityIdentifierRetriever (II)

/// <summary>/// Returns the last Entity Identifier generated/// </summary>/// <param name="connection">DataBase Connection</param>/// <exception cref="InternalErrorException"/> public Int64 GetGeneratedIdentifier(DbConnection connection,

DbTransaction transaction) {

DbCommand command = null;

try {

command = connection CreateCommand();command = connection.CreateCommand();command.CommandText = queryString;

/* If transaction exists, command will be added */if (transaction != null){

command.Transaction = transaction;}

Page 44: 03.2.- MiniPortal - MiniBank - UDC

44

Int64 identity = Convert.ToInt64(command.ExecuteScalar());return identity;

Generación IdentificadoresGenericEntityIdentifierRetriever (III)

} catch (Exception e) {

throw new InternalErrorException(e);}

}}

}

Generación IdentificadoresEntityIdentifierRetrieverFactoryclass EntityIdentifierRetrieverFactory {

private EntityIdentifierRetrieverFactory() { }

public static IEntityIdentifierRetriever GetRetriever() {

Object theObject = null;

try {

String retrieverClassName =Settings.Default.

EntityIdentifierRetrieverFactory_retrieverClassName;

Assembly assembly = Assembly.GetExecutingAssembly();

theObject = AppDomain.CurrentDomain.theObject AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assembly.FullName, retrieverClassName);

} catch (Exception e) {

throw new InternalErrorException(e);}

return (IEntityIdentifierRetriever)theObject;}

}

Page 45: 03.2.- MiniPortal - MiniBank - UDC

45

Generación IdentificadoresParámetros de configuración

Query para la obtención del último identificador insertado

<add key="GenericEntityIdentifierRetriever_query" serializeAs="String"

value="SELECT @@IDENTITY"/>

Clase instanciada por la factoría EntityIdentifierRetrieverFactory para la recuperación deEntityIdentifierRetrieverFactory para la recuperación de identificadores

<add key="EntityIdentifierRetrieverFactory_retrieverClassName“ serializeAs="String"

value="IdentifierGenerator.GenericEntityIdentifierRetriever"/>

Generación IdentificadoresEjemplo de uso: MiniBank (I)public class CCSqlServerAccountDAO : AbstractSQLAccountDAO

{

/// <summary>/// I l t th C t ti f A tDAO i C t C l h/// Implements the Create operation for AccountDAO using a Counter Columns approach/// </summary>/// <exception cref="InternalErrorException"/> public AccountVO Create(DbConnection connection, Transaction transaction, AccountVO accountVO) {

DbCommand command = null;

try {

command = connection.CreateCommand();command.CommandText = "INSERT INTO Account (userID, balance) " +

" values (" + GetParameterSyntax(userID) + ", " + GetParameterSyntax(balance) + ")";

// paramaters configuration <<…>>

command.Prepare();

/* Execute query. */int insertedRows = command.ExecuteNonQuery();

if (insertedRows == 0) throw new SQLException("Can not add row to table 'Account'");

if (insertedRows > 1)throw new SQLException("Duplicate row in table 'Account'");

Page 46: 03.2.- MiniPortal - MiniBank - UDC

46

Generación IdentificadoresEjemplo de uso: MiniBank (II)

/* Get account identifier. */IEntityIdentifierRetriever entityIdentifierRetriever =

EntityIdentifierRetrieverFactory.GetRetriever();

Int64 accountIdentifier = entityIdentifierRetriever.GetGeneratedIdentifier(connection, transaction);

/* Return the value object AccountVO(id, userID, balance) */return new AccountVO(accountIdentifier, accountVO.UserIdentifier,

accountVO.Balance);

} catch(Exception e){

throw new InternalErrorException(e);}

}}}

Procesador de acciones

En MiniBank, a diferencia de MiniPortal, se ha implementado el Session Facade en términos de acciones

Cada operación del Session Facade delega su implementación en la acción correspondiente

Existen acciones transaccionales (deben implementar ITransactionalPlainAction) y no transaccionales (deben implementar INonTransactionalPlainAction)

Implementación de un procesador de acciones en Es UDC DotNet Util SQL ActionProcessorEs.UDC.DotNet.Util.SQL.ActionProcessor

Page 47: 03.2.- MiniPortal - MiniBank - UDC

47

Es.UDC.DotNet.Util.SQL.ActionProcessor.PlainActionProcessor

public sealed class PlainActionProcessor{

private static readonly String connectionString =Settings.Default.PlainActionProcessor_connectionString;

private PlainActionProcessor() { }

/// <exception cref="ModelException"/>/// <exception cref="InternalErrorException"/>public static Object Process(DbProviderFactory dbProviderFactory,

INonTransactionalPlainAction action){

DbConnection connection = null;

try{

connection = dbProviderFactory.CreateConnection();connection.ConnectionString = connectionString;connection.Open();

return action.Execute(connection);}

Es.UDC.DotNet.Util.SQL.ActionProcessor.PlainActionProcessor

catch (DbException e){

throw new InternalErrorException(e);} finally{ try{

if (connection != null){

connection.Close();}

}catch (Exception e)catch (Exception e){

throw new InternalErrorException(e);}

}}

Page 48: 03.2.- MiniPortal - MiniBank - UDC

48

Es.UDC.DotNet.Util.SQL.ActionProcessor.PlainActionProcessor

/// <exception cref="ModelException"/>/// <exception cref="InternalErrorException"/>public static Object Process(DbProviderFactory dbProviderFactory,

ITransactionalPlainAction action){

DbConnection connection = null;DbTransaction transaction = null;Boolean rollback = false;

try{

connection = dbProviderFactory.CreateConnection();connection.ConnectionString = connectionString;connection Open();connection.Open();

transaction =connection.BeginTransaction(IsolationLevel.Serializable);

/* Execute action. */Object result = action.Execute(connection, transaction);

Es.UDC.DotNet.Util.SQL.ActionProcessor.PlainActionProcessor

/* Return "result". */return result;

}catch (InternalErrorException e){

rollback = true;throw e;

}catch (Exception e){

rollback = true;throw new InternalErrorException(e);

}finallyfinally{

Page 49: 03.2.- MiniPortal - MiniBank - UDC

49

Es.UDC.DotNet.Util.SQL.ActionProcessor.PlainActionProcessor

try{

/* Commits or rollbacks, and finally, closes connection. */if (connection != null){

if (rollback){

transaction.Rollback();}else{

transaction.Commit();}connection Close();connection.Close();

}}catch (Exception e){

throw new InternalErrorException(e);}

} // finally} // Process