Mostrando entradas con la etiqueta Access. Mostrar todas las entradas
Mostrando entradas con la etiqueta Access. Mostrar todas las entradas

miércoles, 17 de julio de 2013

Bases de datos locales y uso del app.config con .NET: Access vs SQLCompact

Buenas en este post voy a empezar a fondo con el tema de las bases de datos locales en .NET y en Java. Primero voy a tratar cómo utilizar bases de datos locales en aplicaciones de escritorio de Windows Forms en .NET y en el siguiente post trataré lo mismo pero con WPF y en siguientes empezaré con bases de datos tanto situadas en servidores como locales a las que nuestra aplicación se conectará.
Idea clara: vamos a crear aplicaciones con bases de datos locales. Instalo la aplicación en un ordenador y ésta accederá a su base de datos local. Otra alternativa sería usar SQL Server o MySQL como proveedor de bases de datos y entonces tendríamos una o varias aplicaciones clientes que se conectarían a un servidor donde estarían almacenados los datos y trabajarían con ellos. En ambos tipos de aplicaciones el acceso a los datos se puede hacer de forma conectada (es decir crear conexión, crear comando, abrir conexión, ejecutar comando, cerrar conexión, etc… En pocas palabras si por lo que sea se corta la conexión con la base de datos en cualquier momento la aplicación fallará) o de forma desconectada (trabajar con datasets y dataadapters, es decir, tenemos una copia en memoria de nuestros datos en el dataset con los que trabajaremos y el dataadapter será el encargado se sincronizar la copia en memoria con los datos de la base datos cuando se requiera).
En el vídeo que voy a colgar voy a explicar cómo crear, configurar y publicar varios proyectos de aplicaciones para Windows Forms que usan bases de datos locales y me voy a centrar en las dos más conocidas: Access y SQLCompact. Para usar una base de datos Access la tenemos que crear primero ya sea en Access directamente y añadirla al proyecto. El IDE ajudará en el proceso de agregar un nuevo origen de datos a nuestro proyecto.
Pues bien aquí viene la chicha, porque de conectarse a una base de datos en .NET hay mil y un post, pero… qué pasa si quiero ocultar la contraseña de la base de datos que usará mi aplicación y que por defecto, y atendiendo a las buenas prácticas de programación, se me guardará en el archivo app.config o en [NombreDeMiAplicación].vshost.exe que se genera en la carpeta bin/Debug o bin/Release una vez compilemos el proyecto, y añadirla en tiempo de ejecución.
Normalmente los usuarios finales de las aplicaciones no sabrán que en ese archivo estará el id y el password de la base de datos pero es bueno no jugársela. ¿Cuál es la solución que podemos usar para que esa información esté oculta? Pues la mejor es encriptar la cadena de conexión y otra información sensible en el archivo app.config.
Pues bien la pregunta ahora es cómo la desencripto en tiempo de ejecución. Bueno dependerá del tipo proyecto. Si el proyecto que tienes es el tipo proyecto que creas tú desde cero sin usar ningún asistente, pues en el método que crees para recuperar la cadena de conexión podrás aprovechar para desencriptarla y ya la podrás usar. El código sería similar a éste de aquí:
Private _cadenaConexion As String
Private _factory As DbProviderFactory = Nothing

Private Sub ConfigurarAcceso()
Try
Dim proveedor As String = ConfigurationManager.ConnectionStrings("BaseConnectionString").ProviderName
Me._cadenaConexion = ConfigurationManager.ConnectionStrings("BaseConnectionString").ConnectionString

'Aquí iría el código para desencriptar los datos de la cadena de conexión
 
Me._cadenaConexion = …

Me._factory = DbProviderFactories.GetFactory(proveedor)
Catch ex As ConfigurationErrorsException
Throw New MiBaseDatosException("Error al acceder a la configuración del acceso a datos.", ex)
End Try
End Sub

Pero qué es lo que pasa cuando has creado un proyecto para Windows Forms y has usado el asistente para que te cree un dataset y un dataadapter y te das cuenta que si ejecutas el proyecto no funciona porque la cadena de conexión está encriptada o le falta añadir la contraseña como en el ejemplo que pongo. Pues nada verás si abres el dataset con el diseñador y haces click en el TableAdapter la cadena de conexión la recoge no del archivo app.config sino de My.Settings
Pues bien podríamos ser chapuceros y borrar el nodo del archivo app.config y más feliz que una pediz  o podríamos usar las buenas prácticas y ejemplo encriptar esa sección del app.config o eliminar la contraseña. Luego vamos a nuestro proyecto y hacemos click con el botón derecho para ver las propiedades en “Configuración”  “Ver Código” y podemos pegar un código como este para añadir el password a la cadena de conexión:
Partial Friend NotInheritable Class MySettings

Default Public Overrides Property Item(ByVal propertyName As String) As Object

Get
If propertyName = "BaseConnectionString" Then
Return MyBase.Item(propertyName) & ";Jet OLEDB:Database Password=admin;"
End If
Return MyBase.Item(propertyName)
End Get

Set(ByVal value As Object)
MyBase.Item(propertyName) = value
End Set

End Property

End Class
 
 

Por último qué pasa si usamos Entity FrameWork  y queremos desencriptar la cadena de conexión o añadir la contraseña a la cadena de conexión que aparece en nuestro archivo app.config. Verás que aquí como puedo no usaré Access sino SQLCompact como base de datos.
Pues una de las tantas maneras es crear una función que me devolverá la conexión ya desencriptada o con la contraseña en nuestro caso:

Private Function getConnection(name As String) As String

Dim connectionString = ConfigurationManager.ConnectionStrings(name).ConnectionString
Dim builder = New EntityConnectionStringBuilder(connectionString)

builder.ProviderConnectionString = builder.ProviderConnectionString & ";Password=estrella;"

Return builder.ToString()

End Function
Y luego ya en el código al crear una nueva instancia de nuestra entidad pues usamos una de las sobrecargas del método constructor que me permitirá pasarle ya cadena de conexión ya lista para usar (porque me la ha devuelto la función getConnection que hemos creado antes.
Dim db As New baseEntities(getConnection("baseEntities"))
Pues bien en el siguiente vídeo voy a concretar todos estos temas ya que hay amplio contenido.

En el siguiente post continuaré con acceso a bases de datos locales en WPF, que proporcinará unas interfaces mucho más modernas para nuestras aplicaciones y entonces entraremos al mundo de las bases locales en Java usando Hibernate y JPA. Tengo pensado desarrollar otra aplicación en Java para hacer facturas y listar datos. Quiero desarrollar la típica aplicación de facturación en Java y luego desarrollar alguna que otra aplicación contable así útil que me quite trabajo.

domingo, 17 de junio de 2012

Formulario de Login con Base de datos Access

Buenas después de bastante tiempo sin publicar nada por temas de exámenes, en este post voy a tratar el tema del formulario de login (LoginForm) que se puede agregar a cualquier proyecto para WindowsForms en Visual Studio. Es un formulario ya diseñado que nos permitirá que los usuarios de nuestra aplicación puedan entrar su nombre y su contraseña y una vez validado puedan acceder a otros formularios de la aplicación. El problema es que el código brilla por su ausencia. Es sólo un formulario con 2 textboxes añadidos, uno para el nombre de usuario y otro para la contraseña, una imagen en la esquina izquierda y un botón de Ok y otro de Cancel. Hay un link para más información de como implementar la autentificación en http://go.microsoft.com/fwlink/?LinkId=35339) pero no funciona.

Ya sé que el código podría ser tan simple como escribir un simple condicional y comprobar que el usuario y la contraseña introducida coincide con algún valor que ponemos en el código. Sería un simple If PasswordTextBox.Txt = “1234” Then… Esto lógicamente funciona pero tiene el problema de su difícil mantenimiento ya que la contraseña para validar estaría en el código y podría ser fácilmente encontrada si el proyecto se descompila. A parte si la aplicación se distribuye y se quieren agregar más usuarios y más contraseñas se tendría que estar frecuentemente actualizando. Vamos que no es viable.  
La idea es usar bases de datos, en mi caso Access pero con SQL o MySQL sería lo mismo. Pero aquí hay otro problema que es que si alguien abre la base de datos verá el nombre de usuario y la contraseña. Por lo que no nos queda más remedio que encriptar la contraseña en la base de datos por si alguien la abre no pueda ver las contraseñas. Con .NET es sencillo gracias al espacio de nombres System.Security.Cryptography
Bueno en el código que voy a colgar vamos a recordar como hacer operaciones de SELECT, UPDATE e INSERT en una base de datos Access usando ahora un acceso conectado (es decir sin DataSets ni DataAdapters). Lo que vamos a repasar como crear una conexión, crear un comando con parámetros, abrir la conexión, ejecutar el comando y cerrar la conexión. Como lo que vamos a consultar es si existe en la base de datos un usuario ya creado y sino lo crearemos y a parte permitiremos cambiar la contraseña vamos a usar 'comando.ExecuteScalar' para devolver la fila de la base de datos cuyo usuario y contraseña coincide con el especificado en los parámetros de la consulta, y 'comando.ExecuteNonQuery' para los INSERT y UPDATE -y DELETE- en los que no quiero que la consulta nos retorne nada. Hoy no voy a usar 'comando.ExecuteReader' ya que no quiero que me devuelva varias filas de la base de datos.
Un ejemplo de un SELECT en la base de datos Access con 2 parámetros sería el siguiente:
Dim conexion As OleDbConnection = New OleDbConnection()
        ' Asigno la cadena de conexion a la base de datos
        conexion.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\data\Base.mdb;Persist Security Info=True;Jet OLEDB:Database Password=luna"
        ' Creo un comando
        Dim comando As OleDbCommand = New OleDbCommand()
        ' Asigno el texto de la consulta SQL
        comando.CommandText = "SELECT COUNT(user) FROM `Usuarios` WHERE `user`=? and `password`=?"
        comando.Connection = conexion
        ' Añado los parámetros
        comando.Parameters.AddWithValue("user", nombre.ToUpper())
        comando.Parameters.AddWithValue("password", clave)
        Try
            ' Abro la conexión
            conexion.Open()
            Dim resultado As String
            ' Ejecuto la consulta que devolverá 1 si el usuario existe
            resultado = comando.ExecuteScalar
            If resultado < > 1 Then
                'Se ha encontrado el usuario
                             msgbox("Usuario encontrado")
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            err = True
        Finally
            ' Cierro la conexión
            conexion.Close()
            If conexion IsNot Nothing Then
                ' Libero los recursos asignados
                conexion.Dispose()
            End If
        End Try

De hecho como siempre voy a colgar aquí el código por si alguien quiere aportar, mejorar o agregarlo a su repositorio de código.
Lo ideal es que en el Visual Studio vinieran más ejemplos implementados para no tener que perder el tiempo en esos desarrollos que son idénticos a todas las aplicaciones y centrase más en la lógica de tu aplicación que es lo que te dará el valor añadido y no el crear un formulario con dos o tres controles puestos de tal forma. A veces echas de menos estas cosas o por ejemplo sistemas de Login más complejos, a lo CMS, que puedan mostrar contenido independiente para cada usuario. Un ejemplo sería el tema de las páginas donde te puedes descargar facturas electrónicas. Cada cliente tiene acceso sólo a sus facturas y a parte el hecho de subir y crear facturas no tiene que ser complicado ya que se subirían todas pero sólo tú tendrás acceso a la que coinciden con tus datos de Login. Bueno esto ya será un proyecto a más largo plazo y ya como sitio web para subir a un servidor, si es que en versiones siguientes del Visual Studio no se animan a los que trabajamos en el mundo de la empresa a facilitarnos la vida.
En la siguiente entrada colgaré un ejemplo de aplicación demo o con periodo de evaluación (Trial) que se puede hacer de forma sencilla con .NET y así ya cubro 2 temas que siempre generan muchos quebraderos de cabeza a los programadores novatos.