3. Introducción al desarrollo web ASP.NET
3.1. Introduction
En el capítulo anterior se han presentado los principios del desarrollo web, que son independientes del lenguaje de programación utilizado. En la actualidad, tres tecnologías dominan el mercado del desarrollo web:
- J2EE, que es una plataforma de desarrollo Java. Asociada a la tecnología Struts, instalada en distintos servidores de aplicaciones, la plataforma J2EE se utiliza principalmente en grandes proyectos. Debido al lenguaje utilizado —Java—, una aplicación J2EE puede funcionar en los principales sistemas operativos (Windows, Unix, Linux, Mac OS, etc.).
- PHP, que es un lenguaje interpretado, también independiente del sistema operativo. A diferencia de Java, no es un lenguaje orientado a objetos. Sin embargo, la versión PHP5 debería introducir los objetos en el lenguaje. De fácil acceso, PHP se utiliza ampliamente en proyectos pequeños y medianos.
- ASP.NET es una tecnología que solo funciona en equipos Windows que dispongan de la plataforma .NET (XP, 2000, 2003, ...). El lenguaje de desarrollo utilizado puede ser cualquier lenguaje compatible con .NET, c.a.d. Hay más de una decena, empezando por los lenguajes de Microsoft (C#, VB.NET, J#), Delphi de Borland, Perl, Python, etc.
En el capítulo anterior se han presentado breves ejemplos de cada una de estas tres tecnologías. Este documento se centra en el desarrollo web ASP.NET con el lenguaje VB.NET. Damos por hecho que se conoce este lenguaje. Este punto es importante. Aquí nos centramos únicamente en su uso en el contexto del desarrollo web. Aclaremos este punto con más detalle hablando de la metodología MVC de desarrollo web.
Una aplicación web que respete el modelo MVC tendrá la siguiente arquitectura:

Esta arquitectura, denominada de tres capas o de tres niveles, pretende ajustarse al modelo MVC (Model View Controller):
- la interfaz de usuario es la V (la vista)
- la lógica de la aplicación es el C (el controlador)
- las fuentes de datos son el M (modelo)
La interfaz de usuario suele ser un navegador web, pero también podría ser una aplicación autónoma que, a través de la red, enviara solicitudes HTTP al servicio web y diera formato a los resultados que este le enviara. La lógica de la aplicación está formada por los scripts que procesan las solicitudes del usuario. La fuente de datos suele ser una base de datos, pero también pueden ser simples archivos planos, un directorio LDAP, un servicio web remoto, etc. Al desarrollador le conviene mantener una gran independencia entre estas tres entidades, de modo que, si una de ellas cambia, las otras dos no tengan que cambiar, o lo hagan en menor medida.
- La lógica de negocio de la aplicación se colocará en clases separadas de la clase que controla el diálogo de solicitud-respuesta. Así, el bloque [Logique applicative] anterior podría estar compuesto por los siguientes elementos:

En el bloque [Logique Applicative], se podrá distinguir
- la clase controladora, que es la puerta de entrada a la aplicación,
- el bloque [Classes métier], que agrupa las clases necesarias para la lógica de la aplicación. Son independientes del cliente.
- el bloque [Classes d'accès aux données], que agrupa las clases necesarias para obtener los datos que necesita el servlet, a menudo datos persistentes (BD, archivos, servicio WEB, etc.)
- el bloque de páginas ASP, que constituye las vistas de la aplicación.
En los casos sencillos, la lógica de la aplicación suele reducirse a dos clases:
- la clase controladora, que se encarga del diálogo entre el cliente y el servidor: procesamiento de la solicitud, generación de las distintas respuestas
- la clase de negocio, que recibe del controlador los datos que debe procesar y le proporciona a su vez los resultados. Esta clase de negocio gestiona entonces por sí misma el acceso a los datos persistentes.
La particularidad del desarrollo web radica en la escritura de la clase controladora y de las páginas de presentación. Las clases de negocio y de acceso a datos son clases .NET clásicas que pueden utilizarse tanto en una aplicación web como en una aplicación de Windows o incluso de tipo consola. La escritura de estas clases requiere un buen conocimiento de la programación orientada a objetos. En este documento, se escribirán en VB.NET, por lo que damos por hecho que se domina este lenguaje. Desde esta perspectiva, no es necesario extenderse más de lo necesario sobre el código de acceso a los datos. En la casi totalidad de los libros sobre ASP.NET, se dedica un capítulo a ADO.NET. El esquema anterior muestra que el acceso a los datos se realiza mediante clases .NET totalmente clásicas que ignoran que se utilizan en un contexto web. El controlador, que es el jefe de equipo de la aplicación web, no tiene que preocuparse por ADO.NET. Solo tiene que saber a qué clase debe solicitar los datos que necesita y cómo solicitarlos. Eso es todo. Incluir código ADO.NET en el controlador no se ajusta al concepto MVC explicado anteriormente y no lo haremos.
3.2. Las herramientas
Este documento está dirigido a estudiantes, por lo que trabajaremos con herramientas gratuitas que se pueden descargar de Internet:
- la plataforma .NET (compiladores, documentación)
- el entorno de desarrollo WebMatrix, que incluye el servidor web Cassini
- diferentes SGBD (MSDE, MySQL)
Se recomienda al lector que consulte el anexo «Herramientas web», donde se indica dónde encontrar y cómo instalar estas diferentes herramientas. En la mayoría de los casos, solo necesitaremos tres herramientas:
- un editor de texto para escribir las aplicaciones web.
- una herramienta de desarrollo VB.NET para escribir el código VB cuando este sea extenso. Este tipo de herramienta suele ofrecer ayuda para la introducción de código (autocompletado) y la detección de errores sintácticos, ya sea al escribir el código o durante la compilación.
- Un servidor web para probar las aplicaciones web creadas. En este documento se utilizará Cassini. El lector que disponga del servidor IIS podrá sustituir Cassini por IIS. Ambos son compatibles con .NET. Sin embargo, Cassini está limitado a responder únicamente a solicitudes locales (localhost), mientras que IIS puede responder a solicitudes de equipos externos.
Un excelente entorno comercial para desarrollar en VB.NET es Visual Studio.NET de Microsoft. Este IDE, muy completo, permite gestionar todo tipo de documentos (código VB.NET, documentos HTML, XML, hojas de estilo, etc.). A la hora de escribir código, ofrece la valiosa ayuda de la «autocompletación» automática. Dicho esto, esta herramienta, que mejora notablemente la productividad del desarrollador, tiene el inconveniente de sus propias ventajas: encasilla al desarrollador en un modo de desarrollo estándar que, aunque eficaz, no siempre resulta adecuado.
Es posible utilizar el servidor Cassini fuera de [WebMatrix] y es lo que haremos a menudo. El ejecutable del servidor se encuentra en <WebMatrix>\<versión>\WebServer.exe, donde <WebMatrix> es el directorio de instalación de [WebMatrix] y <versión> su número de versión:

Abramos una ventana de DOS y accedamos a la carpeta del servidor Cassini:
E:\Program Files\Microsoft ASP.NET Web Matrix\v0.6.812>dir
...
29/05/2003 11:00 53 248 WebServer.exe
...
Ejecutemos [WebServer.exe] sin parámetros:

El panel anterior nos indica que la aplicación [WebServer/Cassini] admite tres parámetros:
- /port: número de puerto del servicio web. Puede ser cualquiera. Por defecto, el valor es 80
- /path: ruta física de una carpeta del disco
- /vpath: carpeta virtual asociada a la carpeta física anterior.
Colocaremos nuestros ejemplos en un árbol de archivos con raíz P, con carpetas chap1, chap2, ... para los diferentes capítulos de este documento. Asociaremos a esta carpeta física P la ruta virtual V. Por lo tanto, ejecutaremos Cassini con el siguiente comando de DOS:
Por ejemplo, si queremos que la raíz física del servidor sea la carpeta [D:\data\devel\aspnet\poly] y su raíz virtual [aspnet], el comando DOS para iniciar el servidor web será:
Este comando se puede añadir a un acceso directo. Una vez iniciado, Cassini instala un icono en la barra de tareas. Al hacer doble clic en él, se accede a un panel de encendido/apagado del servidor:

El panel muestra los tres parámetros con los que se ha iniciado. Ofrece dos botones de inicio y parada, así como un enlace de prueba a la raíz de su árbol web. Lo seguimos. Se abre un navegador y se solicita la página URL [http://localhost/aspnet]. Obtenemos el contenido de la carpeta indicada en el campo [Physical Path] anterior:

En el ejemplo, la solicitud URL corresponde a una carpeta y no a un documento web, por lo que el servidor ha mostrado el contenido de dicha carpeta y no un documento web concreto. Si en esa carpeta existe un archivo llamado [default.aspx], este se visualizará. Creemos, por ejemplo, el siguiente archivo y coloquémoslo en la raíz del árbol web de Cassini (d:\data\devel\aspnet\poly en este caso):
Ahora solicitemos el URL [http://localhost/aspnet] con un navegador:

Vemos que, en realidad, lo que se ha mostrado es el URL [http://localhost/aspnet/default.aspx]. Más adelante en este documento, indicaremos cómo debe configurarse Cassini mediante la notación Cassini(path,vpath), donde [path] es el nombre de la carpeta raíz del árbol web del servidor y [vpath] la ruta virtual asociada. Recordemos que, con el servidor Cassini(path,vpath), la URL [http://localhost/vpath/XX] corresponde a la ruta física [path\XX]. Colocaremos todos nuestros documentos en una raíz física a la que llamaremos <webroot>. De este modo, podremos referirnos al archivo <webroot>\chap2\here1.aspx. Para cada lector, esta raíz <webroot> será una carpeta de su ordenador personal. Aquí, las capturas de pantalla mostrarán que esta carpeta suele ser [d:\data\devel\aspnet\poly]. Sin embargo, no siempre será así, ya que las pruebas se han realizado en ordenadores diferentes.
3.3. Primeros ejemplos
Vamos a presentar algunos ejemplos sencillos de páginas web dinámicas creadas con VB.NET. Se invita al lector a probarlos para comprobar que su entorno de desarrollo está correctamente instalado. Descubriremos que hay varias formas de crear una página ASP.NET. Elegiremos una de ellas para continuar con nuestro desarrollo.
3.3.1. Ejemplo básico - variante 1
Herramientas necesarias: un editor de texto, el servidor web Cassini
Retomamos el ejemplo del capítulo anterior. Creamos el siguiente archivo [heure1.aspx]:
<html>
<head>
<title>Demo asp.net </title>
</head>
<body>
Il est <% =Date.Now.ToString("T") %>
</body>
</html>
Este código es del tipo HTML con una etiqueta especial <% ... %>. Dentro de esta etiqueta, se puede incluir código VB.NET. En este caso, el código
genera una cadena de caracteres C que representa la hora actual. La etiqueta <% ... %> se sustituye entonces por esta cadena de caracteres C. Así, si C es la cadena 18:11:01, la línea HTML que contiene el código VB.NET queda así:
Colocamos el código anterior en el archivo [<webroot>\chap2\heure1.aspx]. Iniciamos Cassini (<webroot>,/aspnet) y solicitamos con un navegador el archivo URL [http://localhost/aspnet/chap2/heure1.aspx]:

Una vez obtenido este resultado, sabemos que el entorno de desarrollo está correctamente instalado. La página [heure1.aspx] se ha compilado, ya que contiene código VB.NET. Su compilación ha generado un archivo DLL que se ha almacenado en una carpeta del sistema y, a continuación, ha sido ejecutado por el servidor Cassini.
3.3.2. Ejemplo básico - variante 2
Herramientas necesarias: un editor de texto, el servidor web Cassini
El documento [heure1.aspx] combina código HTML y código VB.NET. En un ejemplo tan sencillo, esto no supone ningún problema. Si hay que incluir más código VB.NET, será conveniente separar aún más el código HTML del código VB. Esto se puede hacer agrupando el código VB dentro de una etiqueta <script>:
<script runat="server">
' cálculo de los datos que se van a mostrar mediante el código HTML
...
</script>
<html>
....
' visualización de los valores calculados por la parte de script
</html>
El ejemplo [heure2.aspx] ilustra este método:
<script runat="server">
Dim maintenant as String=Date.Now.ToString("T")
</script>
<html>
<head>
<title>Demo asp.net </title>
</head>
<body>
Il est
<% =maintenant %>
</body>
</html>
Colocamos el documento [heure2.aspx] en la estructura de directorios [<webroot>\chap2\heure2.aspx] del servidor web Cassini (<webroot>,/aspnet) y solicitamos el documento con un navegador:

3.3.3. Ejemplo básico - variante 3
Herramientas necesarias: un editor de texto, el servidor web Cassini
Llevamos un paso más allá el proceso de separación del código VB y del código HTML, colocándolos en dos archivos distintos. El código HTML se incluirá en el documento [heure3.aspx] y el código VB, en [heure3.aspx.vb]. El contenido de [heure3.aspx] será el siguiente:
<%@ Page Language="vb" src="heure3.aspx.vb" Inherits="heure3" %>
<html>
<head>
<title>Demo asp.net</title>
</head>
<body>
Il est
<% =maintenant %>
</body>
</html>
Hay dos diferencias fundamentales:
- la directiva [Page] con atributos aún desconocidos
- el uso de la variable [maintenant] en el código HTML, cuando no se ha inicializado en ningún sitio
La directiva [Page] sirve aquí para indicar que el código VB, que va a inicializar la página, se encuentra en otro archivo. Es el atributo [src] el que lo indica. Veremos que el código VB corresponde a una clase llamada [heure3]. De forma transparente para el desarrollador, un archivo .aspx se transforma en una clase que deriva de una clase base llamada [Page]. En este caso, nuestro documento HTML debe derivarse de la clase que define y calcula los datos que debe mostrar. En este caso, se trata de la clase [heure3], definida en el archivo [heure3.aspx.vb]. Asimismo, hay que indicar esta relación padre-hijo entre el documento VB [heure3.aspx.vb] y el documento HTML [heure3.aspx]. El atributo [inherits] es el que especifica esta relación. Debe indicar el nombre de la clase definida en el archivo al que apunta el atributo [src].
Analicemos ahora el código VB de la página:
Public Class heure3
Inherits System.Web.UI.Page
' datos de la página web que se van a mostrar
Protected maintenant As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
': se calculan los datos de la página web
maintenant = Date.Now.ToString("T")
End Sub
End Class
Cabe destacar lo siguiente:
- el código VB define una clase [heure3] derivada de la clase [System.Web.UI.Page]. Esto siempre es así, ya que una página web siempre debe derivarse de [System.Web.UI.Page].
- La clase declara un atributo protegido (protected) [maintenant]. Sabemos que se puede acceder directamente a un atributo protegido en las clases derivadas. Esto es lo que permite que el documento HTML [heure3.aspx] tenga acceso al valor del dato [maintenant] en su código.
- La inicialización del atributo [maintenant] se realiza en un procedimiento [Page_Load]. Más adelante veremos que el servidor web notifica a un objeto de tipo [Page] una serie de eventos. El evento [Load] se produce cuando se han creado el objeto [Page] y sus componentes. El gestor de este evento se designa mediante la directiva [Handles MyBase.Load]
- El nombre [XX] del gestor del evento puede ser cualquiera. Su firma debe ser la indicada anteriormente. No la explicaremos por el momento.
- A menudo se utiliza el gestor de eventos [Page.Load] para calcular los valores de los datos dinámicos que debe mostrar la página web.
Los documentos [heure3.spx] y [heure3.aspx.vb] se colocan en [<webroot>\chap2]. A continuación, mediante un navegador, se solicita el URL y el [http://localhost/aspnet/chap2/heure3.aspx] al servidor web (<webroot>,/aspnet):

3.3.4. Ejemplo básico - variante 4
Herramientas necesarias: un editor de texto, el servidor web Cassini
Mantenemos el mismo ejemplo que antes, pero volvemos a agrupar todo el código en un único archivo [heure4.aspx]:
<script runat="server">
' datos de la página web que se van a mostrar
Private maintenant As String
' evt page_load
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
': se calculan los datos de la página web
maintenant = Date.Now.ToString("T")
End Sub
</script>
<html>
<head>
<title>Demo asp.net</title>
</head>
<body>
Il est
<% =maintenant %>
</body>
</html>
Volvemos a encontrar la secuencia del ejemplo 2:
En esta ocasión, el código VB se ha estructurado en procedimientos. Volvemos a encontrar el procedimiento [Page_Load] del ejemplo anterior. Lo que queremos mostrar aquí es que una página .aspx por sí sola (no vinculada a un código VB en un archivo separado) se transforma de forma implícita en una clase derivada de [Page]. Por lo tanto, se pueden utilizar los atributos, métodos y eventos de esta clase. Esto es lo que se hace aquí, donde se utiliza el evento [Load] de esta clase.
El método de prueba es idéntico a los anteriores:

3.3.5. Ejemplo básico - variante 5
Herramientas necesarias: un editor de texto, el servidor web Cassini
Al igual que en el ejemplo 3, se separan el código VB y el código HTML en dos archivos distintos. El código VB se coloca en [heure5.aspx.vb]:
Public Class heure5
Inherits System.Web.UI.Page
' datos de la página web que se van a mostrar
Protected maintenant As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'se calculan los datos de la página web
maintenant = Date.Now.ToString("T")
End Sub
End Class
El código HTML se incluye en [heure5.aspx]:
<%@ Page Inherits="heure5" %>
<html>
<head>
<title>Demo asp.net</title>
</head>
<body>
Il est
<% =maintenant %>
</body>
</html>
En esta ocasión, la directiva [Page] ya no indica la relación entre el código HTML y el código VB. El servidor web ya no puede localizar el código VB para compilarlo (falta el atributo src). Nos corresponde a nosotros realizar esta compilación. Por lo tanto, en una ventana de DOS, compilamos la clase VB [heure5.aspx.vb]:
dos>dir
23/03/2004 18:34 133 heure1.aspx
24/03/2004 09:47 232 heure2.aspx
24/03/2004 10:16 183 heure3.aspx
24/03/2004 10:16 332 heure3.aspx.vb
24/03/2004 14:31 440 heure4.aspx
24/03/2004 14:45 332 heure5.aspx.vb
24/03/2004 14:56 148 heure5.aspx
dos>vbc /r:system.dll /r:system.web.dll /t:library /out:heure5.dll heure5.aspx.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4
En el ejemplo anterior, el ejecutable [vbc.exe] del compilador se encontraba en el directorio PATH del sistema DOS. Si no hubiera sido así, habría sido necesario indicar la ruta completa de [vbc.exe], que se encuentra en el árbol de carpetas donde se instaló SDK.NET. Las clases derivadas de [Page] requieren recursos presentes en DLL y [system.dll, system.web.dll], de ahí que se haga referencia a ellas mediante la opción /r del compilador. La opción /t:library sirve para indicar que se desea generar un archivo DLL. La opción /out indica el nombre del archivo que se va a generar, en este caso [heure5.dll]. Este archivo contiene la clase [heure5] que necesita el documento web [heure5.aspx]. Sin embargo, el servidor web busca los archivos DLL que necesita en ubicaciones muy concretas. Una de estas ubicaciones es la carpeta [bin], situada en la raíz de su árbol de directorios. Esta raíz es lo que hemos denominado <webroot>. Para el servidor IIS, suele ser <unidad>:\inetpub\wwwroot, donde <unidad> es la unidad (C, D, ...) en el que se ha instalado IIS. En el caso del servidor Cassini, esta raíz se corresponde con el parámetro /path con el que lo ha iniciado. Recordemos que este valor se puede obtener haciendo doble clic en el icono del servidor en la barra de tareas:

<webroot> se corresponde con el atributo [Physical Path] mencionado anteriormente. Por lo tanto, creamos una carpeta <webroot>\bin y colocamos [heure5.dll] en su interior:

Ya estamos listos. Solicitamos URL [http://localhost/aspnet/chap2/heure5.aspx] al servidor Cassini (<webroot>,/aspnet):

3.3.6. Ejemplo básico - variante 6
Herramientas necesarias: un editor de texto, el servidor web Cassini
Hasta ahora hemos visto que una aplicación web dinámica tiene dos componentes:
- código VB para calcular las partes dinámicas de la página
- código HTML que, en ocasiones, incluye código VB para mostrar dichos valores en la página. Esta parte representa la respuesta que se envía al cliente web.
El componente 1 se denomina componente controlador de la página y el componente 2, componente de presentación. El componente de presentación debe contener la menor cantidad posible de código VB, o incluso ningún código VB. Veremos que esto es posible. Aquí mostramos un ejemplo en el que solo hay un controlador y no hay componente de presentación. Es el controlador el que genera por sí mismo la respuesta al cliente sin la ayuda del componente de presentación.
El código de presentación queda así:
Se observa que ya no hay ningún código HTML en su interior. La respuesta se elabora directamente en el controlador:
Public Class heure6
Inherits System.Web.UI.Page
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' se elabora la respuesta
Dim HTML As String
HTML = "<html><head><title>heure6</title></head><body>Il est "
HTML += Date.Now.ToString("T")
HTML += "</body></html>"
' se envía
Response.Write(HTML)
End Sub
End Class
El controlador genera aquí la respuesta completa, en lugar de solo las partes dinámicas de la misma. Además, la envía. Lo hace mediante la propiedad [Response], de tipo [HttpResponse], de la clase [Page]. Se trata de un objeto que representa la respuesta que el servidor envía al cliente. La clase [HttpResponse] dispone de un método [Write] para escribir en el flujo HTML que se enviará al cliente. Aquí, colocamos todo el flujo HTML que se va a enviar en la variable [HTML] y enviamos esta última al cliente mediante [Response.Write(HTML)].
Solicitamos la URL [http://localhost/aspnet/chap2/heure6.aspx] al servidor Cassini (<webroot>,/aspnet):

3.3.7. Conclusión
A continuación, utilizaremos el método 3, que coloca el código VB y el código HTML de un documento web dinámico en dos archivos separados. Este método tiene la ventaja de dividir una página web en dos componentes:
- un componente de control, compuesto únicamente por el código VB, que calcula las partes dinámicas de la página
- un componente de presentación, que es la respuesta enviada al cliente. Está compuesto por código HTML, que en ocasiones incluye código VB para mostrar los valores dinámicos. Siempre intentaremos que haya el mínimo posible de código VB en la parte de presentación; lo ideal sería no tener nada.
Como se ha mostrado en el método 5, el controlador se puede compilar independientemente de la aplicación web. Esto tiene la ventaja de poder centrarse únicamente en el código y de obtener, en cada compilación, la lista de todos los errores. Una vez compilado el controlador, se puede probar la aplicación web. Sin una compilación previa, será el servidor web el que se encargue de ello, y entonces los errores se señalarán uno por uno. Esto puede resultar tedioso.
Para los ejemplos que siguen, bastan las siguientes herramientas:
- un editor de texto para crear los documentos HTML y VB de la aplicación cuando sean sencillos
- una herramienta de desarrollo .IDE para crear las clases VB.NET, con el fin de aprovechar la ayuda que este tipo de herramienta ofrece a la hora de escribir código. Un ejemplo de dicha herramienta es CSharpDevelop (http://www.icsharpcode.net). En el anexo [Les outils du développement web] se muestra un ejemplo de uso.
- la herramienta WebMatrix para crear las páginas de presentación de la aplicación (véase el anexo [Les outils du développement web]).
- El servidor Cassini
Todas estas herramientas son gratuitas.