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["HTTP_USER_AGENT"];

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]);
}

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:

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.

Read the rest of this post »

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

Servicios Web (I): Creando un servicio web simple

Un servicio web no es más que un conjunto de protocolos y estándares cuyo objetivo es el intercambio de información entre distintas aplicaciones. Los servicios web tienen la peculiaridad de ser independientes de plataforma, es decir, cumplen estándares propios y no dependen ni del hardware sobre el que se ejecuta ni del sistema operativo o servidor web que lo aloja.

Un servicio web intercambia información. Al invocar un servicio web estamos realizando una petición a otra máquina, a la que (opcionalmente) le enviamos información, la procesa y nos devuelve una respuesta, generalmente atómica y serializable, es decir: lo común es que un servicio web nos devuelva un dato o estructura de datos con la información que necesitemos (atómica) en forma de cadena de texto (serializable). Esto es así por el lenguaje común que “hablan” los servicios web: XML.

Si quisiéramos crear un servicio web, en una solución en blanco pulsaríamos sobre Agregar > Nuevo sitio Web…

0906servicioweb01
Hecho esto, seleccionaremos la plantilla “Servicio Web ASP.NET”, y alojaremos el servicio web en nuestro IIS indicándole la ruta que deseemos.

0906servicioweb02
A continuación, crearemos los métodos que queramos exponer, añadiendo el atributo [WebService] a la clase y el atributo [WebMethod] a los métodos que deban ser expuestos.

Crearemos tres métodos: uno que devuelva la hora actual, otro que devuelva nuestra localización geográfica y otro que añada las horas pasadas como parámetro a la hora actual.

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://localhost/Services/Date")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () {

//Eliminar la marca de comentario de la línea siguiente si utiliza los componentes diseñados
//InitializeComponent();
}

[WebMethod]
public DateTime GetDate() {
return DateTime.Now;
}

[WebMethod]
public string GetLocation()
{
return "UTC/GMT +2, Madrid, Spain.";
}

[WebMethod]
public DateTime GetDateDiff(int horasDiferencia)
{
return DateTime.Now.AddHours(horasDiferencia);
}

}

Hecho esto, iremos a la dirección de nuestro servicio web, lo cual nos mostrará lo siguiente:
0906servicioweb03
Para probar el servicio web, haremos click sobre cualquiera de los métodos expuestos. Si el webservice no requiere ningún parámetro, se nos mostrará directamente el resultado de la invocación:

0906servicioweb05
En caso contrario, se nos pedirá que introduzcamos el parámetro requerido, lo cual nos llevará a la obtención del dato.

0906servicioweb04
Si analizamos el contenido de la respuesta, comprobaremos que, efectivamente, se trata de un fichero XML.

<?xml version="1.0" encoding="utf-8"?>
<dateTime xmlns="http://localhost/Services/Date">2009-06-09T17:27:00.0874935+02:00</dateTime>

Posteriormente comprobaremos cómo realizar una invocación a un servicio web desde nuestra aplicación.

Añadiendo un TemplateField a un GridView de forma dinámica

La mayor parte de los sitios web que se sirven de listados lo hacen utilizando un esquema como el que sigue:

090501Grid
Como vemos, lo normal suele ser utilizar campos enlazados a la consulta (BoundFields), así como campos-plantilla (TemplateFields) con los que se suele interactuar con el listado (ver detalles, edición, etc.).

Si sabemos de antemano qué datos vamos a obtener, es sencillo “maquetar” nuestro GridView de forma sencilla. El problema radica en el momento en el que el número de columnas que nuestro GridView mostrará sea variable. En este caso, el atributo AutoGenerateColumns deberá ser puesto a True, con lo que perderemos el control del orden de los TemplateFields.

Veamos el siguiente caso: queremos un campo plantilla que muestre un LinkButton que nos permita editar el registro, y otro que nos permita visualizar los detalles del mismo. Queremos uno de estos campos en la primera columna (el de edición) y otro en la última (visualización). Si utilizamos TemplateFields con el atributo AutoGenerateColumns=”True”, lo que lograremos será que ambos botones se sitúen juntos en las dos primeras columnas de nuestro GridView. ¿Cómo hacer que uno de ellos se coloque al final? Añadiéndolo de forma dinámica.

Para comenzar, añadiremos un GridView con un TemplateField conteniendo un LinkButton, colocando el atributo AutogenerateColumns=”True”.

090502Grid
El templatefield contendría un LinkButton:

090503Grid

El resultado sería este:

090504Grid

Seguidamente, acudiremos a nuestro código, listos para editar el evento RowDataBound. En él haremos lo siguiente:

Para ello utilizaremos el siguiente código:


Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
Try

    ' Si se trata de una fila de datos...
    If e.Row.RowType = DataControlRowType.DataRow Then
        Dim celda As New TableCell()
        Dim boton As New LinkButton()

        boton.Text = "Detalles"
        If e.Row.Cells.Count > 1 Then
            boton.CommandArgument = GridView1.DataKeys(e.Row.RowIndex).Value.ToString()
        End If

        ' Añadimos el LinkButton a la celda, y la celda a la fila
        celda.Controls.Add(boton)
        e.Row.Controls.Add(celda)
    End If
Catch ex As Exception
    Throw ex
End Try
End Sub

Con esto lograremos el buscado esquema [Botón] [CAMPOS] [Botón].