Bluetooth (IV): Creando el hilo de conexión


Como vimos en anteriores artículos, los elementos necesarios para realizar una comunicación entre dos dispositivos a través de Bluetooth van a ser:

  • Cliente
  • Servidor
  • Conexión

Codificaremos cada uno de estos elementos como hilos independientes encargados de centrarse exclusivamente en su tarea. Así, el hilo servidor se encargará de escuchar conexiones entrantes, aceptarlas y establecer la conexión, mientras que el hilo cliente será el encargado de solicitar la conexión y establecerla una vez que haya sido aceptada por el servidor. Por lo tanto, el hilo encargado de establecer la conexión será lanzado tanto por el cliente como por el servidor.

Comenzaremos codificando el hilo encargado de establecer la conexión. Crearemos una clase específica que contendrá los tres hilos, de modo que la funcionalidad entre interfaz de usuario y lógica de la aplicación se mantenga separada.

Crearemos la clase añadiéndole unas cuantas constantes para definir los posibles estados y mensajes a manejar por el handler y un par de atributos privados para almacenar el estado actual de la conexión, el socket de la conexión y el handler que se encargará de comunicar los datos a la interfaz de usuario.

(más…)

Widgets en Android: creando una linterna


Todos los usuarios de Android conocemos los widgets, pequeñas aplicaciones que por lo general, corren y/o se sitúan en la pantalla principal (Homescreen).

A diferencia de una aplicación tradicional, un widget no necesita una actividad para vivir, sino que se hace uso de la clase RemoteViews para su ejecución. Esta clase implementa un layout (fichero xml con elementos de interfaz) que contiene una o más vistas (View) y tiene la peculiaridad de poder ser ejecutado por otro proceso con los mismos permisos que la aplicación original.

Como introducción a los widgets crearemos una aplicación completa que consistirá en un widget consistente en un ImageButton con el dibujo de una lámpara que cambiará su imagen cuando el usuario lo pulse, haciendo que se encienda y apague la linterna en un dispositivo que cuente con cámara con flash.

Los elementos que necesitaremos para crear este widget serán los siguientes, describiéndolos descendentemente, desde la capa más externa (interfaz) hasta la más interna (receptor de las acciones generadas al pulsar el widget).

  • res/layout/flashlight_layout.xml: Fichero XML que contendrá el layout del widget, es decir, la interfaz del widget en sí, compuesta en este caso por un ImageButton.
  • res/xml/flashlight_widget_provider.xml: Fichero XML que contendrá la descripción del widget provider. Contendrá el layout inicial (que será el fichero anterior) y el tamaño mínimo del widget.
  • FlashLightWidgetProvider.java: Clase que heredará de AppWidgetProvider y se encargará de generar los Intents al producirse algún evento sobre el widget y actualizar las instancias del widget.
  • FlashLightBroadcastReceiver.java: Clase que heredará de BroadcastReceiver y se encargará de detectar las acciones generadas por el elemento anterior. Al detectar la acción, ejecutará la lógica de la aplicación y regenerará la interfaz del widget.

(más…)

Bluetooth (III): El esquema cliente-servidor


Hasta ahora hemos sido capaces de activar y desactivar el Bluetooth, hacer visible nuestro dispositivo y detectar los dispositivos visibles que encuentren en las proximidades. Es hora de intercambiar información por medio del protocolo Bluetooth, para lo cual necesitaremos unas pequeñas nociones básicas de la arquitectura cliente-servidor.

En primer lugar, el protocolo Bluetooth no se diferencia gran cosa de otros protocolos como TCP. El funcionamiento es básicamente el siguiente:

  • El servidor crea un socket de tipo BluetoothServerSocket y lo pone a la escucha de peticiones de conexión.
  • El servidor se mantiene en espera ocupada atendiendo solicitudes de conexión mediante el método accept(). Este método bloqueará el hilo hasta que una conexión entrante sea recibida.
  • El cliente instancia un dispositivo Bluetooth (BluetoothDevice) a partir de la dirección del dispositivo.
  • El cliente abre un nuevo socket de tipo BluetoothSocket a partir del dispositivo que obtuvo previamente.

Instanciación del socket cliente a partir del dispositivo (más…)

Bluetooth (II): Descubriendo dispositivos


Una vez que sabemos cómo funciona el proceso de activación y desactivación del Bluetooth, es hora de buscar dispositivos cercanos que nos permitan establecer una conexión. Para entender los ejemplos mostrados en este artículo se recomienda leer el artículo anterior, Bluetooth (I): Activando y desactivando el Bluetooth en Android.

Como vimos, para que se realice una conexión Bluetooth es necesaria la siguiente secuencia de pasos:

  1. El dispositivo B se configura como servidor, aceptando conexiones entrantes.
  2. El dispositivo A solicita la conexión al dispositivo B. Para ello, es necesario que A conozca la dirección física de B.
  3. En el caso de que A no conozca la dirección de B, la conexión no podrá llevarse a cabo.

Dado que las direcciones no se conocen a priori, es necesario un mecanismo que permita a un dispositivo Bluetooth «encontrar» a otro. Este proceso se denomina descubrimiento o discovery.

Para que el dispositivo A descubra al dispositivo B, es necesario que B, además de tener activado el Bluetooth, cambie su estado a «visible». Esto lo hacíamos solicitándoselo de forma explícita al usuario, tal y como vimos en el artículo anterior.


	Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
	startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

Partiendo de la base de que el dispositivo B se encuentra visible con el Bluetooth activo, ¿cómo hacemos que el dispositivo A le «descubra»? (más…)

Bluetooth (I): Activando y desactivando el Bluetooth en Android


El primer paso a la hora de desarrollar una aplicación que haga uso de la comunicación mediante Bluetooth es comprobar si éste está activado o no en el dispositivo y, en caso de que no sea así, solicitar al usuario permiso para activarlo.

En primer lugar, si vamos a hacer uso del Bluetooth será requisito indispensable añadir los permisos adecuados para ello en el fichero AndroidManifest.xml:


    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Pese a que la tecnología Bluetooth está ampliamente extendida, es de obligado cumplimiento la comprobación de que el servicio está disponible en el dispositivo. Para realizar esta operación haremos uso de la clase android.bluetooth.BluetoothAdapter. Declararemos una referencia como atributo dentro de nuestra Activity y a continuación codificaremos un método, al que llamaremos configurarAdaptadorBluetooth(), que se encargará de detectar si el dispositivo puede hacer uso del Bluetooth y si éste se encuentra activo o no.

(más…)

Diálogos modales en Android (AlertDialog)


Una de las desventajas de las interfaces táctiles es que en ocasiones pulsamos por error elementos que no deseamos. Por ello es conveniente realizar diálogos de confirmación en aquellas operaciones que tengan un carácter sensible, como por ejemplo la eliminación de un registro de la base de datos o la ejecución de una transacción financiera.

Para crear diálogos modales haremos uso de la clases android.app.AlertDialog y android.app.AlertDialog.Builder. El proceso a realizar será el siguiente:

  • Crear un método que genere el diálogo. En él construiremos paso a paso los elementos que queremos mostrar y utilizar, como mensajes, botones y acciones a realizar.
  • Llamar al método show() para mostrar el diálogo.

Imaginemos que en nuestra Activity deseamos realizar una conexión a un dispositivo Bluetooth, y el método destinado a ello recibe el nombre de conectarDispositivo(). Este método recibirá una cadena de texto que indicará la dirección del dispositivo, que se utilizará para obtener una referencia del dispositivo en sí. Olvidémonos del funcionamiento interno de la función y centrémonos en el hecho de que se trata de un método de nuestra Activity y que necesita parámetros para su ejecución:

(más…)

Nueva etapa


Tras una serie de catastróficas desdichas que comienzan con un problema con el anterior hosting y continúan con la corrupción del disco duro en el que almacenaba el backup de la web, he decidido hacer borrón y cuenta nueva y retomar el blog como lo que es: una colección de pequeños apuntes que proporcionan soluciones concretas a problemas concretos.

Pese a que «crecí» con la tecnología .NET, en los últimos años he tenido la oportunidad (y suerte) de formarme y trabajar en otras tecnologías (Diseño web, Java, ADA, Android…). Por lo tanto, este espacio dejará de centrarse exclusivamente en la plataforma de Microsoft y comenzará a diversificar su contenido.

¡Nos leemos!

Redimensionar un control de texto con el tamaño de su contenido


En ocasiones, trabajando con WinForms, nos encontramos con un control contenedor de un texto variable en el que, o nos sobra espacio o nos falta. La clase Graphics de System.Drawing nos proporciona un método tremendamente útil para saber el tamaño, en píxels, de una cadena de texto.
Veremos a continuación cómo redimensionar de forma dinámica un control dependiendo del tamaño del texto contenido. Para ello crearemos, por ejemplo, un TextBox al que llamaremos txtPrueba, y en el que albergaremos un texto, por ejemplo «Más vale pájaro en mano, que ciento volando».


txtPrueba.Text = "Más vale pájaro en mano que ciento volando";

A continuación, declararemos dos variables enteras, una para el alto y otra para el ancho.

// Declaramos una variable entera para almacenar el nuevo ancho y el nuevo alto
int nuevoAncho = 0;
int nuevoAlto = 0;

Es ahora donde instanciaremos la clase Graphics a partir del control TextBox, y extraeremos la fuente que está utilizando.

// Creamos un objeto de tipo Graphics a partir del TextBox
Graphics g = txt.CreateGraphics();

// Extraemos la fuente del TextBox
Font fuente = txt.Font;

Obtenemos, a partir del objeto Graphics, su alto y ancho a partir del método MeasureString, que no hace otra cosa que medir, en pixels, el tamaño que ocupa la cadena con la fuente indicada.


nuevoAncho = (int)g.MeasureString(txt.Text, fuente).Width;
nuevoAlto = (int)g.MeasureString(txt.Text, fuente).Height;

Por último, asignamos los nuevos valores de alto y ancho y refrescamos el control.


txt.Width = nuevoAncho;
txt.Height = nuevoAlto;

txt.Refresh();

A partir de estos conceptos básicos, se pueden encontrar multitud de utilidades a este proceso, como por ejemplo, redimensionar el desplegable de un ComboBox al tamaño del mayor de sus elementos.

Crear un campo autoincrementable en ORACLE


Para los que nos iniciamos en los Gestores de Bases de Datos con SQL Server, la transición a ORACLE resulta siempre más dura que cuando se realiza el camino inverso. Realizando una analogía simple, en mi caso podría decir que T-SQL es a PL/SQL lo que C# es a C++. Más complicación, más potencia… y un sistema más «tiquismiquis» que los desarrollados por Microsoft.
SQL Server proporciona una forma muy sencilla de crear campos autonuméricos, generalmente utilizados en los IDs de las claves primarias de las tablas. Para crear un campo autoincrementable, lo único que teníamos que hacer era editar las propiedades de la columna que queríamos convertir en autoincrementable, acceder a sus propiedades y seleccionar la opción [Especificación de Identidad] marcando la casilla (Identidad) e informando del número de inicio del índice (Inicialización de identidad) y el número de unidades que se incrementará cada vez que se intente insertar un registro (Incremento de identidad).

Oracle nos pone las cosas un poco más difíciles, obligándonos a realizar dos pasos para realizar el mismo procedimiento: crear una secuencia y crear un trigger.

(más…)

Redimensión dinámica de imágenes


Siguiendo con la manipulación de imágenes en .NET, imaginemos que disponemos de una imagen de un tamaño considerable, bien en disco, bien en base de datos, y queremos enviarle al usuario un thumbnail de dicha imagen. ¡Ojo! No queremos mostrar la imagen completa con un estilo que modifique su alto y ancho, ya que con esto estaríamos enviando la imagen completa y luego modificaríamos su visualización en cliente, perdiendo el correspondiente (y valioso) ancho de banda.

En lugar de esto, sacrificaremos unos cuantos ciclos de CPU en pos de limitar el tráfico y realizaremos la operación de redimensionar la imagen en servidor para posteriormente enviarsela (más pequeñita o más grande) al cliente.
Para ello, nos crearemos una función llamada RedimensionarImagen que reciba tres parámetros: la imagen que queremos redimensionar, la nueva altura y la nueva anchura:


private System.Drawing.Bitmap RedimensionarImagen(System.Drawing.Image imagenOriginal, int alto, int ancho)
{

Lo primero que haremos será guardar el alto y el ancho de la imagen original.


int anchoOriginal = imagenOriginal.Width;
int altoOriginal = imagenOriginal.Height;

A continuación declaramos dos variables de tipo float que almacenaran el porcentaje de escalado al que se va a ver sometida la imagen.


float porcentajeEscaladoX = (float)ancho / (float)anchoOriginal;
float porcentajeEscaladoY = (float)alto / (float)altoOriginal;

El siguiente paso será definir una nueva altura para la imagen, multiplicando los valores originales por los factores que hemos obtenido en el paso anterior.


int nuevoAncho = (int)(anchoOriginal * porcentajeEscaladoX);
int nuevoAlto = (int)(altoOriginal * porcentajeEscaladoY);

Ya tenemos las dimensiones de nuestra nueva imagen, ahora necesitaremos crear una instancia.


System.Drawing.Bitmap nuevaImagen = new System.Drawing.Bitmap(nuevoAncho, nuevoAlto);

Ahora instanciamos una superficie de dibujo de GDI+ a partir de la imagen para tratar el tamaño.


System.Drawing.Graphics superficieGDI = System.Drawing.Graphics.FromImage((System.Drawing.Image)nuevaImagen);

Indicamos el modo de interpolación (en nuestro caso, Bicúbico Alta Calidad) y dibujamos la imagen con los nuevos valores de ancho y alto.


superficieGDI.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
superficieGDI.DrawImage(imagenOriginal, 0, 0, nuevoAncho, nuevoAlto);

Finalmente, liberamos el objeto GDI+ y devolvemos la imagen.


superficieGDI.Dispose();

return nuevaImagen;
}

Et voilà!, hecho esto, obtendremos una imagen con el alto y ancho deseados.

Utilizar la Base de Datos como repositorio de imágenes (II)


En un artículo anterior aprendimos a almacenar una imagen en nuestra base de datos SQL Server. Ahora vamos a obtener la imagen que almacenamos previamente utilizando como dirección de la imagen un formulario aspx al que le pasaremos el identificador de la imagen a través de la QueryString.

Comenzaremos creando un nuevo formulario, al que llamaremos showImage.aspx. En el formulario, crearemos un nuevo método al que llamaremos ObtenerImagen, que recibirá como parámetro un entero (el ID de la imagen) y devolverá una secuencia de bytes (un byte[]).

byte[] ObtenerImagen(int idImagen)
{
}

Lo primero que hará este método será declarar una cadena de conexión y una sentencia SELECT que devuelva la imagen cuyo ID le pasamos. Para ello, declararemos ambas cadenas de texto.


string selectCommandText = "SELECT Fichero FROM Imagen WHERE IdImagen = " + Convert.ToString(idImagen);
string ConnectionString = @"Data Source=DANIGARCIASQLSERVER2005;Initial Catalog=TestDB;Persist Security Info=True;User ID=dani;Password=c0ntr4s3n14";

A continuación podemos hacer dos cosas: crear un SqlCommand y ejecutar la sentencia SELECT, o bien declarar un DataSet y un SqlDataAdapter y dejar que sea éste último objeto el que nos proporcione los datos. Optaremos por la segunda opción, que pese a ser menos óptima, resulta mucho más cómoda 🙂


// Declaramos un DataSet y un SqlDataAdapter
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(selectCommandText, selectConnectionString);

// Rellenamos el DataSet con la consulta y la cadena de conexión anteriores
adapter.Fill(ds);

Llegados a este punto, ya deberíamos tener almacenada en el DataSet la imagen que estábamos buscando. Por lo tanto, lo único que deberemos hacer será serializarla y devolverla, realizando las comprobaciones pertinentes:


if ((ds != null) && (ds.Tables.Count > 0) && (ds.Tables[0].Rows.Count > 0))
{
if (!ds.Tables[0].Rows[0].IsNull("Fichero"))
{
return ((byte[])(ds.Tables[0].Rows[0]["Fichero"]));
}
}

return null;

Llegados a este punto, codificaremos el contenido del Page_Load de nuestro aspx, comprobando la QueryString y pasándole el parámetro a nuestra función ObtenerImagen, declarando, en primer lugar, un array de Bytes para almacenar el resultado:


protected void Page_Load(object sender, EventArgs e)
{
byte[] bImagen = null;

if (!string.IsNullOrEmpty(Convert.ToString(Request.QueryString["id"])))
{
bImagen = ObtenerImagen(Convert.ToInt32((Convert.ToString(Request.QueryString["id"]))));
}

Si el resultado obtenido no es nulo, modificamos la respuesta para que sea de tipo imagen, haciendo lo siguiente:


if(bImagen != null)
{
Response.Clear();
Response.Buffer = true;
Response.ContentType = "image/jpeg";
Response.BinaryWrite(bImagen);
Response.End();
}
}

Con lo cual, si invocamos la ruta a través del ID, obtendremos directamente una imagen:


Esto es una prueba <br />
<img src="../aspx/showImage.aspx?id=1" />

Utilizar la Base de Datos como repositorio de imágenes (I)


En cierto proyecto necesitaba mostrar una serie de imágenes que el usuario debía insertar desde su equipo local. En un principio pensé enviar al servidor las imágenes, guardar la ruta relativa en Base de Datos y, cuando fuese necesario acceder a las imágenes, utilizar dicha ruta para acceder a la imagen. Pero no era tan sencillo. Por desgracia, no teníamos permiso de escritura en el disco duro, por lo que tenía que juguetear con las imágenes sin que éstas existieran físicamente. ¿Cómo? Almacenando y recuperando las imágenes de base de datos.

Guardando una imagen en SQL Server

Para empezar, veremos cómo almacenar en base de datos una imagen. Crearemos, desde el SQL Server Management Studio, una nueva tabla que tendrá tres campos:

  • Un Id único entero y autoincrementable (IdImagen)
  • Un nombre para la imagen nvarchar(50) (NombreImagen)
  • Una secuencia de bytes, variable de tipo image (Fichero).

09111201 Creada la tabla, crearemos una página que, a partir de la ruta de la imagen, la inserte en base de datos. Podemos utilizar un Input File o un control similar para indicarle la ruta, pero aquí indicaremos únicamente el código necesario para subir la imagen dada su ruta física. Lo que haremos a continuación será lo siguiente:

  • Crear una conexión a Base de Datos a partir de una cadena de conexión
string ConnectionString = @"Data Source=DANIGARCIASQLSERVER2005;Initial Catalog=TestDB;Persist Security Info=True;User ID=dani;Password=c0ntr4s3n14";
  • Crear una cadena de texto con la sentencia INSERT.
string CommandString = "INSERT INTO Imagen(NombreImagen, Fichero) VALUES (@NombreImagen, @Fichero)";
  • A continuación necesitaremos convertir nuestra imagen en un objeto que podamos manejar, por ejemplo un array de bytes. Para ello, a partir de la ruta física de la imagen crearemos un objeto de tipo System.Drawing.Bitmap que guardaremos en un MemoryStream que, a su vez, convertiremos en un array de bytes (byte[]).
  byte[] bImagen = null; System.IO.MemoryStream ms = new System.IO.MemoryStream();  System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(@"C:TEMPinicio.jpg"); if (bmp != null) { bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); bImagen = ms.ToArray(); ms.Close(); }  
  • Instanciar un objeto de tipo SqlCommand a partir de la  conexión y de la sentencia INSERT.
  SqlConnection conexion = new SqlConnection(ConnectionString);  SqlCommand command = new SqlCommand(CommandString, conexion);  
  • Añadiremos ahora los SqlParameters necesarios al objeto SqlCommand con los datos a insertar en la base de datos. Estos serán, en nuestro caso, el nombre de la imagen y el array de bytes con la imagen.
  SqlParameter nombre = new SqlParameter("@NombreImagen", "inicio.jpg"); SqlParameter imagen = new SqlParameter("@Fichero", bImagen);  
  • Por último, abrimos la conexión, ejecutamos la sentencia mediante ExecuteNonQuery() y cerramos la conexión. Hecho esto, tendremos nuestra imagen almacenada en base de datos.
  conexion.Open();  command.Parameters.Add(nombre); command.Parameters.Add(imagen); command.ExecuteNonQuery();  conexion.Close();  

Hecho esto insertaremos una imagen en una tabla de la base de datos. 09111202 Más adelante aprenderemos cómo recuperarla y referenciarla directamente a través de una URL con extensión aspx, es decir, invocar una ruta de tipo getImage.aspx?Id=xxx.

Recuperar una contraseña almacenada automáticamente mediante Javascript


Últimamente existe una cruenta batalla en la plataforma Windows entre Internet Explorer y Firefox. Personalmente, yo no me decanto hacia uno ni otro: utilizo Opera desde su versión 6.05, allá por 2002. Indico que utilizo Opera porque es un navegador que posee una funcionalidad llamada «varita mágica», que no es más que un gestor de contraseñas en las que, pulsando ALT+ENTER se introducen automáticamente el nombre de usuario y la contraseña de una web en la que se hayan almacenado estos datos previamente.

Esta «comodidad» tiene un precio: a veces, de tanto utilizar este sistema, se me olvida alguna contraseña a causa del desuso, lo que causa que mi navegador la conozca y yo no.

0811_01

Para paliar esta posibilidad, teniendo acceso a la página con el nombre de usuario y la contraseña, es posible averiguar el contenido del campo oculto entre asteriscos mediante una pequeña «treta» en Javascript. Lo primero que deberemos hacer será visualizar el código fuente de nuestra página (normalmente, haciendo click derecho sobre la misma y pulsando «Ver código fuente» o algo así, dependiendo del navegador).

Una vez visualizado, comprobamos la etiqueta que se muestra antes del campo que alberga la contraseña. En GMail, por ejemplo, «Contraseña». Buscaremos este texto en el código fuente, obteniendo algo como lo que sigue: Como podemos observar, nos encontramos con un Input con un campo ID.

0811_02

El valor de esa variable, en nuestro caso «Passwd», es lo que nos interesa. Volveremos a nuestra página, y escribiremos lo siguiente en nuestra barra de navegación:


javascript:alert((document.getElementById('Passwd')).value);

Lo que le estamos diciendo a nuestro navegador es: «Ejecuta el siguiente código javascript: muestrame una alerta con el valor del elemento cuyo ID es ‘Passwd'».

0811_03

Acto seguido, se mostrará el contenido del campo en texto plano.

0811_04

Es ahora tarea del usuario el ejecutar este código lejos de la vista de un posible mirón y, por supuesto, en un PC no comprometido… 😉

Variables de servidor en ASP.NET


Nuestro servidor ASP.NET aloja una gran cantidad de información útil que, en determinado momento, puede salvarnos de situaciones complejas. Este conjunto de variables puede consultarse mediante el objeto Request.ServerVariables[<NombreVariable>]. Así, si realizamos la siguiente consulta:

string navegador = Request.ServerVariable[&quot;HTTP_USER_AGENT&quot;];

La variable navegador alojará, como intuitivamente podremos imaginar, el navegador que está utilizando el cliente que se conecta a nuestro servidor, dato utilizado, por ejemplo, para estadísticas. En nuestro caso, el dato devuelto será el siguiente:

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)

Hay cantidad de variables de servidor cuya consulta puede hacernos la vida más fácil. Como ejemplo, indicaremos algunas de ellas:

VARIABLE SIGNIFICADO EJEMPLO
SERVER_PROTOCOL Protocolo de conexión HTTP/1.1
REMOTE_ADDR Dirección IP Remota 80.24.53.11
LOCAL_ADDR Direccion IP Local 127.0.0.1
PATH_INFO Ruta de la aplicación /MiAplicacion/Pagina.aspx
URL URL de la página /MiAplicacion/Pagina.aspx
AUTH_TYPE Tipo de autenticación Forms
SERVER_PORT Puerto HTTP 80
HTTP_USER_AGENT Navegador del usuario Mozilla/4.0 (compatible; MSIE 8.0;…
HTTP_HOST Nombre del host MyMachine
SERVER_NAME Nombre del servidor MyMachine
SERVER_SOFTWARE Servidor web Microsoft-IIS/6.0
APPL_PHYSICAL_PATH Ruta física de la aplicación C:\Inetpub\wwwroot\MiAplicacion\
HTTPS ¿Usa SSL? off
AUTH_USER Usuario autenticado administrador
REMOTE_USER Usuario remoto administrador
HTTP_CONNECTION Tipo de conexión HTTP Keep alive
HTTP_ACCEPT_LANGUAGE Idioma es

Existen más variables de servidor, y basta con recorrer con un bucle su contenido para echarle un vistazo a todas:


Hashtable hs = new Hashtable();

foreach (string s in Request.ServerVariables.AllKeys)
{
hs.Add(s, Request.ServerVariables[s]);
}

Enviar un e-mail desde .NET utilizando una cuenta SMTP de GMail


En mi proyecto de fin de carrera implementé un sistema automatizado de reservas que avisaba por e-mail del estado de las mismas. Para mi desgracia, olvidé mencionarlo durante la defensa, por lo que a nivel institucional fue una pérdida de tiempo, pero no así a nivel didáctico (que es, a fin de cuentas, lo importante).

Para implementarlo, utilicé los espacios de nombres System.Net y System.Net.Mail y una cuenta de Gmail a la que previamente le había activado el acceso POP/SMTP. Mandar un mail desde .NET es relativamente sencillo.

Si pensamos en la composición de un mail en términos de objetos, veremos que en realidad, enviar un mail es muy, pero que muy sencillo. Imaginemos que tenemos una cuenta en Gmail, por ejemplo ‘estoesunapruebademail25@gmail.com‘, cuya contraseña es ‘inteligible43‘. Queremos mandar un correo. ¿Qué información necesitamos?

  • Un mensaje, que implementará la clase MailMessage.
  • Un cliente de correo (SmtpClient) que se encargue de la autenticación y envío del mensaje.

A su vez, el mensaje necesitará:

  • Uno o varios destinatarios.
  • Un remitente.
  • Un asunto (subject).
  • El texto del mensaje.

Mientras que el cliente del correo necesitará saber:

  • Servidor SMTP al que conectarse y puerto.
  • Nombre de usuario y contraseña.

(más…)

Almacenamiento y recuperación de parámetros en Sesión y ViewState


Muchas veces necesitamos utilizar parámetros entre distintos métodos de un mismo formulario web, o incluso entre formularios distintos. Una forma dinámica de realizar este intercambio de datos es la utilización del ViewState y del espacio de sesión.

Antes de embarcarnos a almacenar datos y datos en estos dos espacios de memoria, hay que dejar claras dos cosas:

  • El ViewState se intercambia continuamente entre cliente y servidor, por lo que es aconsejable no sobrecargarlo. Al aumentar el ViewState, aumentará el tamaño de la página, y por consiguiente, el tráfico de datos y la velocidad de carga de la misma.
  • La sesión se almacena en servidor, por lo que si nuestro sitio web posee una carga de datos moderada – alta, el rendimiento del mismo se verá penalizado. Nuevamente, es aconsejable utilizar con cautela este espacio de memoria.

Teniendo claros estos dos conceptos, utilizaremos el ViewState para almacenar datos locales (de una misma página) y la sesión para pasar parámetros entre distintas páginas sin hacer uso de la QueryString. Para los profanos en la materia, explicaremos que la QueryString es la colección de parámetros que pueden, opcionalmente, acompañar a la dirección de la página. Éstos parámetros ofrecen información directamente recopilable por nuestro formulario web, pero cuenta con la desventaja de que es visible para el usuario.

(más…)

Obtener el identificador de un registro recien insertado en SQL Server


Cuando insertamos un registro en una tabla en la que su Identificador es único y autoincrementable, podemos solicitar a la base de datos que nos devuelva ese ID en concreto para realizar o encadenar nuevas operaciones. Ese ID se obtiene llamando a la función SCOPE_IDENTITY() de T-SQL.

Así, si almacenamos la siguiente sentencia en una cadena de texto:

string sentenciaSQL = &quot;INSERT INTO USUARIOS(Nombre, Apellidos, NIF, Login, Password) VALUES('Alberto' 'Lopez Villarino', '12345678Z', 'alopezv', '7EVASGEAGE9='); SELECT SCOPE_IDENTITY();&quot;;

Al invocar al método ExecuteScalar() de un objeto de la clase SqlCommand utilizando la sentencia anterior, el valor devuelto será, precisamente, el ID del registro insertado.

Transacciones en ADO.NET (II): Activando las Transacciones Distribuidas mediante MSDTC


Anteriormente hemos aprendido a utilizar entornos transaccionales o Transaction Scopes. El ejemplo anterior mostraba lo que se conoce como una ‘transacción ligera’ que afecta a varias tablas de una misma fuente de datos. Sin embargo, en numerosas ocasiones se nos presentará la dificultad añadida de trabajar con múltiples fuentes de datos localizadas incluso en puntos geográficos diversos.

Para solventar esta dificultad, el propio Windows nos ofrece la posibilidad de utilizar las llamadas Transacciones distribuidas. Por defecto aparecen deshabilitadas, por lo que a continuación, mostraremos cómo activarlas. Una vez activadas, utilizaremos la clase TransactionScope como si se tratara de una transacción ligera, dejando en manos del sistema operativoel control de la propia transacción.

(más…)

Transacciones en ADO.NET (I): La clase TransactionScope


Hay determinadas ocasiones en las que se nos presenta la obligación de realizar inserciones, eliminaciones o actualizaciones en una base de datos en la cual los datos que se van a tocar están relacionados entre sí. Imaginemos la siguiente situación: nuestro cliente regenta un concesionario, y un cliente desea adquirir un vehículo. Tras rellenar el papeleo pertinente, la venta toca a su fin, y necesitamos realizar una serie de operaciones, tales como:

  • Enviar la orden de cobro al banco.
  • Enviar a Tráfico los datos de nuestro cliente para el registro del mismo.
  • Almacenar los datos de nuestro cliente en la base de datos de la empresa.

Imaginemos por un momento que una de estas operaciones falla, por ejemplo, la segunda: la orden al banco ya habrá sido cursada, mientras que tráfico y el concesionario no tendrán notificación alguna de la titularidad del vehículo. Los datos se encontrarían, pues, en un estado inconsistente. Para evitar este tipo de situaciones recurrimos a las transacciones. Una transacción es un conjunto de operaciones sobre una o varias fuentes de datos, con la peculiaridad de que o se ejecutan todas correctamente, o no se ejecuta ninguna. Una transacción se caracteriza por cumplir las llamadas propiedades ACID, que identifican los requisitos para que una transacción se realice. Estas propiedades son: atomicidad (Atomicity), coherencia (Consistency), aislamiento (Isolation) y permanencia (Durability). Así, en el ejemplo anterior, si la conexión con la base de datos de Tráfico devuelve un error, se revertirán los cambios realizados en la conexión con el banco, dejando la transacción en el estado inicial. Es lo que llamamos un ROLLBACK o «vuelta atrás». En el caso de que todo haya ido correctamente, procederíamos a «comprometer» la transacción, ejecutando todas las operaciones por las que ésta se componga. Es lo que llamamos COMMIT. Vista la introducción teórica ¿cómo implementamos una transacción en ADO.NET? Personalmente me gusta implementar las transacciones mediante entornos transaccionales o transactional scopes, implementados mediante la clase System.Transactions.TransactionScope. Lo primero que deberemos hacer será añadir una referencia a la biblioteca System.Transactions.

090701st

Hecho esto, mediante la cláusula using crearemos un entorno transaccional en el que encerraremos un bloque try/catch. En el interior del try será donde implementemos la lógica de acceso a datos, realizando múltiples consultas/inserciones/eliminaciones/actualizaciones. Si se produce un error, el flujo de control saltará al bloque catch, donde se interrumpirá la transacción y se realizará un ROLLBACK automático. Si no se produce ningún error, se llegará a la cláusula Complete() de la transacción, la cual comprometerá la misma y dejará la fuente de datos en un estado consistente. En C# sería algo como lo que sigue, suponiendo que la lógica de acceso a datos está encapsulada en los métodos del objeto DAO y que ‘listaElementos’ es un array de enteros que contiene identificadores de la tabla a modificar:

using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
{
try
{
foreach (int id in listaElementos)
{
dao.OrdenarEnvioCuentaBancaria(id, numeroCuenta, datosCliente);
dao.RegistrarVehiculoEnTrafico(id, matricula, datosCliente);
dao.GuardarDatosCompraCliente(id, matricula, datosCliente, fechaActual);
}
scope.Complete();
}
catch (Exception ex)
{
throw (ex);
}
}

Esto nos permitirá realizar transacciones de forma segura. Pero ¡ojo! ¿y si lo que queremos realizar son operaciones sobre distintas fuentes de datos? Para ello necesitaremos activar las transacciones distribuidas, que por defecto aparecen deshabilitadas. En un artículo posterior aprenderemos cómo activarlas.

Servicios Web (II): Consumiendo un servicio web


Veíamos anteriormente cómo crear un servicio web simple. A continuación veremos cómo consumirlo.

Si crear un WebService no tiene demasiada dificultad, consumirlo es, si cabe, mucho más sencillo. Crearemos una aplicación web normal y corriente, y sobre ésta, haremos click derecho y seleccionaremos la opción [Agregar Referencia Web…]

0906agregarreferenciaweb
Hecho esto, se desplegará un menú que nos permitirá la detección de servicios web. Si introducimos la dirección en la que el servicio está publicado y pulsamos en «Ir» se nos mostrará los métodos que el servicio expone. En la caja de texto derecha añadiremos el nombre que tendrá nuestra referencia (por ejemplo, ServicioSimple) y pulsaremos sobre [Agregar referencia].

0906servicio

Hecho esto, se agregará a nuestro proyecto una referencia a nuestro servicio web, que se mostrará en nuestro proyecto de la siguiente manera:

0906referencia

Finalmente, añadiremos controles a nuestra página para comprobar que nuestra aplicación se comunica perfectamente con el servicio web. Para ello crearemos un GridView, dos Label, una caja de Texto y tres botones.

En el primer botón codificaremos la funcionalidad para cargar el GridView con la primera tabla del DataSet devuelto por el método GetData() de nuestro servicio web. Para ello crearemos una referencia a nuestro servicio, crearemos una referencia a un DataSet e invocaremos el método GetData() del WebService. Finalmente rellenaremos el Grid con el resultado obtenido.

protected void ButtonGrid_Click(object sender, EventArgs e)
{
// Referenciamos el servicio
ServicioSimple.Service referenciaServicio = new ServicioSimple.Service();

// Creamos una referencia a un DataSet
DataSet ds;

// Invocamos el WebMethod GetData()
ds = referenciaServicio.GetData();

// Rellenamos el DataGrid
GridViewDatos.DataSource = ds.Tables[0];
GridViewDatos.DataBind();
}

En el segundo botón haremos que nuestro label muestre el resultado de la invocación al método GetDate(), que recordemos que devolvía la fecha actual.

protected void ButtonFecha_Click(object sender, EventArgs e)
{
// Referenciamos el servicio
ServicioSimple.Service referenciaServicio = new ServicioSimple.Service();

LabelFecha.Text = referenciaServicio.GetDate().ToString();
}

Por último, el tercer botón mostrará el resultado de invocar al método GetDateDiff(int). Para ello le pasaremos al WebService un parámetro que indicará el número de horas que tiene que añadir. Para ello utilizaremos la caja de texto.

protected void ButtonFechaDiff_Click(object sender, EventArgs e)
{
// Referenciamos el servicio
ServicioSimple.Service referenciaServicio = new ServicioSimple.Service();

if (!string.IsNullOrEmpty(TextBoxDiferencia.Text))
{
LabelFechaDiferencia.Text = referenciaServicio.GetDateDiff(Convert.ToInt32(TextBoxDiferencia.Text)).ToString();
}
}

Hecho. Ya hemos creado un servicio web y hemos aprendido a consumirlo.

0906resultado