Agenda telefónica en Internet

A menudo necesitamos recordar números de teléfono. Tanto en casa como en el trabajo tenemos agendas de papel y en el teléfono móvil podemos llevar un número grande de contactos. Pero, en ocasiones, necesitamos consultar un número de teléfono que no está guardado en el teléfono móvil y tampoco tenemos a mano las agendas con nuestro listado telefónico. Contando con la facilidad para acceder a Internet desde casi cualquier sitio al que vayamos y con la potencia y facilidad de uso de Asp .NET, se propone la creación de una agenda telefónica, alojada en el servidor de nuestro proveedor de servicios de Internet, para acceder a ella desde cualquier lugar que tenga conexión a Internet.

En resumen, la aplicación propuesta consta de:

A continuación se comentan las características de cada una de las partes de que consta la aplicación, buscando ante todo que el texto sea comprensible por desarrolladores poco expertos. Esta aplicación ejemplifica la facilidad con que podemos crear aplicaciones complejas con la tecnología Asp .NET sin necesidad de ser programadores avanzados.

Apartados de que consta el texto:

 

VALIDACIÓN DE CONTROLES EN ASP .NET

Como programadores, sabemos que el usuario de un programa informático es impredecible en cuanto a lo que teclea. Por muy claras que nos parezcan las instrucciones y las opciones de una ventana de programa, es necesario saber si lo tecleado por el usario se adapta a lo esperado o no y, en caso de ser así, poder tomar acciones adecuadas que eviten el fallo de la aplicación. Se nos pueden ocurrir muchos ejemplos de ello pero, sin ir más lejos, podemos pensar en la petición del número de teléfono en donde el usuario teclea sólo letras, por lo que no se tratará de un número de teléfono válido.

Capturar lo tecleado por el usuario y comprobar si los datos proporcionados son correctos de acuerdo con la información solicitada es lo que llamamos validación. La tecnología Asp .NET nos proporciona una manera sencilla de validar lo tecleado por el usuario en los formularios Web. Recurre a controles de validación de varios tipos, capaces de realizar comprobaciones útiles como:

Estos controles llevan a cabo la validación (controles Validation) en el servidor. También es posible validar en el cliente gracias a código JavaScript y, en muchas ocasiones, ello puede ser válido para nuestros propósitos, pero la validación en el servidor es necesaria para tareas más complejas en las que la seguridad adquiere mayor importancia, y Asp .NET tiene un mecanismo sencillo para realizarla.

Los controles Validation de Asp .NET permiten:

Todos los controles Validation son controles Web, se ejecutan en el servidor y generan HTML que es enviado al cliente. La sintaxis básica es similar en todos ellos, aunque hay diferencias en las propiedades que admiten, según el tipo de control:

<asp:Nombre_de_Validator - (control Validation)
Runat="server"
ControlToValidate=
"Nombre_de_control"
- (control que es "vigilado" por el validator)
ErrorMessage=
"Texto informativo" />
- (texto del aviso de error)

Los tipos de controles Validation de que dispone Asp .NET son:

Es interesante remarcar que podemos usar etiquetas HTML en las cadenas de ErrorMessage con las posibilidades de personalización que ello conlleva.


Archivo 
WebUIValidation.js

Para que los controles Validation de Asp .NET funcionen, es necesario que exista en el servidor Web un archivo llamado WebUIValidation.js de JavaScript. Este archivo de secuencias de comando es generado de manera automática en la instalación de Asp .NET y ha de estar colocado en la ruta:

localhost/aspnet_client/system_web/nº_de_versión_de_Framework/WebUIValidation.js

 Si por algún motivo no existe ese fichero, puede ser copiado manualmente desde otro servidor que lo posea o generado de nuevo con la orden "aspnet_regiiis -c". WebUIValidation.js contiene todas las funciones de HTML dinámico (DHTML) requeridas para ejecutar en el cliente el código HTML de validación generado por el servido al compilar la página aspx.


Uso de los
controles Validation en este ejercicio

Creamos 2 controles TextButton de Asp .NET para escribir y confirmar en ellos la contraseña, ambos controles se configuran como texto de tipo contraseña para que no muestren los caracteres tecleados sino asteriscos:

<asp:TextBox id="txtPassword" TextMode="Password"
Width=
"120" Runat="server" MaxLength="10"
EnableViewState=
"True"></asp:TextBox>

<asp:TextBox id="txtConfirmar" TextMode="Password"
Width=
"120" Runat="server" MaxLength="10"
EnableViewState=
"True"></asp:TextBox>


Creamos 2 controles RequiredFieldValidator (para comprobar si el usuario escribe algo en ambos campos de contraseña):

<asp:RequiredFieldValidator ID="valPassword1" Runat="server"
ControlToValidate="
txtPassword" EnableClientScript="True" Display="None"
ErrorMessage=
"<br><div align=center><b>Contraseña</b> es un campo obligatorio.</div>" />

<asp:RequiredFieldValidator ID="valConfirmar" Runat="server"
ControlToValidate="
txtConfirmar" EnableClientScript="True" Display="None"
ErrorMessage=
"<br><div align=center><b>Confirmar contraseña</b> es un campo obligatorio.</div>" />

También creamos un control CompareValidator para comparar el campo txtContraseña con un valor constante (xxx en este ejercicio) y creamos otro control CompareValidator que comprueba si el contenido de ambas cajas de texto es idéntico:

<asp:CompareValidator ID="valPassword2" Runat="server" ControlToValidate="txtPassword"
ValueToCompare=
"xxx" Operator="Equal" EnableClientScript="True" Display="None"
ErrorMessage=
"<br><div align=center><b>Contraseña</b> no válida.</div>" />

<asp:CompareValidator
id="valComparar" ControlToValidate="txtConfirmar" Runat="server"
ControlToCompare=
"txtPassword" Display="None" EnableClientScript="true"
ErrorMessage=
"<br><div align=center>Ambas contraseñas deben <b>coincidir</b>.</div>" />

Por último, creamos un control ValidationSummary que configura el resumen de la validación y la manera de mostrar los mensajes de error producidos. Esta etiqueta permite elegir el formato del resumen con las propiedades:

<asp:ValidationSummary runat="server" DisplayMode="SingleParagraph"  ID="valSumario"
ShowSummary=
"True" ShowMessageBox="False" Font-Size="10pt" Font-Names="Verdana"
HeaderText=
"<div align=center><u>Se han encontrado los siguientes errores</u>: </div>" />


Asp .NET tiene mecanismos para guardar lo capturado en los controles del formulario durante la sesión. Si queremos que lo esrito en las cajas de texto permanezca en ellas aún después de pulsar el botón que envía los datos, debemos configurar la propiedad EnableViewState de los controles TextBox a True, en caso contrario las cajas de texto se vaciarán cada vez que pulsemos el botón.
 

Código Visual Basic .NET (bloque de declaración de código)

Por último, hay que desarrollar el método de Visual basic .NET que, al pulsar el botón que envía al servidor los datos del formulario, comprueba si la validación ha sido correcta o han surgido errores, para enviarnos a la página web deseada sólo en el primer caso. Este código lo colocamos en la cabecera del documento aspx (se trata, pues, de un bloque de declaración de código). Tenemos una manera muy sencilla de saber si lo capturado desde el formulario cumple las condiciones de validación, mediante la propiedad IsValid del objeto Page, que devuelve True si no ha habido errores. Para enviar al usuario a la página requerida, usamos el método Response.Redirect, que puede llevarnos a una página html o aspx, a diferencia del método Server.Transfer que sólo puede llevarnos a una página aspx:

<%@ Page Language="vb" %>

<script runat="server">
Sub pasar (obj As Object, e As EventArgs)
    If Page.IsValid Then
        Response.Redirect("clikear4.aspx")
    End If
End Sub

</script>

Y, en la etiqueta del botón que envía los datos, añadimos en la propiedad onclick el nombre del método:

<asp:Button ID="cmdEnviar" CausesValidation="True" Runat="server" Text="Enviar datos" OnClick="pasar"></asp:Button>



Código completo de la página aspx de validación de contraseña

<%@ Page Language="VB" %>
 
<SCRIPT runat="server">
Sub pasar (obj As Object, e As EventArgs)
    If Page.IsValid Then
    'Server.Transfer("clikear4.aspx")
    Response.Redirect("clikear4.aspx"")
    End If
End Sub

</SCRIPT>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
    <head>
        <title>Validar contraseña</title>
        <meta name="GENERATOR" content="Microsoft FrontPage 6.0">
        <meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
        <meta name="Author" content="Miliuco">
</head>
    <body>
        <div align="center">
            <h2><font face="Verdana">Sitio restringido</font></h2>
           <FORM id="Form1" method="post" runat="server">
                <table>
                    <tr width="120">
                        <td width="140"><font face="Verdana" size="2">Contraseña:</font></td>
                        <td>
                        <asp:TextBox id="txtPassword" TextMode="Password" Width="120" Runat="server" MaxLength="10" EnableViewState="True" />
                        </td>
                    </tr>
                    <tr width="120">
                        <td width="140"><font face="Verdana" size="2">Repetir contraseña:</font></td>
                        <td>
                        <asp:TextBox id="txtConfirmar" TextMode="Password" Width="120" Runat="server" MaxLength="10" EnableViewState="True" />
                        </td>
                    </tr>
                </table>
                 <br>
                <asp:Button ID="cmdEnviar" CausesValidation="True" Runat="server" Text="Enviar datos" OnClick="pasar" />
                <br><br>
                <asp:RequiredFieldValidator ID="valPassword1" Runat="server" ControlToValidate="txtPassword" EnableClientScript="True" Display="None" 
ErrorMessage=
"
<br><div align=center><b>Contraseña</b> es un campo obligatorio.</div>" />    
                <asp:CompareValidator ID="valPassword2" Runat="server" ControlToValidate="txtPassword" ValueToCompare="xxx" Operator="Equal" EnableClientScript="True" Display="None" ErrorMessage="<br><div align=center><b>Contraseña</b> no válida.</div>"
/>            
             <asp:RequiredFieldValidator id="valConfirmar" ControlToValidate="txtConfirmar" EnableClientScript="true" Display="None" Runat="server" ErrorMessage="<br><div align=center><b>Repetir contraseña</b> es un campo obligatorio.</div>" />                
             <asp:CompareValidator id="valComparar" ControlToValidate="txtConfirmar" ControlToCompare="txtPassword" Display="None" EnableClientScript="true" ErrorMessage="<br><div align=center>Ambas contraseñas deben <b>coincidir</b>.</div>" Runat="server" />
                <br>
             <asp:ValidationSummary runat="server" DisplayMode="SingleParagraph" ShowSummary="True" ShowMessageBox="False" ID="valSumario" HeaderText="<div align=center><u>Se han encontrado los siguientes errores</u>: </div>" Font-Size="10pt" Font-Names="Verdana" />
            </div>
            </FORM >
        </body>
</HTML>

 

ARCHIVO XML COMO ORIGEN DE DATOS.
CONTROL DATAGRID EDITABLE POR EL USUARIO

 
El control DataGrid puede conectar con bases de datos usando las clases de Ado .NET pero también puede leer los datos desde un archivo XML, de texto plano y fácilmente accesible desde cualquier editor de texto o navegador de Internet, con las ventajas que éso conlleva frente a formatos propietarios de bases de datos.


Ventajas de XML como origen de datos del DataGrid

Almacenar datos en formato XML tiene algunas ventajas destacadas:
  • no dependemos de etiquetas preestablecidas, como sucede con HTML, sino que podemos crear nuestras propias etiquetas y, si el archivo cumple el estándar XML, serán reconocidas.

  • como el formato XML se basa en texto plano, se evita la necesidad de tener instalados los programas que entienden formatos específicos de bases de datos. XML es fácilmente portable entre almacenes de datos diferentes y distintas plataformas.

  • al tratarse de texto plano, es capaz de penetrar los cortafuegos , evitando problemas de seguridad que aparecen al abrir paso a otros tipos de archivos capaces de causar daños.


Mostrar los datos XML en el DataGrid

Los datos que están guardados en formato XML pueden ser manipulados usando las clases del espacio de nombres System.Xml, sobre todo XmlTxtReader y XmlTextWriter pero, en una aplicación sencilla como ésta, en la que simplemente necesitamos una forma simple de leer y escribir en el archivo XML sin recurrir a las grandes potencialidades de las clases de System.Xml, nos basta con métodos de la propia clase DataSet:

  • DataSet.ReadXml(Fuente_XML)
  • DataSet.WriteXml(Fuente_XML)

Podemos disponer de estos métodos sin necesidad de importar el espacio de nombres System.Xml. Para generar el DataSet y rellenarlo desde el archivo XML usamos este código:

'Variable para contener el nombre del archivo XML y su ruta
Public sourceXML As String = Server.MapPath("agenda2big.xml")

'Creación del DataSet por código
    Protected Function dsDatos() As DataSet
        'Si no se encuentra el archivo XML, avisar
        If (Not File.Exists(sourceXML)) Then
            ErrorMessage.Text =
"<font size=4>No se encuentra el archivo XML en la ruta prevista." & _
            "<br><br>Revisa la localización del archivo origen XML.</font>"

            lbNew.Visible = False
            Return Nothing
        End If
        'Generar una instancia de DataSet   
        Dim dsDatos2 As DataSet = New DataSet
        Try
            'Rellenar el DataSet desde el archivo XML
            dsDatos2.ReadXml(sourceXML)
            'Contar el número de filas de la tabla para mostrar información al usuario
            Dim n As Integer
            n = dsDatos2.Tables(0).Rows.Count
            Label2.Text = "Número de registros en el DataGrid: " & "<b>" & n & "</b>"
            'Si hay algún error al cargar el DataSet
        Catch pollo As Exception
            ErrorMessage.Text = pollo.Message
            dsDatos2 = Nothing
        End Try
        'Devolver la instancia de DataSet generada
        Return dsDatos2
    End Function

Para rellenar el DataGrid desde el Dataset usamos este código al cargar la página (asignamos el DataSet a la propiedad DataSource del DataGrid y realizamos el enlace de datos a controles mediante DataBinding):

    'Al cargar la página, se rellena el DataGrid
    'Las páginas aspx tienen una propiedad IsPostBack que informa si el formulario Web
    'ha sido enviado al servidor. La sentencia "If Not Page.IsPostBack" se refiere a si es
    'el primer acceso a la página aspx, en ese caso se rellena el DataGrid desde el DataSet.
    'IsPostBack solo es true si la página se carga como respuesta a un valor devuelto por 
    'el cliente; en caso contrario, es false
    Sub Page_Load(ByVal Sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        'Rejilla es el DataGrid que rellenamos
        'dsDatos es la función que devuelve un objeto DataSet (dsDatos2)
        If Not Page.IsPostBack Then
            rejilla.DataSource = dsDatos()
            rejilla.DataBind()
        End If
    End Sub
 

Modificación de los registros del DataGrid   

Cuando necesitemos modificar los datos mientras estamos conectados a ellos, tenemos 2 maneras principales de hacerlo:

  • usar BoundColumn que, por defecto, es el único tipo de columna capaz de cambiar a campos modificables. El otro tipo de columna usada para contener registros en el DataGrid es TemplateColumn, que mantiene su aspecto original. Con este método se pierde control al interpretar los campos de la tabla (ej: los cuadros de texto pueden ser mucho más largos que la celda que los contiene).

  • usar cuadros de texto (asp:TextBox ) dentro de elementos EditItemTemplate incluidos en columnas TemplateColumn. De esta manera hay menos eventos que vigilar y se tiene mayor control sobre las características del DataGrid.

    En este ejercicio se ha elegido la segunda manera:

<asp:TemplateColumn HeaderText="Nombre">
 <HeaderStyle
Width="300px" HorizontalAlign="Left"
></HeaderStyle>
  <ItemTemplate>
  
<%# Container.DataItem("Nombre") %>

  </ItemTemplate>
  <EditItemTemplate>
   <asp:TextBox
id="txtNombre" Width="295px"
        Text=
'<%# Container.DataItem("Nombre")%>' runat="server"
/>
  </EditItemTemplate>
</asp:TemplateColumn>


    Las columnas del DataGrid que contienen los enlaces a los métodos de edición de registros son diferentes, en este ejercicio se han empleado asp:LinkButton en las que se definen los comandos Edit, Delete, Cancel y Update:

<asp:TemplateColumn>
 <ItemTemplate>
  <asp:LinkButton
CommandName="Edit" Text="Editar" runat="server" ID="btEdit" />
  <asp:LinkButton
CommandName="Delete" Text="Borrar" runat="server" ID="btDelete"
/>
 </ItemTemplate>
 <EditItemTemplate>
  <asp:LinkButton
CommandName="Cancel" Text="Cancelar" runat="server" ID="btCancel"
/>
  <asp:LinkButton
CommandName="Update" Text="Actualizar" runat=server" ID="btUpdate"
/>
 </EditItemTemplate>
</asp:TemplateColumn>


    El nombre de los métodos que se ejecutarán en cada uno de estos comandos se define en la etiqueta
asp:DataGrid

<asp:DataGrid OnDeleteCommand="cmDelete" OnCancelCommand="cmCancel" OnUpdateCommand="cmUpdate" OnEditCommand="cmEdit">

Después hay que definir en el código Visual Basic cada uno de estos métodos, como ejemplo, vemos el que activa el modo de edición cmEdit:

'Procedimiento al pulsar el botón EDITAR del control DataGrid
'Este controlador para el evento cmEdit (evento del tipo EditCommand)
'establece la propiedad EditItemIndex en la fila seleccionada

Sub cmEdit(ByVal Sender As Object, ByVal e As DataGridCommandEventArgs)
'Editar el elemento cuyo índice coincide con el de la fila elegida
rejilla.EditItemIndex = CInt(e.Item.ItemIndex)
'Enlazar de nuevo los datos al control DataGrid
rejilla.DataSource = dsDatos()
rejilla.DataBind()
End Sub

    O el que activa el modo de edición cmDelete :

'Procedimiento al pulsar el botón BORRAR
Sub cmDelete(Sender As Object, e As DataGridCommandEventArgs)
'Generar una instancia de DataSet
Dim dsDatos2 As DataSet = dsDatos()
'Entero que contiene el índice de la fila seleccionada
Dim fila As Integer = CInt(e.Item.ItemIndex)
'Eliminar la fila seleccionada
dsDatos2.Tables(0).Rows(fila).Delete()
'Escribir el contenido del DataSet en el archivo XML
dsDatos2.WriteXml(Server.MapPath("agenda2big.xml"))
'Quitar el modo de edición a la fila seleccionada:
'EditItemIndex igual a -1 desactiva el modo de edición
rejilla.EditItemIndex = -1
'Enlazar de nuevo los datos al control DataGrid
rejilla.DataSource = dsDatos()
rejilla.DataBind()
End Sub


Problemas de seguridad al generar la página aspx con el DataGrid

Si al generar la página dinámica aspx aparece un error de compilación relacionado con un mensaje del tipo: "Exception Details: System.UnauthorizedAccessException: El acceso a la ruta "ruta_al_archivo_xml" ha sido denegado. Asp .NET no está autorizado a acceder al recurso solicitado..." posiblemente la carpeta en que se encuentra el archivo XML no tenga concedidos por IIS permisos de escritura (se soluciona fácilmente configurando los permisos de IIS con la herramienta %SystemRoot%\System32\Inetsrv\iis.msc y añadiendo permisos de escritura a ese directorio haciendo clic con el botón derecho sobre él y entrando en la pestaña Directorio).

Si con ello el error no desaparece, entonces lo más probable sea que la carpeta que contiene el archivo XML no tenga, entre los grupos de usuarios que tienen permiso para acceder a ella, el grupo Nombre_de_máquina/ASP .NET (ASP.NET Machine Account) o, en caso de tenerlo, este grupo ASP .NET no tenga concedidos los permisos adecuados de modificación y escritura, en cualquiera de los 2 casos hay que entrar en la configuración de seguridad de la carpeta (clic con el botón derecho sobre la carpeta, elegir Propiedades y seleccionar la pestaña Seguridad para añadir o modificar el grupo apropiado, remarcar la cuenta ASP .NET y marcar las casillas de verificación deseadas).

Para los usuarios de Windows XP Home, conviene recordar que la pestaña Seguridad de las carpetas y archivos sólo está disponible si se entra en el sistema en modo seguro, para ello hay que pulsar F8 justo antes de que se inicie el arranque de Windows y elegir Modo seguro en el menú que se muesta en pantalla.
 

NOTA: Para que el código sea más legible se ha separado en 2 archivos, la página aspx contiene el código HTML - Asp.NET y un archivo externo vb contiene el código Visual Basic (código de apoyo). Puedes consultar unas instrucciones muy simples sobre éste y otros temas de Asp .NET relacionados con esta aplicación aquí.