You are on page 1of 255

Presentacin del tutorial de ASP.

NET
El tutorial de ASP.NET comprende un conjunto de ejemplos y comentarios relacionados acerca de ASP.NET, diseado para explicar rpidamente a los programadores la sintaxis, la arquitectura y la eficacia del marco de programacin para aplicaciones Web de ASP.NET. Los ejemplos del tutorial se disearon en forma de ilustraciones breves y fciles de comprender de las caractersticas de ASP.NET. Cuando haya completado el tutorial, estar familiarizado con:

La sintaxis de ASP.NET. Aunque algunos de los elementos de la sintaxis de ASP.NET sern familiares para los programadores veteranos de ASP, otros son exclusivos del nuevo marco de trabajo. Los ejemplos del tutorial describen cada elemento en detalle. La arquitectura y las caractersticas de ASP.NET. En el tutorial se describen las caractersticas de ASP.NET, que permiten a los programadores crear aplicaciones interactivas de primer nivel con mucho menos esfuerzo que antes. Los mejores procedimientos. Los ejemplos del tutorial explican las mejores formas de utilizar la eficacia de ASP.NET y la forma de evitar posibles errores al hacerlo.

Nivel de conocimientos necesario para poder seguir el tutorial


Si no tiene experiencia en programacin de pginas, este tutorial no es lo ms aconsejable. Debe tener conocimientos acerca de HTML y de terminologa general de programacin Web. No necesita experiencia previa en ASP, pero debe conocer los conceptos bsicos relacionados con pginas Web interactivas, como "formulario", "secuencia de comando" y "acceso a datos".

Trabajar con los ejemplos del tutorial


Es mejor estudiar los ejemplos del tutorial en el orden en que se presentan. Cada ejemplo se basa en conceptos tratados en el ejemplo anterior. La serie empieza con el envo de un formulario sencillo y contina con ms ejemplos hasta desarrollar escenarios de aplicacin integrados.

Qu es ASP.NET?
ASP.NET es un marco de trabajo de programacin generado en Common Language Runtime que puede utilizarse en un servidor para generar eficaces aplicaciones Web. ASP.NET ofrece varias ventajas importantes acerca de los modelos de programacin Web anteriores:

Mejor rendimiento. ASP.NET es un cdigo de Common Language Runtime compilado que se ejecuta en el servidor. A diferencia de sus predecesores, ASP.NET puede aprovechar las ventajas del enlace anticipado, la compilacin just-in-time, la optimizacin nativa y los servicios de cach desde el primer momento. Esto supone un incremento espectacular del rendimiento antes de siquiera escribir una lnea de cdigo.

Compatibilidad con herramientas de primer nivel. El marco de trabajo de ASP.NET se complementa con un diseador y una caja de herramientas muy completos en el entorno integrado de programacin (Integrated Development Environment, IDE) de Visual Studio. La edicin WYSIWYG, los controles de servidor de arrastrar y colocar y la implementacin automtica son slo algunas de las caractersticas que proporciona esta eficaz herramienta.

Eficacia y flexibilidad. Debido a que ASP.NET se basa en Common Language Runtime, la eficacia y la flexibilidad de toda esa plataforma se encuentra disponible para los programadores de aplicaciones Web. La biblioteca de clases de .NET Framework, la Mensajera y las soluciones de Acceso a datos se encuentran accesibles desde el Web de manera uniforme. ASP.NET es tambin independiente del lenguaje, por lo que puede elegir el lenguaje que mejor se adapte a la aplicacin o dividir la aplicacin en varios lenguajes. Adems, la interoperabilidad de Common Language Runtime garantiza que la inversin existente en programacin basada en COM se conserva al migrar a ASP.NET.

Simplicidad. ASP.NET facilita la realizacin de tareas comunes, desde el sencillo envo de formularios y la autenticacin del cliente hasta la implementacin y la configuracin de sitios. Por ejemplo, el marco de trabajo de pgina de ASP.NET permite generar interfaces de usuario, que separan claramente la lgica de aplicacin del cdigo de presentacin, y controlar eventos en un sencillo modelo de procesamiento de formularios de tipo Visual Basic. Adems, Common Language Runtime simplifica la programacin, con servicios de cdigo administrado como el recuento de referencia automtico y el recolector de elementos no utilizados.

Facilidad de uso. ASP.NET emplea un sistema de configuracin jerrquico, basado en texto, que simplifica la aplicacin de la configuracin al entorno de servidor y las aplicaciones Web. Debido a que la informacin de configuracin se almacena como texto sin formato, se puede aplicar la nueva configuracin sin la ayuda de herramientas de administracin local. Esta filosofa de "administracin local cero" se extiende asimismo a la implementacin de las aplicaciones ASP.NET Framework. Una aplicacin ASP.NET Framework se implementa en un servidor sencillamente mediante la copia de los archivos necesarios al servidor. No se requiere el reinicio del servidor, ni siquiera para implementar o reemplazar el cdigo compilado en ejecucin.

Escalabilidad y disponibilidad. ASP.NET se ha diseado teniendo en cuenta la escalabilidad, con caractersticas diseadas especficamente a medida, con el fin de mejorar el rendimiento en entornos agrupados y de mltiples procesadores. Adems, el motor de tiempo de ejecucin de ASP.NET controla y administra los procesos de cerca, por lo que si uno no se comporta adecuadamente (filtraciones, bloqueos), se puede crear un proceso nuevo en su lugar, lo que ayuda a mantener la aplicacin disponible constantemente para controlar solicitudes.

Posibilidad de personalizacin y extensibilidad. ASP.NET presenta una arquitectura bien diseada que permite a los programadores insertar su cdigo en el nivel adecuado. De hecho, es posible extender o reemplazar cualquier subcomponente del motor de tiempo de ejecucin de ASP.NET con su propio componente escrito personalizado. La implementacin de la autenticacin personalizada o de los servicios de estado nunca ha sido ms fcil.

Seguridad. Con la autenticacin de Windows integrada y la configuracin por aplicacin, se puede tener la completa seguridad de que las aplicaciones estn a salvo. El resto del tutorial presenta ejemplos prcticos de estos conceptos.

Compatibilidad de lenguajes
La Plataforma Microsoft .NET ofrece actualmente compatibilidad integrada para tres lenguajes: C#, Visual Basic y JScript. En los ejercicios y los ejemplos de cdigo de este tutorial se muestra cmo utilizar C#, Visual Basic y JScript para generar aplicaciones .NET. Para obtener ms informacin sobre la sintaxis de los dems lenguajes, consulte la documentacin completa del Kit de desarrollo de software (SDK) de .NET Framework. La siguiente tabla ayuda a comprender los ejemplos de cdigo de este tutorial as como las diferencias entre los tres lenguajes:

Declaraciones de variables
Dim x As Integer Dim s As String Dim s1, s2 As String Dim o 'Implicitly Object Dim obj As New Object() Public name As String

Instrucciones
Response.Write("foo")

Comentarios
' This is a comment ' This ' is 'a ' multiline ' comment

Obtener acceso a propiedades indizadas


Dim s, value As String s = Request.QueryString("Name") value = Request.Cookies("Key").Value 'Note that default non-indexed properties 'must be explicitly named in VB

Declarar propiedades indizadas


' Default Indexed Property Public Default ReadOnly Property DefaultProperty(Name As String) As String Get Return CStr(lookuptable(name)) End Get End Property

Declarar propiedades sencillas


Public Property Name As String Get ... Return ... End Get Set ... = Value End Set End Property

Declarar y utilizar una enumeracin


' Declare the Enumeration Public Enum MessageSize Small = 0 Medium = 1 Large = 2 End Enum ' Create a Field or Property Public MsgSize As MessageSize ' Assign to the property using the Enumeration values MsgSize = small

Enumerar una coleccin


Dim S As String For Each S In Coll ... Next

Declarar y utilizar mtodos

' Declare a void return function Sub VoidFunction() ... End Sub ' Declare a function that returns a value Function StringFunction() As String ... Return CStr(val) End Function ' Declare a function that takes and returns values Function ParmFunction(a As String, b As String) As String ... Return CStr(A & B) End Function ' Use the Functions VoidFunction() Dim s1 As String = StringFunction() Dim s2 As String = ParmFunction("Hello", "World!")

Atributos personalizados
' Stand-alone attribute <STAThread> ' Attribute with parameters <DllImport("ADVAPI32.DLL")> ' Attribute with named parameters <DllImport("KERNEL32.DLL", CharSet:=CharSet.Auto)>

Matrices
Dim a(2) As String a(0) = "1" a(1) = "2" a(2) = "3" Dim a(2,2) As String a(0,0) = "1" a(1,0) = "2" a(2,0) = "3"

Inicializacin
Dim s As String = "Hello World" Dim i As Integer = 1 Dim a() As Double = { 3.00, 4.00, 5.00 }

Instrucciones if
If Not (Request.QueryString = Nothing) ...

End If

Instrucciones case
Select Case FirstName Case "John" ... Case "Paul" ... Case "Ringo" ... Case Else ... End Select

Bucles for
Dim I As Integer For I = 0 To 2 a(I) = "test" Next

Bucles while
Dim I As Integer I=0 Do While I < 3 Console.WriteLine(I.ToString()) I += 1 Loop

Control de excepciones
Try ' Code that throws exceptions Catch E As OverflowException ' Catch a specific exception Catch E As Exception ' Catch the generic exceptions Finally ' Execute some cleanup code End Try

Concatenacin de cadenas
' Using Strings Dim s1, s2 As String s2 = "hello" s2 &= " world" s1 = s2 & " !!!" ' Using StringBuilder class for performance Dim s3 As New StringBuilder() s3.Append("hello") s3.Append(" world")

s3.Append(" !!!")

Delegados de controlador de eventos


Sub MyButton_Click(Sender As Object, E As EventArgs) ... End Sub

Declarar eventos
' Create a public event Public Event MyEvent(Sender as Object, E as EventArgs) ' Create a method for firing the event Protected Sub OnMyEvent(E As EventArgs) RaiseEvent MyEvent(Me, E) End Sub

Agregar o quitar controladores de eventos en eventos


AddHandler Control.Change, AddressOf Me.ChangeEventHandler RemoveHandler Control.Change, AddressOf Me.ChangeEventHandler

Conversin de tipos
Dim obj As MyObject Dim iObj As IMyObject obj = Session("Some Value") iObj = CType(obj, IMyObject)

Conversin
Dim i As Integer Dim s As String Dim d As Double i=3 s = i.ToString() d = CDbl(s) ' See also CDbl(...), CStr(...), ...

Definicin de clase con herencia


Imports System Namespace MySpace Public Class Foo : Inherits Bar Dim x As Integer Public Sub New() MyBase.New()

x=4 End Sub Public Sub Add(x As Integer) Me.x = Me.x + x End Sub Overrides Public Function GetNum() As Integer Return x End Function End Class End Namespace ' vbc /out:libraryvb.dll /t:library ' library.vb

Implementar una interfaz


Public Class MyClass : Implements IEnumerable ... Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ... End Function End Class

Definicin de clase con un mtodo principal


Imports System Public Class ConsoleVB Public Sub New() MyBase.New() Console.WriteLine("Object Created") End Sub Public Shared Sub Main() Console.WriteLine("Hello World") Dim cvb As New ConsoleVB End Sub End Class ' vbc /out:consolevb.exe /t:exe console.vb

Mdulo estndar
Imports System Public Module ConsoleVB Public Sub Main() Console.WriteLine("Hello World") End Sub

End Module ' vbc /out:consolevb.exe /t:exe console.vb

Web Forms ASP.NET

Presentacin de formularios Web Qu son los formularios Web de ASP.NET?


El marco de trabajo de la pgina de formularios Web de ASP.NET es un modelo de programacin escalable de Common Language Runtime que puede utilizarse en el servidor para generar pginas Web dinmicamente. Concebido como una evolucin lgica de ASP (ASP.NET proporciona compatibilidad sintctica con las pginas existentes), el marco de trabajo de formularios Web ASP.NET se ha diseado especficamente para tratar varias deficiencias clave del modelo anterior. En particular, proporciona:

Capacidad para crear y utilizar controles de la interfaz de usuario reutilizables que puedan encapsular funcionalidades comunes y, as, reducir la cantidad de cdigo que tiene que escribir el programador de una pgina. Capacidad para que los programadores puedan estructurar limpiamente la lgica de la pgina de forma ordenada (no revuelta). Capacidad para que las herramientas de desarrollo proporcionen un fuerte soporte de diseo WYSIWYG (Lo que ve es lo que se imprime) a las pginas (el cdigo ASP existente es opaco para las herramientas). Es esta seccin se proporciona un recorrido con cdigo de gran nivel por algunas de las funciones claves de formularios Web de ASP.NET. En las siguientes secciones, se profundizar en detalles ms concretos.

Escribir la pgina de formularios Web


Las pginas de formularios Web de ASP.NET consisten en archivos de texto con una extensin de nombre de archivo .aspx. Pueden implementarse por todo un rbol de directorio raz virtual IIS. Cuando un explorador cliente solicita recursos .aspx, el motor en tiempo de ejecucin de ASP.NET analiza y compila el archivo de destino en una clase de .NET Framework. Esta clase puede utilizarse, a continuacin, para procesar de forma dinmica las solicitudes entrantes. (Debe observarse que el archivo .aspx slo se compila la primera que se tiene acceso al mismo; la instancia de tipo compilada se vuelve a utilizar en mltiples solicitudes). Una pgina de ASP.NET puede crearse tomando simplemente un archivo HTML existente y cambiando la extensin del nombre de archivo a .aspx (no se necesita ninguna modificacin del cdigo). En el siguiente ejemplo se muestra una pgina HTML sencilla que recoge una preferencia de categora y un nombre de usuario, y a continuacin realiza una devolucin de formulario a la pgina de origen cuando se hace clic sobre el botn:

<html> <head> <link rel="stylesheet" href="intro.css"> </head> <body> <center> <form action="intro1.aspx" method="post"> <h3> Nombre: <input id="Name" type=text> Categora: <select id="Category" size=1> <option>psychology</option> <option>business</option> <option>popular_comp</option> </select> <input type=submit value="Bsqueda"> </h3> </form> </center>

</body> </html>

Importante: Debe observarse que no sucede nada cuando se hace clic en el botn Lookup. Esto sucede porque el archivo .aspx slo contiene HTML esttico (sin contenido dinmico). As pues, el mismo HTML se enva de vuelta al cliente en cada viaje a la pgina, lo que conlleva una prdida de los contenidos de los campos del formulario (el cuadro de texto y la lista desplegable) entre solicitudes.

Utilizar bloques de representacin ASP <%%>


ASP.NET proporciona compatibilidad sintctica con pginas ASP existentes. Esto incluye compatibilidad para bloques de representacin de cdigo <% %> que pueden entremezclarse con contenido HTML dentro de un archivo .aspx. Estos bloques de cdigo se ejecutan de arriba a abajo en tiempo de representacin de pgina. En el siguiente ejemplo se muestra cmo se pueden utilizar bloques de representacin <% %> para ascender en bucle por un bloque HTML (aumentando el tamao de fuente cada vez):

<%@ Page Language="VB" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <body> <center> <form action="intro2.aspx" method="post"> <h3> Nombre: <input id="Nombre" type=text> Categora: <select id="Categora" size=1> <option>psychology</option> <option>business</option> <option>popular_comp</option> </select> </h3> <input type=submit value="Bsqueda"> <p> <% Dim I As Integer For I = 0 to 7 %> <font size="<%=I%>"> Bienvenido a ASP.NET </font> <br> <% Next %> </form> </center> </body> </html>

Importante: A diferencia de ASP, el cdigo que se utiliza en los bloques <% %> anteriores realmente se compila, no se interpreta mediante un motor de secuencias de comandos. Esto produce un mejor rendimiento de la ejecucin en tiempo de ejecucin.

Los programadores de pginas ASP.NET pueden utilizar bloques de cdigo <% %> para modificar dinmicamente resultados HTML ms de lo que se puede actualmente con ASP. En el siguiente ejemplo se muestra cmo se pueden utilizar bloques de cdigo <% %> para interpretar resultados devueltos desde un cliente.

<%@ Page Language="VB" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <body> <center> <form action="intro3.aspx"> <h3> Nombre: <input name="Nombre" type=text value="<%=Request.QueryString("Nombre")%>"> Categora: <select name="Categora" size=1> <% Dim I As Integer Dim Values(2) As String Values(0) = "psychology" Values(1) = "business" Values(2) = "popular_comp" For I = 0 To Values.Length - 1 %> <% If (Request.QueryString("Categora") = Values(i)) %> <option selected> <% Else %> <option> <% End If %> <%=Values(i)%> </option> <% Next %> </select> </h3> <input type=submit name="Bsqueda" value="Bsqueda"> <p> <% If (Not Request.QueryString("Bsqueda") = Nothing) %> Hola <%=Request.QueryString("Nombre") %>, ha seleccionado: <%=Request.QueryString("Categora") %> <% End If %> </form> </center> </body> </html>

Importante: Mientras que los bloques de cdigo <% %> proporcionan una forma potente de manipular de forma personalizada el resultado de texto devuelto desde una pgina ASP.NET, no proporcionan un modelo de programacin HTML limpio. Tal y como se muestra en el ejemplo anterior, los programadores que slo utilizan bloques de cdigo <% %> deben administrar de forma personalizada el estado de pgina entre acciones de ida y vuelta e interpretar valores expuestos.

Introduccin a controles de servidor ASP.NET


Adems de (o en vez de) utilizar bloques de cdigo <% %> para programar contenido dinmico, los programadores de pginas ASP.NET pueden utilizar controles de servidor ASP.NET para programar pginas Web. Los controles de servidor se declaran dentro de un archivo .aspx mediante etiquetas personalizadas o etiquetas HTML intrnsecas que contienen un valor de atributo runat="server". Las etiquetas HTML intrnsecas las controla uno de los controles del espacio de nombres System.Web.UI.HtmlControls. A cualquier etiqueta que no est explcitamente asignada a uno de los controles se le asigna el tipo de System.Web.UI.HtmlControls.HtmlGenericControl. En el siguiente ejemplo se utilizan cuatro controles de servidor: <form runat=server>, <asp:textbox runat=server>, <asp:dropdownlist runat=server>, y <asp:button runat=server>. En tiempo de ejecucin, estos controles de servidor generan contenido HTML automticamente.

<html> <head> <link rel="stylesheet"href="intro.css"> </head> <body> <center> <form action="intro4.aspx" method="post" runat=server> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" runat="server"/> </form> </center> </body> </html>

Importante: Debe tenerse en cuenta que estos controles de servidor mantienen automticamente cualquier valor introducido por el cliente entre acciones de ida y vuelta al servidor. El estado del control no se almacena en el servidor, sino en un campo del formulario <input type="hidden"> que recibe acciones de ida y vuelta entre solicitudes. Hay que tener en cuenta que no se necesita ninguna secuencia de comando en el cliente. Adems de admitir controles estndar de entrada HTML, ASP.NET permite programadores utilizar controles personalizados enriquecidos en las En el siguiente ejemplo se demuestra cmo puede utilizarse el control <asp:adrotator> para mostrar dinmicamente en la pgina anuncios en a los pginas. rotacin.

<html> <head>

<link rel="stylesheet"href="intro.css"> </head> <body> <center> <form action="intro5.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" runat="server"/> </form> </center> </body> </html>

Importante: Se puede encontrar un listado detallado de todos los controles de servidor integrados en la seccin Referencia de controles de formularios Web de este tutorial.

Controlar eventos de controles de servidor


Cada control de servidor ASP.NET puede exponer un modelo de objeto con propiedades, mtodos y eventos. Los programadores de ASP.NET pueden utilizar este modelo de objeto para modificar e interactuar limpiamente con la pgina. En el siguiente ejemplo se muestra cmo un programador de pginas ASP.NET puede controlar el evento OnClick desde el control <asp:button runat=server> para manipular la propiedad Text del control <asp:label runat=server>.

<html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) Message.Text = "Hola " & Name.Text & ", ha selecionado: " & Category.SelectedItem.Text End Sub </script> <body> <center>

<form action="intro6.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/> <p> <asp:label id="Message" runat="server"/> </form> </center> </body> </html>

Este simple ejemplo resulta equivalente al ejemplo "Intro3" que se mostr antes en esta misma seccin. No obstante, debe observarse que el cdigo es mucho ms limpio y sencillo en esta nueva versin basada en el control de servidor.

Utilizar controles de servidor personalizados


ASP.NET incluye 45 controles de servidor integrados que se pueden utilizar fuera del cuadro (para obtener ms detalles, vea Referencia de controles de formularios Web). Adems de utilizar los controles integrados de ASP.NET, los programadores tambin pueden utilizar controles desarrollados por otros fabricantes. En el siguiente ejemplo se muestra un control Calendar sencillo. El control Calendar se declara en la pgina mediante una etiqueta <acme:calendar runat=server>. Debe observarse que la directiva <% Register %> al principio de la pgina es la responsable de registrar el prefijo de etiqueta XML con el espacio de nombres de cdigo "Acme" de la implementacin del control. El localizador de pginas de ASP.NET utilizar entonces este espacio de nombres para cargar la instancia de la clase del control Calendar en tiempo de ejecucin.

<%@ Register TagPrefix="Acme" Namespace="AcmeVB" Assembly="AcmeVB" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) Message.Text = "Hola " & Name.Text & ", ha selecionado: " & Category.SelectedItem.Text & " el: " & MyCal.Date.ToShortDateString() End Sub </script> <body>

<center> <form action="intro7.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/> <p> <Acme:Calendar id="MyCal" runat=server/> <p> <asp:label id="Message" runat="server"/> </form> </center> </body> </html>

El control Calendar de este ejemplo se ha diseado para realizar procesos similares a los de alto nivel en Internet Explorer 5.5 y procesos de bajo nivel en todos los dems exploradores. El olfateo de este explorador no es, en absoluto, ms complejo que el que proporcionan los controles de servidor integrados de ASP.NET. Para los exploradores Internet Explorer 5.5, genera resultados DHTML. Dicho resultado no necesita acciones de ida y vuelta al servidor cuando se realizan selecciones de da y desplazamientos de mes. Para el resto de exploradores, el control genera HTML 3.2 estndar. HTML 3.2 necesita acciones de ida y vuelta al servidor para controlar interacciones del usuario en el cliente. Importante: El cdigo que escribe el programador de una pgina es idntico, sin importar si se empleo un explorador de alto o bajo nivel para tener acceso a la pgina. El mismo control Calendar encapsula toda la lgica necesaria para controlar ambos escenarios.

Listas, datos y enlace de datos


ASP.NET incluye un conjunto integrado de controles de lista y cuadrcula de datos. Se pueden utilizar para proporcionar una interfaz de usuario personalizada basada en consultas a una base de datos o a otro origen de datos. En el siguiente ejemplo se muestra cmo se puede utilizar un control <asp:datagrid runat=server> para enlazar mediante datos informacin de libros recogida mediante una consulta a una base de datos de SQL.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs)

Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection) DS = new DataSet() MyCommand.Fill(ds, "Titles") MyList.DataSource = ds.Tables("Titles").DefaultView MyList.DataBind() End Sub </script> <body> <center> <form action="intro8.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/> <p> <ASP:DataGrid id="MyList" HeaderStyle-BackColor="#aaaadd" BackColor="#ccccff" runat="server"/> </form> </center> </body> </html>

El control DataGrid <asp:datagrid runat=server> proporciona una forma sencilla de visualizar rpidamente resultados de datos mediante una interfaz de usuario tradicional de control de cuadrcula. Como alternativa, los programadores de ASP.NET pueden utilizar el control DataList <asp:DataList runat=server> y una plantilla ItemTemplate personalizada para personalizar informacin de datos, tal y como se muestra en el siguiente ejemplo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html>

<head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection) DS = new DataSet() MyCommand.Fill(ds, "Titles") MyList.DataSource = ds.Tables("Titles").DefaultView MyList.DataBind() End Sub </script> <body> <center> <form action="intro9.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/> <p> <asp:datalist id="MyList" repeatcolumns="2" borderwidth="0" runat="server"> <ItemTemplate> <table> <tr> <td> <img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>'> </td> <td width=250 valign=top> <b><%# DataBinder.Eval(Container.DataItem, "title") %></b>

<br><br> Precio: <%# DataBinder.Eval(Container.DataItem, "price", "${0}") %> </td> </tr> </table> </ItemTemplate> </asp:datalist> </form> </center> </body> </html>

Debe observarse que el control <asp:datalist runat=server> permite a los usuarios finales controlar exactamente la estructura y el diseo de cada elemento de la lista (mediante la propiedad de plantillas ItemTemplate). El control tambin controla automticamente el ajuste de contenido en dos columnas (los usuarios pueden controlar el nmero de columnas mediante la propiedad RepeatColumns de la lista de datos). En el siguiente ejemplo se proporciona una visin alternativa del control <asp:datalist runat=server>.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection) DS = new DataSet() MyCommand.Fill(ds, "Titles") MyList.DataSource = ds.Tables("Titles").DefaultView MyList.DataBind() End Sub </script> <body>

<center> <form action="intro10.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <h3> Nombre: <asp:textbox id="Name" runat="server"/> Categora: <asp:dropdownlist id="Category" runat=server> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </h3> <asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/> <p> <asp:datalist id="MyList" layout="flow" showfooter=true borderwidth=0 runat=server> <HeaderTemplate> <table cellpadding=1 cellspacing=0 > <tr> <td colspan=4> <b><font face="Verdana" size=3>Lista de productos </font></b> </td> </tr> <tr> <td colspan=4 height=5 bgcolor="000000"></td> </tr> </HeaderTemplate> <ItemTemplate> <tr> <td colspan=3 style="font-size:10pt"> <b><%# DataBinder.Eval(Container.DataItem, "title_id") %></b> <span> <%# DataBinder.Eval(Container.DataItem, "title") %> </span> </td> <td align=right style="font-size:10pt"> <b><%# DataBinder.Eval(Container.DataItem, "price", "${0}") %> </b> </td> </tr> </ItemTemplate> <SeparatorTemplate> <tr> <td colspan=4 height=1 bgcolor="000000"></td> </tr> </SeparatorTemplate> <FooterTemplate> <tr> <td colspan=4 height=5 bgcolor="000000"></td> </tr> </table> </FooterTemplate> </asp:datalist>

</form> </center> </body> </html>

Debe observarse que el control, el modelo de datos y el usuario de la pgina son los mismos que en el ejemplo anterior. La nica diferencia consiste en que, en este caso, las plantillas alternativas se proporcionan al cdigo de forma declarativa.

Controles de validacin de formulario


El marco de trabajo de la pgina de formularios Web de ASP.NET proporciona un conjunto de controles de servidor de validacin que proporcionan a su vez un modo sencillo a la vez que potente de comprobar errores en los formularios de entrada y, en caso necesario, mostrar mensajes al usuario. Los controles de validacin se agregan a una pgina ASP.NET con otros controles de servidor. Existen controles para tipos concretos de validacin, como la comprobacin de intervalos o la coincidencia de modelos, adems de RequiredFieldValidator, que se asegura de que un usuario omita un campo de entrada. En el siguiente ejemplo se muestra cmo utilizar dos controles <asp:requiredfieldvalidator runat=server> en una pgina para validar los contenidos de los controles TextBox y DropDownList.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection) DS = new DataSet() MyCommand.Fill(ds, "Titles") MyList.DataSource = ds.Tables("Titles").DefaultView MyList.DataBind() End Sub </script> <body> <center> <form action="intro11.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <table> <tr> <td> Nombre: </td> <td> <asp:textbox id="Name" runat="server"/> </td> <td> <asp:RequiredFieldValidator ControlToValidate="Name" Display="Dynamic" errormessage="Debe escribir su nombre" runat=server/> </td> </tr> <tr> <td> Categora: </td> <td> <asp:dropdownlist id="Category" width=220 runat=server> <asp:listitem><!--Seleccionar categora--></asp:listitem> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </td> <td> <asp:RequiredFieldValidator ControlToValidate="Category" Display="Dynamic" InitialValue="<!-Seleccionar categora-->" errormessage="Debe seleccionar una categora" runat=server/> </td> </tr> <tr> <td></td> <td><asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/></td> </tr> </table> <p> <asp:datalist id="MyList" repeatcolumns="2" borderwidth="0" runat="server"> <ItemTemplate> <table> <tr> <td> <img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>'> </td> <td width=250 valign=top> <b><%# DataBinder.Eval(Container.DataItem, "title") %></b> <br><br> Precio: <%# DataBinder.Eval(Container.DataItem, "price", "${0}") %> </td> </tr> </table> </ItemTemplate> </asp:datalist> </form> </center>

</body> </html>

Debe observarse que los controles de validacin disponen de compatibilidad con clientes de alto y bajo nivel. Los exploradores de alto nivel realizan la validacin en el cliente (mediante JavaScript y DHTML) y en el servidor. Los exploradores de bajo nivel slo realizan la validacin en el servidor. El modelo de programacin de los dos escenarios es idntico. Debe observarse que los programadores de pginas ASP.NET pueden activar opcionalmente la propiedad Page.IsValid en tiempo de ejecucin para determinar si todos los controles de validacin de una pgina son vlidos en ese momento. Esto proporciona un modo simple de determinar si se contina con la lgica empresarial o no. En el siguiente ejemplo se realiza una comprobacin Page.IsValid antes de ejecutar una bsqueda de la categora especificada en la base de datos.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <link rel="stylesheet"href="intro.css"> </head> <script language="VB" runat=server> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) If (Page.IsValid) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection) DS = new DataSet() MyCommand.Fill(ds, "Titles") MyList.DataSource = ds.Tables("Titles").DefaultView MyList.DataBind() End If End Sub </script> <body> <center> <form action="intro12.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <table> <tr> <td> Nombre: </td> <td> <asp:textbox id="Name" runat="server"/> </td>

<td> <asp:RequiredFieldValidator ControlToValidate="Name" Display="Dynamic" errormessage="Debe escribir su nombre" runat=server/> </td> </tr> <tr> <td> Categora: </td> <td> <asp:dropdownlist id="Category" width=220 runat=server> <asp:listitem><!--Seleccionar categora--></asp:listitem> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </td> <td> <asp:RequiredFieldValidator ControlToValidate="Category" Display="Dynamic" InitialValue="<!-Seleccionar categora-->" errormessage="Debe seleccionar una categora" runat=server/> </td> </tr> <tr> <td></td> <td><asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/></td> </tr> </table> <p> <asp:datalist id="MyList" repeatcolumns="2" borderwidth="0" runat="server"> <ItemTemplate> <table> <tr> <td> <img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>'> </td> <td width=250 valign=top> <b><%# DataBinder.Eval(Container.DataItem, "title") %></b> <br><br> Precio: <%# DataBinder.Eval(Container.DataItem, "price", "${0}") %> </td> </tr> </table> </ItemTemplate> </asp:datalist> </form> </center> </body> </html>

Formularios Web de cdigo subyacente

ASP.NET admite dos mtodos para crear pginas dinmicas. El primero es el mtodo que se ha mostrado en los ejemplos anteriores, en el que el cdigo de pgina se declara fsicamente en el archivo .aspx de origen. La forma alternativa (conocida como mtodo de cdigo subyacente) permite que el cdigo de pgina est ms claramente separado del contenido HTML en un archivo completamente independiente. En el siguiente ejemplo se muestra el uso del mtodo de cdigo subyacente para escribir cdigo de pginas ASP.NET.

<%@ Page Inherits="MyCodeBehind" Src="Intro13.vb" %> <html> <head> <link rel="stylesheet" href="intro.css"> </head> <body> <center> <form action="intro13.aspx" method="post" runat="server"> <asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/> <table> <tr> <td> Nombre: </td> <td> <asp:textbox id="Name" runat="server"/> </td> <td> <asp:RequiredFieldValidator ControlToValidate="Name" Display="Dynamic" errormessage="Debe escribir su nombre" runat=server/> </td> </tr> <tr> <td> Categora: </td> <td> <asp:dropdownlist id="Category" width=220 runat=server> <asp:listitem><!--Seleccionar categora--></asp:listitem> <asp:listitem >psychology</asp:listitem> <asp:listitem >business</asp:listitem> <asp:listitem >popular_comp</asp:listitem> </asp:dropdownlist> </td> <td> <asp:RequiredFieldValidator ControlToValidate="Category" Display="Dynamic" InitialValue="<!-Seleccionar categora-->" errormessage="Debe seleccionar una categora" runat=server/> </td> </tr> <tr> <td></td> <td><asp:button text="Bsqueda" OnClick="SubmitBtn_Click" runat="server"/></td> </tr> </table> <p> <asp:datalist id="MyList" repeatcolumns="2" borderwidth="0" runat="server"> <ItemTemplate> <table> <tr> <td> <img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>'> </td>

<td width=250 valign=top> <b><%# DataBinder.Eval(Container.DataItem, "title") %></b> <br><br> Precio: <%# DataBinder.Eval(Container.DataItem, "price", "${0}") %> </td> </tr> </table> </ItemTemplate> </asp:datalist> </form> </center> </body> </html>

Resumen de la seccin
1. Los formularios Web ASP.NET proporcionan una forma fcil y potente de generar interfaces de usuario Web dinmicas. 2. Las pginas de formularios Web de ASP.NET pueden dirigirse a cualquier explorador cliente (no existe ningn requisito de cookies o de biblioteca de secuencias de comandos). 3. Las pginas de formularios Web de ASP.NET proporciona compatibilidad sintctica con pginas ASP existentes. 4. Los controles de servidor de ASP.NET proporcionan una forma sencilla de encapsular funcionalidades comunes. 5. ASP.NET incluye 45 controles de servidor integrados. Los programadores tambin pueden utilizar los controles generados por otros. 6. Los controles de servidor ASP.NET pueden proyectar automticamente HTML de alto y bajo nivel. 7. Las plantillas ASP.NET proporcionan una forma sencilla de personalizar la apariencia y sensacin de controles de servidor de lista. 8. Los controles de validacin de ASP.NET proporcionan una forma sencilla de realizar validaciones de datos declarativas en el cliente o en el servidor.

Trabajar con controles de servidor


En esta seccin del tutorial, se muestra algunos conceptos bsicos comunes y acciones comunes realizadas por usuarios finales al utilizar controles de servidor ASP.NET en una pgina.

Declarar controles de servidor


Los controles de servidor ASP.NET se identifican en una pgina mediante etiquetas declarativas que contienen un atributo runat="server". En el siguiente ejemplo se declaran tres controles de servidor <asp:label runat="server"> y se personaliza las propiedades de texto y estilo de cada uno por separado.

<html> <body> <h3><font face="Verdana">Declarar controles de servidor</font></h3> Este ejemplo muestra cmo declarar el control de servidor &lt;asp:label&gt; y manipular sus propiedades en una pgina.

<p> <hr> <asp:label id="Message1" font-size="16" font-bold="true" forecolor="red" runat=server>Primer mensaje</asp:label> <br> <asp:label id="Message2" font-size="20" font-italic="true" forecolor="blue" runat=server>Segundo mensaje</asp:label> <br> <asp:label id="Message3" font-size="24" font-underline="true" forecolor="green" runat=server>Tercer mensaje</asp:label> </body> </html>

Manipular controles de servidor


Se puede identificar mediante programacin un control de servidor individual de ASP.NET dentro de una pgina proporcionndolo con un atributo id. Se puede utilizar la referencia id para manipular mediante programacin el modelo de objeto del control de servidor en tiempo de ejecucin. En el siguiente ejemplo se muestra cmo puede un programador de pginas establecer una propiedad Text del control <asp:label runat="server"> en el evento Page_Load.

<html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Message.Text = "Fecha y hora en la que obtuvo acceso por ltima vez a esta pgina: " & DateTime.Now End Sub </script> <body> <h3><font face="Verdana">Manipular controles de servidor</font></h3> Este ejemplo muestra cmo manipular el control de servidor &lt;asp:label&gt; del evento Page_Load para representar la hora actual. <p> <hr> <asp:label id="Message" font-size="24" font-bold="true" runat=server/> </body> </html>

Controlar eventos de accin del control

Los controles de servidor ASP.NET pueden exponer y provocar opcionalmente eventos, que pueden controlar los programadores de pginas. Un programador de pgina puede cumplir con esto mediante la conexin de un evento con un control (en el que el nombre de atributo de un evento indica el nombre del evento y el valor del atributo indica el nombre de un mtodo al que llamar). Por ejemplo, en el siguiente ejemplo de cdigo se demuestra cmo conectar un evento OnClick a un control de botn.

html> <script language="VB" runat="server"> Sub EnterBtn_Click(Sender As Object, E As EventArgs) Message.Text = "Hola " & Name.Text & ", esto es ASP.NET" End Sub </script> <body> <h3><font face="Verdana">Administrar eventos de accin de control</font></h3> <p> Este ejemplo muestra cmo obtener acceso al control de servidor &lt;asp:textbox&gt; del evento "Click" de &lt;asp:button&gt; y utilizar el contenido para modificar el texto de &lt;asp:label&gt;. <p> <hr> <form action="controls3.aspx" runat=server> <font face="Verdana"> Escribir su nombre: <asp:textbox id="Name" runat=server/> <asp:button text="Entrar" Onclick="EnterBtn_Click" runat=server/> <p> <asp:label id="Message" runat=server/> </font> </form> </body> </html>

Controlar mltiples eventos de accin del control


Los controladores de eventos proporcionan a los programadores de pginas una forma limpia de estructurar lgicamente en una pgina ASP.NET. Por ejemplo, en el siguiente ejemplo se demuestra cmo conectar y controlar cuatro eventos de botn en una nica pgina.

<html> <script language="VB" runat="server"> Sub AddBtn_Click(Sender As Object, E As EventArgs) If Not (AvailableFonts.SelectedIndex = -1)

InstalledFonts.Items.Add(New ListItem(AvailableFonts.SelectedItem.Value)) AvailableFonts.Items.Remove(AvailableFonts.SelectedItem.Value) End If End Sub Sub AddAllBtn_Click(Sender As Object, E As EventArgs) Do While Not (AvailableFonts.Items.Count = 0) InstalledFonts.Items.Add(New ListItem(AvailableFonts.Items(0).Value)) AvailableFonts.Items.Remove(AvailableFonts.Items(0).Value) Loop End Sub Sub RemoveBtn_Click(Sender As Object, E As EventArgs) If Not (InstalledFonts.SelectedIndex = -1) AvailableFonts.Items.Add(New ListItem(InstalledFonts.SelectedItem.Value)) InstalledFonts.Items.Remove(InstalledFonts.SelectedItem.Value) End If End Sub Sub RemoveAllBtn_Click(Sender As Object, E As EventArgs) Do While Not (InstalledFonts.Items.Count = 0) AvailableFonts.Items.Add(New ListItem(InstalledFonts.Items(0).Value)) InstalledFonts.Items.Remove(InstalledFonts.Items(0).Value) Loop End Sub </script> <body> <h3><font face="Verdana">Administrar eventos mltiples de accin de control</font></h3> <p> Este ejemplo muestra cmo administrar eventos mltiples de accin de control provocados por controles diferentes &lt;asp:button&gt;. <p> <hr> <form action="controls4.aspx" runat=server> <table> <tr> <td> Fuentes disponibles </td> <td> <!-- Filler --> </td> <td> Fuentes instaladas </td> </tr> <tr>

<td> <asp:listbox id="AvailableFonts" width="100px" runat=server> <asp:listitem>Roman</asp:listitem> <asp:listitem>Arial Black</asp:listitem> <asp:listitem>Garamond</asp:listitem> <asp:listitem>Somona</asp:listitem> <asp:listitem>Symbol</asp:listitem> </asp:listbox> </td> <td> <!-- Filler --> </td> <td> <asp:listbox id="InstalledFonts" width="100px" runat=server> <asp:listitem>Times</asp:listitem> <asp:listitem>Helvetica</asp:listitem> <asp:listitem>Arial</asp:listitem> </asp:listbox> </td> </tr> <tr> <td> <!-- Filler --> </td> <td> <asp:button text="<<" OnClick="RemoveAllBtn_Click" runat=server/> <asp:button text="<" OnClick="RemoveBtn_Click" runat=server/> <asp:button text=">" OnClick="AddBtn_Click" runat=server/> <asp:button text=">>" OnClick="AddAllBtn_Click" runat=server/> </td> <td> <!-- Filler --> </td> </tr> </table> </form> </body> </html>

Realizar desplazamientos de pgina (escenario 1)


Desplazamiento por mltiples pginas es un escenario habitual en prcticamente todas las aplicaciones Web. En el siguiente ejemplo se demuestra cmo utilizar el control <asp:hyperlink runat=server> para desplazarse a otra pgina (pasando parmetros de cadenas de consulta personalizadas por el camino). En el ejemplo se demuestra, pues, cmo obtener acceso fcilmente a dichos parmetros de cadenas de consulta desde la pgina de destino.

<html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim RandomGenerator As Random RandomGenerator = New Random(DateTime.Now.Millisecond) Dim RandomNum As Integer

RandomNum = RandomGenerator.Next(0, 3) Select RandomNum Case 0: Name.Text = "Scott" Case 1: Name.Text = "Fred" Case 2: Name.Text = "Adam" End Select AnchorLink.NavigateUrl = "controls_navigationtarget.aspx?name=" & System.Web.HttpUtility.UrlEncode(Name.Text) End Sub </script> <body> <h3><font face="Verdana">Realizar exploracin de pginas (escenario 1)</font></h3> <p> Este ejemplo muestra cmo generar una etiqueta delimitadora HTML que hace que el cliente explore una nueva pgina cuando hace clic en el explorador. <p> <hr> <p> <asp:hyperlink id="AnchorLink" font-size=24 runat=server> Hola <asp:label id="Name" runat=server/> hacer clic en este vnculo </asp:hyperlink> </body> </html>

Realizar desplazamientos de pgina (escenario 2)


No todos los escenarios de desplazamiento de pginas se inician a travs de hipervnculos en el cliente. Las redirecciones y desplazamientos en el cliente tambin puede iniciarlas desde el servidor un programador de pginas ASP.NET llamando al mtodo Response.Redirect(url). Esto suele realizarse cuando se necesita la validacin en el servidor para alguna entrada del cliente antes de que el desplazamiento sea realmente efectivo. En el siguiente ejemplo se demuestra cmo utilizar el mtodo Response.Redirect para pasar parmetros a otra pgina de destino. Tambin se demuestra cmo obtener acceso fcilmente a dichos parmetros desde la pgina de destino.

<html> <script language="VB" runat="server"> Sub EnterBtn_Click(Sender As Object, E As EventArgs)

' Navigate to a new page (passing name as a querystring argument) if ' user has entered a valid name value in the <asp:textbox> If Not (Name.Text = "") Response.Redirect("Controls_NavigationTarget.aspx?name=" & System.Web.HttpUtility.UrlEncode(Name.Text)) Else Message.Text = "Escribir su nombre en el cuadro de texto" End If End Sub </script> <body> <h3><font face="Verdana">Realizar exploracin de pginas (escenario 2)</font></h3> <p> Este ejemplo muestra cmo explorar una nueva pgina desde el evento &lt;asp:button&gt; Click, pasando &lt;asp:textbox&gt; un valor como argumento de la cadena de consulta (una vez que se ha especificado el valor del cuadro de texto). <p> <hr> <form action="controls6.aspx" runat=server> <font face="Verdana"> Escribir su nombre: <asp:textbox id="Name" runat=server/> <asp:button text="Entrar" Onclick="EnterBtn_Click" runat=server/> <p> <asp:label id="Message" forecolor="red" font-bold="true" runat=server/> </font> </form> </body> </html>

Aplicar estilos a controles


El Web es un entorno flexible para interfaces de usuarios con variaciones extremas en la apariencia y sensacin de diferentes sitios Web. La amplia adopcin de hojas de estilo en cascada (CSS) es la gran responsable de los ricos diseos que se encuentran en el Web. Todos los controles de servidor HTML de ASP.NET y los controles de servidores Web se han diseado para proporcionar compatibilidad de primera clase con los estilos de CSS. En esta seccin se comenta cmo utilizar estilos en unin con controles de servidor y se demuestra el preciso control que se ejerce sobre la apariencia y sensacin de los formularios Web que proporciona.

Aplicar estilos a controles HTML


Las etiquetas HTML estndar admiten CSS a travs de un atributo de estilo que se puede establecer en una lista de pares atributo-valor delimitada por punto y coma. Para obtener informacin acerca de los atributos CSS admitidos por el explorador Internet Explorer, vea pgina Referencia de atributos CSS del sitio Web Workshop de MSDN. Todos los controles de servidor HTML de ASP.NET pueden aceptar estilos exactamente del mismo que las etiquetas HTML estndar. En el siguiente ejemplo se muestra un nmero de estilos ms la modo

aplicados a varios controles de servidor HTML. Si se visualiza el cdigo fuente en la pgina devuelta al cliente, se ver que estos estilos se pasan al explorador del procesamiento del control.

<html> <body> <h3><font face="verdana">Aplicacin de estilos a controles HTML</font></h3> <p><font face="verdana"><h4>Intervalo con estilo</h4></font><p> <span style="font: 12pt verdana; color:orange;font-weight:700" runat="server"> Texto literal dentro de un control Span con estilo </span> <p><font face="verdana"><h4>Botn con estilo</h4></font><p> <button style="font: 8pt verdana;background-color:lightgreen;border-color:black;width:100" runat="server">Hacer clic aqu</button> <p><font face="verdana"><h4>Entrada de texto con estilo</h4></font><p> Escriba texto: <p> <input type="text" value="Un, dos, tres" style="font: 14pt verdana;background-color:yellow;borderstyle:dashed;border-color:red;width:300;" runat="server"/> <p><font face="verdana"><h4>Entrada de seleccin con estilo</h4></font><p> Seleccione un elemento: <p> <select style="font: 14pt verdana;background-color:lightblue;color:purple;" runat="server"> <option>Elemento 1</option> <option>Elemento 2</option> <option>Elemento 3</option> </select> <p><font face="verdana"><h4>Botones de opcin con estilo</h4></font><p> Seleccione una opcin: <p> <span style="font: 16 pt verdana;font-weight:300"> <input type="radio" name="Mode" checked style="width:50;background-color:red;zoom:200%" runat="server"/>Opcin 1<br> <input type="radio" name="Mode" style="width:50;background-color:red;zoom:200%" runat="server"/>Opcin 2<br> <input type="radio" name="Mode" style="width:50;background-color:red;zoom:200%" runat="server"/>Opcin 3 </span> </body> </html>

CSS tambin define un atributo de clase que se puede establecer en una definicin de estilo CSS incluida en una seccin <style>...</style> del documento. Los atributos de clase facilitan la definicin de estilos y la aplicacin de los mismos a varias etiquetas sin tener que volver a definir el mismo estilo. Los estilos de controles de servidor HTML tambin se pueden establecer de esta forma, como se demuestra en el siguiente ejemplo.

<html> <head> <style>

.spanstyle { font: 12pt verdana; font-weight:700; color:orange; } .buttonstyle { font: 8pt verdana; background-color:lightgreen; border-color:black; width:100 } .inputstyle { font: 14pt verdana; background-color:yellow; border-style:dashed; border-color:red; width:300; } .selectstyle { font: 14pt verdana; background-color:lightblue; color:purple; } .radiostyle { width:50; background-color:red; zoom:200% } </style> </head> <body> <h3><font face="verdana">Aplicacin de estilos a controles HTML</font></h3> <p><font face="verdana"><h4>Intervalo con estilo</h4></font><p> <span class="spanstyle" runat="server"> Texto literal dentro de un control Span con estilo </span> <p><font face="verdana"><h4>Botn con estilo</h4></font><p> <button class="buttonstyle" runat="server">Hacer clic aqu</button> <p><font face="verdana"><h4>Entrada de texto con estilo</h4></font><p> Escriba texto: <p> <input type="text" value="Un, dos, tres" class="inputstyle" runat="server"/> <p><font face="verdana"><h4>Entrada de seleccin con estilo</h4></font><p> Seleccione un elemento: <p> <select class="selectstyle" runat="server"> <option>Elemento 1</option>

<option>Elemento 2</option> <option>Elemento 3</option> </select> <p><font face="verdana"><h4>Botones de opcin con estilo</h4></font><p> Seleccione una opcin: <p> <span style="font: 16 pt verdana;font-weight:300"> <input type="radio" name="Mode" checked class="radiostyle" runat="server"/>Opcin 1<br> <input type="radio" name="Mode" class="radiostyle" runat="server"/>Opcin 2<br> <input type="radio" name="Mode" class="radiostyle" runat="server"/>Opcin 3 </span> </body> </html>

Cuando se analiza una pgina ASP.NET, la informacin de estilo se llena en una propiedad Style (de tipo CssStyleCollection) de la clase System.Web.UI.HtmlControls.HtmlControl. Bsicamente, esta propiedad consiste en un diccionario que expone los estilos del control como coleccin de valores indizada por cadenas para cada clave de atributo de estilo. Por ejemplo, se puede utilizar el siguiente cdigo para establecer y, en consecuencia, recuperar el atributo de estilo width en un control de servidor HtmlInputText.

<script language="VB" runat="server" > Sub Page_Load(Sender As Object, E As EventArgs) MyText.Style("width") = "90px" Response.Write(MyText.Style("width")) End Sub </script> <input type="text" id="MyText" runat="server"/>

En el siguiente ejemplo se muestra cmo se puede manipular mediante programacin el estilo de un control de servidor HTML mediante la propiedad de coleccin Style.

<html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Message.InnerHtml &= "<h5>Obteniendo acceso a los estilos...</h5>" Message.InnerHtml &= "Color del intervalo: " & MySpan.Style("color") & "<br>" Message.InnerHtml &= "Ancho del cuadro de texto: " & MyText.Style("ancho") & "<p>" Message.InnerHtml &= "La coleccin de estilos de MySelect es: <br>" Dim Keys As IEnumerator Keys = MySelect.Style.Keys.GetEnumerator() Do While (Keys.MoveNext()) Dim Key As String Key = CStr(Keys.Current)

Message.InnerHtml &= "<img src='/quickstart/images/bullet.gif'>&nbsp;&nbsp;" Message.InnerHtml &= Key & "=" & MySelect.Style(Key) & "<br>" Loop End Sub Sub Submit_Click(Src As Object, E As EventArgs) Message.InnerHtml &= "<h5>Modificando estilos...</h5>" MySpan.Style("color") = ColorSelect.Value MyText.Style("ancho") = "600" Message.InnerHtml &= "Color del intervalo: " & MySpan.Style("color") & "<br>" Message.InnerHtml &= "Ancho del cuadro de texto: " & MyText.Style("ancho") End Sub </script> <body> <form runat="server"> <h3><font face="verdana">Obtener acceso a estilos mediante programacin</font></h3> <div style="font: 8pt verdana;background-color:cccccc;border-color:black;border-width:1;borderstyle:solid;padding:1,10,25,10"> <span id="Message" EnableViewState="false" runat="server"/> <p> Seleccione un color para el control Span: <p> <select id="ColorSelect" style="font: 11pt verdana;font-weight:700;" runat="server"> <option>red</option> <option>green</option> <option>blue</option> </select> <input type="submit" runat="server" Value="Cambiar estilo" OnServerClick="Submit_Click"> </div> <p><font face="verdana"><h4>Control Span con estilo</h4></font><p> <span id="MySpan" style="font: 12pt verdana; color:orange;font-weight:700" runat="server"> Texto literal dentro de un control Span con estilo </span> <p><font face="verdana"><h4>Botn con estilo</h4></font><p> <button id="MyButton" style="font: 8pt verdana;background-color:lightgreen;border-color:black;width:100" runat="server">Hacer clic aqu</button> <p><font face="verdana"><h4>Entrada de texto con estilo</h4></font><p> Escriba texto: <p> <input id="MyText" type="text" value="Un, dos, tres" style="font: 14pt verdana;background-color:yellow;borderstyle:dashed;border-color:red;width:300;" runat="server"/> <p><font face="verdana"><h4>Entrada de seleccin con estilo</h4></font><p> Seleccione un elemento: <p> <select id="MySelect" style="font: 14pt verdana;background-color:lightblue;color:purple;" runat="server"> <option>Elemento 1</option> <option>Elemento 2</option> <option>Elemento 3</option> </select>

<p><font face="verdana"><h4>Botones de opcin con estilo</h4></font><p> Seleccione una opcin: <p> <span style="font: 16 pt verdana;font-weight:300"> <input id="MyRadio1" type="radio" name="Mode" checked style="width:50;backgroundcolor:red;zoom:200%" runat="server"/>Opcin 1<br> <input id="MyRadio2" type="radio" name="Mode" style="width:50;background-color:red;zoom:200%" runat="server"/>Opcin 2<br> <input id="MyRadio3" type="radio" name="Mode" style="width:50;background-color:red;zoom:200%" runat="server"/>Opcin 3 </span> </form> </body> </html>

Aplicar estilos a controles de servidor Web


Los controles de servidor Web proporcionan un nivel adicional de compatibilidad con estilos mediante la adicin de varias propiedades con establecimiento inflexible de tipos para la configuracin del estilo habitual, como el color de fondo y de primer plano, el nombre y tamao de fuente, el ancho, el alto, etc. Estas propiedades de estilo representan un subconjunto de comportamientos de estilo disponible en HTML y se representan como propiedades "planas" expuestas directamente en la clase base System.Web.UI.WebControls.WebControl. La ventaja de utilizar estas propiedades es que proporcionan comprobacin de tipo en tiempo de compilacin y finalizacin de instrucciones en herramientas de programacin como Microsoft Visual Studio .NET. En el siguiente ejemplo se muestra un control WebCalendar al que se aplican varios estilos (se incluye un calendario sin estilos aplicados para comparar). Debe observarse que al establecer una propiedad que es un tipo de clase, como Font, se necesita utilizar la sintaxis de subpropiedad PropertyName-SubPropertyName.

html> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Propiedades de estilo</h4></font><p> <b>Sin estilo:</b> <p> <ASP:Calendar runat="server" /> <p> <b>Estilo: (Puede que, el estilo no sea el ms <i>correcto</i> pero al menos los calcetines van a juego...)</b> <p> <ASP:Calendar runat="server" BackColor="Beige" ForeColor="Brown" BorderWidth="3" BorderStyle="Solid" BorderColor="Black" Height="450" Width="450" Font-Size="12pt" Font-Name="Tahoma,Arial" Font-Underline="false" CellSpacing=2 CellPadding=2

ShowGridLines=true /> </form> </body> </html>

El espacio de nombres System.Web.UI.WebControls incluye una clase base Style que encapsula atributos de estilo comunes (clases de estilo adicionales, como TableStyle y TableItemStyle, heredadas desde esta clase base comn). Numerosos controles de servidor Web exponen propiedades de este tipo para especificar el estilo de elementos de procesamiento individuales del control. Por ejemplo, el control WebCalendar expone muchas de esas propiedades de estilo: DayStyle, WeekendDayStyle, TodayDayStyle, SelectedDayStyle, OtherMonthDayStyle y NextPrevStyle. Se pueden establecer propiedades individuales de estos estilos mediante la sintaxis de subpropiedad PropertyName-SubPropertyName, tal y como se muestra en el siguiente ejemplo.

<html> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Subpropiedades de estilo</h4></font><p> <ASP:Calendar runat="server" BackColor="Beige" ForeColor="Brown" BorderWidth="3" BorderStyle="Solid" BorderColor="Black" Height="450" Width="450" Font-Size="12pt" Font-Name="Tahoma,Arial" Font-Underline="false" CellSpacing=2 CellPadding=2 ShowGridLines=true TitleStyle-BorderColor="darkolivegreen" TitleStyle-BorderWidth="3" TitleStyle-BackColor="olivedrab" TitleStyle-Height="50px" DayHeaderStyle-BorderColor="darkolivegreen" DayHeaderStyle-BorderWidth="3" DayHeaderStyle-BackColor="olivedrab" DayHeaderStyle-ForeColor="black" DayHeaderStyle-Height="20px" DayStyle-Width="50px" DayStyle-Height="50px" TodayDayStyle-BorderWidth="3" WeekEndDayStyle-BackColor="palegoldenrod" WeekEndDayStyle-Width="50px" WeekEndDayStyle-Height="50px"

SelectedDayStyle-BorderColor="firebrick" SelectedDayStyle-BorderWidth="3" OtherMonthDayStyle-Width="50px" OtherMonthDayStyle-Height="50px" /> </form> </body> </html>

Una sintaxis ligeramente diferente permite que se declare cada propiedad Style como un elemento secundario anidado en etiquetas de control de servidor Web.

<ASP:Calendar ... runat="server"> <TitleStyle BorderColor="darkolivegreen" BorderWidth="3" BackColor="olivedrab" Height="50px" /> </ASP:Calendar>
En el siguiente ejemplo se muestra una sintaxis alternativa, pero es funcionalmente equivalente al anterior.

<html> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Subpropiedades de estilo</h4></font><p> <ASP:Calendar id="MyCalendar" runat="server" BackColor="Beige" ForeColor="Brown" BorderWidth="3" BorderStyle="Solid" BorderColor="Black" Height="450" Width="450" Font-Size="12pt" Font-Name="Tahoma,Arial" Font-Underline="false" CellSpacing=2 CellPadding=2 ShowGridLines=true > <TitleStyle BorderColor="darkolivegreen" BorderWidth="3" BackColor="olivedrab" Height="50px" /> <DayHeaderStyle BorderColor="darkolivegreen" BorderWidth="3" BackColor="olivedrab" ForeColor="black" Height="20px" /> <WeekEndDayStyle BackColor="palegoldenrod" Width="50px" Height="50px" /> <DayStyle Width="50px" Height="50px" />

<TodayDayStyle BorderWidth="3" /> <SelectedDayStyle BorderColor="firebrick" BorderWidth="3" /> <OtherMonthDayStyle Width="50px" Height="50px" /> </ASP:Calendar> </form> </body> </html>

Como sucede con los controles de servidor HTML, se pueden aplicar estilos a controles de servidor Web mediante una definicin de clase CSS. La clase base WebControl expone una propiedad String denominada CssClass para establecer la clase de estilo:

<html> <head> <style> .calstyle { position:absolute; left:25%; top:20% } </style> </head> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Propiedad CssClass</h4></font><p> <ASP:Calendar CssClass="calstyle" runat="server" BackColor="Beige" ForeColor="Brown" BorderWidth="3" BorderStyle="Solid" BorderColor="Black" Height="450" Width="450" Font-Size="12pt" Font-Name="Tahoma,Arial" Font-Underline="false" CellSpacing=2 CellPadding=2 ShowGridLines=true TitleStyle-BorderColor="darkolivegreen" TitleStyle-BorderWidth="3" TitleStyle-BackColor="olivedrab" TitleStyle-Height="50px" DayHeaderStyle-BorderColor="darkolivegreen" DayHeaderStyle-BorderWidth="3" DayHeaderStyle-BackColor="olivedrab" DayHeaderStyle-ForeColor="black" DayHeaderStyle-Height="20px"

DayStyle-Width="50px" DayStyle-Height="50px" TodayDayStyle-BorderWidth="3" WeekEndDayStyle-BackColor="palegoldenrod" WeekEndDayStyle-Width="50px" WeekEndDayStyle-Height="50px" SelectedDayStyle-BorderColor="firebrick" SelectedDayStyle-BorderWidth="3" OtherMonthDayStyle-Width="50px" OtherMonthDayStyle-Height="50px" /> </form> </body> </html>

Si se establece un atributo en un control de servidor que no se corresponde con ninguna propiedad con establecimiento inflexible de tipos, el atributo y el valor se llenan en la coleccin Attributes del control. De forma predeterminada, los controles de servidor procesarn estos atributos no modificados en el HTML devuelto al cliente del explorador solicitante. Esto significa que los atributos de estilo y de clase se pueden establecer directamente en controles de servidor Web en vez de utilizar las propiedades con establecimiento inflexible de tipo. Mientras que esto requiere entender algo del procesamiento real del control, tambin puede constituir una forma flexible de aplicar estilos. Resulta especialmente til con los controles estndar de entrada de formulario, tal y como se muestra en el siguiente ejemplo.

<html> <head> <style> .beige { background-color:beige } </style> </head> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Estilos CSS Expando</h4></font><p> <table style="font: 10pt verdana; background-color:tan" cellspacing=15> <tr> <td><b>Iniciar sesin: </b></td> <td><ASP:TextBox runat="server" class="beige" style="font-weight:700;"/></td> </tr> <tr> <td><b>Contrasea: </b></td> <td><ASP:TextBox TextMode="Password" runat="server" class="beige"/></td> </tr> <tr> <td><b>Seleccionar una vista: </b></td> <td>

<ASP:DropDownList class="beige" runat="server"> <ASP:ListItem>Escritorio predeterminado</ASP:ListItem> <ASP:ListItem>Mi cartera de acciones</ASP:ListItem> <ASP:ListItem>Mi lista de contactos</ASP:ListItem> </ASP:DropDownList> </td> </tr> <tr> <td>&nbsp;</td> <td><ASP:Button Text="Enviar" runat="server" class="beige"/></td> </tr> </table> </form> </body> </html>

Los estilos de controles de servidor Web tambin se pueden establecer mediante programacin con el mtodo ApplyStyle de la clase base WebControl, como en el cdigo que se muestra a continuacin.

<script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim MyStyle As New Style MyStyle.BorderColor = Color.Black MyStyle.BorderStyle = BorderStyle.Dashed MyStyle.BorderWidth = New Unit(1) MyLogin.ApplyStyle (MyStyle) MyPassword.ApplyStyle (MyStyle) MySubmit.ApplyStyle (MyStyle) End Sub </script> Login: <ASP:TextBox id="MyLogin" runat="server" />/<p/> Password: <ASP:TextBox id="MyPassword" TextMode="Password" runat="server" /> View: <ASP:DropDownList id="MySelect" runat="server"> ... </ASP:DropDownList>

En el siguiente ejemplo se muestra el cdigo anterior.

<%@ Import Namespace="System.Drawing" %> <html> <head> <style> .beige { background-color:beige } </style> </head> <script language="VB" runat="server">

Sub Page_Load(Src As Object, E As EventArgs) Dim MyStyle As Style MyStyle = New Style() MyStyle.BorderColor = Color.Black MyStyle.BorderStyle = BorderStyle.Dashed MyStyle.BorderWidth = New Unit(1) MyLogin.ApplyStyle (MyStyle) MyPassword.ApplyStyle (MyStyle) MySubmit.ApplyStyle (MyStyle) End Sub </script> <body> <form runat="server"> <h3><font face="verdana">Aplicacin de estilos a controles Web</font></h3> <p><font face="verdana"><h4>Aplicacin de estilos mediante programacin</h4></font><p> <table style="font: 10pt verdana; background-color:tan" cellspacing=15> <tr> <td><b>Iniciar sesin: </b></td> <td><ASP:TextBox id="MyLogin" runat="server" class="beige" style="font-weight:700;"/></td> </tr> <tr> <td><b>Contrasea: </b></td> <td><ASP:TextBox id="MyPassword" TextMode="Password" runat="server" class="beige"/></td> </tr> <tr> <td><b>Seleccionar una vista: </b></td> <td> <ASP:DropDownList id="MySelect" class="beige" runat="server"> <ASP:ListItem>Escritorio predeterminado</ASP:ListItem> <ASP:ListItem>Mi cartera de acciones</ASP:ListItem> <ASP:ListItem>Mi lista de contactos</ASP:ListItem> </ASP:DropDownList> </td> </tr> <tr> <td>&nbsp;</td> <td><ASP:Button id="MySubmit" Text="Enviar" runat="server" class="beige"/></td> </tr> </table> </form> </body> </html>

Resumen de la seccin
1. Los controles de servidor HTML de ASP.NET y las familias de controles de servidores Web proporcionan compatibilidad de primera clase con los estilos de CSS.

2. Los estilos pueden aplicarse estableciendo los atributos de estilo o de clase de un control. Se puede acceder a esta
configuracin mediante programacin a travs de la coleccin Attributes del control. En el caso de controles de servidor HTML, los valores individuales para claves de atributo de estilo se pueden recuperar desde la coleccin Style del control.

3. La configuracin de estilo ms habitual se expone en los controles de servidor Web como propiedades con establecimiento inflexible de tipos del mismo control.

4. El espacio de nombres System.Web.UI.WebControls incluye una clase base Style que encapsula atributos de estilo
comunes. Muchos controles de servidor Web exponen propiedades de este tipo para controlar elementos de procesamiento individuales.

5. Los estilos se pueden establecer mediante programacin en controles de servidor Web mediante el mtodo ApplyStyle de
la clase base WebControl.

Validacin de formularios de control de servidor Introduccin a la validacin


El marco de trabajo de los formularios Web incluye un conjunto de controles de servidor de validacin que proporcionan un modo sencillo a la vez que potente de comprobar errores en los formularios de entrada y, en caso necesario, mostrar mensajes al usuario. Los controles de validacin se agregan a una pgina de formularios Web con otros controles de servidor. Existen controles para tipos concretos de validacin, como la comprobacin de intervalos o la coincidencia de modelos, adems de RequiredFieldValidator, que se asegura de que un usuario omita un campo de entrada. Se puede adjuntar ms de un control de validacin para un control de entrada. Por ejemplo, se puede especificar que se necesita una entrada y que debe contener un intervalo especfico de valores. Los controles de validacin funcionan con un subconjunto limitado de controles de servidor HTML y Web. Para cada control, una propiedad especfica contiene el valor que se va a validar. En la siguiente tabla se enumeran los controles de entrada que pueden validarse. Control HtmlInputText HtmlTextArea HtmlSelect HtmlInputFile TextBox ListBox DropDownList RadioButtonList Propiedad de validacin Value Value Value Value Text SelectedItem.Value SelectedItem.Value SelectedItem.Value

Tipos de controles de validacin


El formulario de validacin ms sencillo es un campo requerido. Si el usuario introduce cualquier valor en un campo, es vlido. Si todos los campos de la pgina son vlidos, la pgina es vlida. En el siguiente ejemplo se muestra cmo utilizar el control RequiredFieldValidator.

<html> <head> <script language="VB" runat="server"> Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Pgina vlida" Else lblOutput.Text = "Algunos campos requeridos estn vacos" End If End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo simple RequiredField Validator</font></h3> <p> <form runat="server">

<table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Text="Rellenar los campos requeridos a continuacin" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /><br> </td> </tr> <tr> <td colspan=3> <font face=Verdana size=2><b>Informacin de la tarjeta de crdito</b></font> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Tipo de tarjeta:</font> </td> <td> <ASP:RadioButtonList id=RadioButtonList1 RepeatLayout="Flow" runat=server> <asp:ListItem>MasterCard</asp:ListItem> <asp:ListItem>Visa</asp:ListItem> </ASP:RadioButtonList> </td> <td align=middle rowspan=1> <asp:RequiredFieldValidator id="RequiredFieldValidator1" ControlToValidate="RadioButtonList1" Display="Static" InitialValue="" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Nmero de tarjeta:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" ControlToValidate="TextBox1" Display="Static" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Fecha de caducidad:</font> </td> <td> <ASP:DropDownList id=DropDownList1 runat=server> <asp:ListItem></asp:ListItem> <asp:ListItem >06/00</asp:ListItem> <asp:ListItem >07/00</asp:ListItem> <asp:ListItem >08/00</asp:ListItem> <asp:ListItem >09/00</asp:ListItem> <asp:ListItem >10/00</asp:ListItem> <asp:ListItem >11/00</asp:ListItem>

<asp:ListItem >01/01</asp:ListItem> <asp:ListItem >02/01</asp:ListItem> <asp:ListItem >03/01</asp:ListItem> <asp:ListItem >04/01</asp:ListItem> <asp:ListItem >05/01</asp:ListItem> <asp:ListItem >06/01</asp:ListItem> <asp:ListItem >07/01</asp:ListItem> <asp:ListItem >08/01</asp:ListItem> <asp:ListItem >09/01</asp:ListItem> <asp:ListItem >10/01</asp:ListItem> <asp:ListItem >11/01</asp:ListItem> <asp:ListItem >12/01</asp:ListItem> </ASP:DropDownList> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator3" ControlToValidate="DropDownList1" Display="Static" InitialValue="" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> <td> </tr> <tr> <td></td> <td> <ASP:Button id=Button1 text="Validar" OnClick="ValidateBtn_Click" runat=server /> </td> <td></td> </tr> </table> </form> </body> </html>

Tambin hay controles de validacin para tipos de validacin especficos, como la comprobacin de intervalos o la coincidencia de modelos. En la siguiente tabla se enumeran los controles de validacin. Nombre del control RequiredFieldValidator CompareValidator Descripcin Se asegura de que el usuario no omita ninguna entrada. Compara una entrada de usuario con un valor constante o un valor de propiedad de otro control mediante un operador de comparacin (menor que, igual a, mayor qu, entre otros). Comprueba que una entrada de usuario se encuentra entre los lmites superior e inferior especificados. Se pueden comprobar los intervalos entre pares de nmeros, caracteres alfabticos o fechas. Los lmites se pueden expresar como constantes.

RangeValidator

RegularExpressionValidator Comprueba que la entrada coincide con un patrn definido por una expresin regular. Este tipo de validacin permite comprobar secuencias de caracteres previsibles, como las de los nmeros de la seguridad social, las direcciones de correo electrnico, los nmeros de telfono y los cdigos postales, entre otras. CustomValidator Comprueba la entrada del usuario mediante lgica de validacin que codifica el usuario. Este tipo de validacin permite comprobar los valores derivados en tiempo de ejecucin. Muestra los errores de validacin en forma de resumen para todos los validadores de la pgina.

ValidationSummary

Validacin en el cliente

Los controles de validacin siempre realizan una comprobacin de validacin en el cdigo del servidor. No obstante, si el usuario trabaja con un explorador que admite DHTML, los controles de validacin tambin pueden realizar validaciones mediante secuencias de comandos del cliente. Con validacin en el cliente, se detectan algunos errores en el cliente cuando se enva el formulario al servidor. Si resulta que alguno de los validadores es un error, se cancela el envo del formulario al servidor y se muestra la propiedad Text del validador. Esto permite al usuario corregir lo escrito antes de enviar el formulario al servidor. Los valores de campo se revalidan en cuanto el campo que contiene el error pierde el foco, proporcionando as al usuario una rica experiencia de validacin interactiva. Debe observarse que el marco de trabajo de la pgina de formularios Web siempre realiza la validacin en el servidor, incluso cuando ya se ha realizado en el cliente. De esta forma, se evita que los usuarios puedan omitir la validacin mediante la suplantacin de otro usuario o de una transaccin previamente aprobada. La validacin en el cliente se ha habilitado de forma predeterminada. Si el cliente es capaz, la validacin de alto nivel se realiza automticamente. Para deshabilitar la validacin en el cliente, establezca la propiedad ClientTarget de la pgina en "Downlevel" ("Uplevel" fuerza la validacin en el cliente).

<%@ Page ClientTarget=UpLevel %> <html> <head> <script language="VB" runat="server"> Sub Page_Load If Not IsPostBack 'Validate intially to force *s to appear before the first round-trip Validate() End If End Sub Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Pgina vlida" Else lblOutput.Text = "Algunos campos requeridos estn vacos" End If End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo RequiredFieldValidator de cliente</font></h3> <p> <form runat="server"> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Name="lblOutput" Text="Rellenar los campos requeridos a continuacin" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /><br> </td> </tr> <tr> <td colspan=3> <font face=Verdana size=2><b>Informacin de la tarjeta de crdito</b></font> </td> </tr> <tr>

<td align=right> <font face=Verdana size=2>Tipo de tarjeta:</font> </td> <td> <ASP:RadioButtonList id=RadioButtonList1 RepeatLayout="Flow" onclick="ClientOnChange();" runat=server> <asp:ListItem>MasterCard</asp:ListItem> <asp:ListItem>Visa</asp:ListItem> </ASP:RadioButtonList> </td> <td align=middle rowspan=1> <asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" ControlToValidate="RadioButtonList1" ErrorMessage="*" Display="Static" InitialValue="" Width="100%"> </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Nmero de tarjeta:</font> </td> <td> <ASP:TextBox id=TextBox1 onchange="ClientOnChange();" runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ControlToValidate="TextBox1" ErrorMessage="*" Display="Static" Width="100%"> </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Fecha de caducidad:</font> </td> <td> <ASP:DropDownList id=DropDownList1 onchange="ClientOnChange();" runat=server> <asp:ListItem></asp:ListItem> <asp:ListItem >06/00</asp:ListItem> <asp:ListItem >07/00</asp:ListItem> <asp:ListItem >08/00</asp:ListItem> <asp:ListItem >09/00</asp:ListItem> <asp:ListItem >10/00</asp:ListItem> <asp:ListItem >11/00</asp:ListItem> <asp:ListItem >01/01</asp:ListItem> <asp:ListItem >02/01</asp:ListItem> <asp:ListItem >03/01</asp:ListItem> <asp:ListItem >04/01</asp:ListItem> <asp:ListItem >05/01</asp:ListItem> <asp:ListItem >06/01</asp:ListItem> <asp:ListItem >07/01</asp:ListItem> <asp:ListItem >08/01</asp:ListItem> <asp:ListItem >09/01</asp:ListItem> <asp:ListItem >10/01</asp:ListItem> <asp:ListItem >11/01</asp:ListItem> <asp:ListItem >12/01</asp:ListItem> </ASP:DropDownList>

</td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator3" runat="server" ControlToValidate="DropDownList1" ErrorMessage="*" Display="Static" InitialValue="" Width="100%"> </asp:RequiredFieldValidator> </td> <td> </tr> <tr> <td></td> <td> <ASP:Button id=Button1 text="Validar" OnClick="ValidateBtn_Click" runat="server" /> </td> <td></td> </tr> </table> </form> <script language=javascript> <!-function ClientOnChange() { if (typeof(Page_Validators) == "sin definir") return; document.all["lblOutput"].innerText = Page_IsValid ? "Pgina vlida" : "Algunos campos requeridos estn vacos"; } // --> </script> </body> </html>

Visualizar errores de validacin


Cuando se procesa la entrada del usuario (por ejemplo, cuando se enva el formulario), el marco de trabajo de la pgina de formularios Web pasa la entrada del usuario al control o controles de validacin asociados. Los controles de validacin comprueban la entrada del usuario y establecen una propiedad para indicar si la entrada pas la prueba de validacin. Tras haber procesado todos los controles de validacin, se establece la propiedad IsValid de la pgina; si cualquiera de los controles muestra que se produjo un error en la prueba de la validacin, toda la pgina se establecer como no vlida. Si un control de validacin es un error, un mensaje de error puede aparecer en la pgina por ese control de validacin o en un control ValidationSummary en cualquier otra parte de la pgina. Se visualiza el control ValidationSummary cuando la propiedad IsValid de la pgina es false. Sondea cada control de validacin de la pgina y agrega mensajes de texto expuestos por cada uno. En el siguiente ejemplo se muestra cmo visualizar errores con ValidationSummary.

<%@ Page clienttarget=downlevel %> <html> <head> <script language="VB" runat="server"> Sub ListFormat_SelectedIndexChanged(sender As Object, e As EventArgs)

' Change display mode of the validator summary when a new option ' is selected from the "ListFormat" dropdownlist valSum.DisplayMode = ListFormat.SelectedIndex End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo ValidationSummary</font></h3> <p> <form runat="server"> <table cellpadding=10> <tr> <td> <table bgcolor="#eeeeee" cellpadding=10> <tr> <td colspan=3> <font face=Verdana size=2><b>Informacin de la tarjeta de crdito</b></font> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Tipo de tarjeta:</font> </td> <td> <ASP:RadioButtonList id=RadioButtonList1 RepeatLayout="Flow" runat=server> <asp:ListItem>MasterCard</asp:ListItem> <asp:ListItem>Visa</asp:ListItem> </ASP:RadioButtonList> </td> <td align=middle rowspan=1> <asp:RequiredFieldValidator id="RequiredFieldValidator1" ControlToValidate="RadioButtonList1" ErrorMessage="Tipo de tarjeta. " Display="Static" InitialValue="" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Nmero de tarjeta:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" ControlToValidate="TextBox1" ErrorMessage="Nmero de tarjeta. " Display="Static" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td>

</tr> <tr> <td align=right> <font face=Verdana size=2>Fecha de caducidad:</font> </td> <td> <ASP:DropDownList id=DropDownList1 runat=server> <asp:ListItem></asp:ListItem> <asp:ListItem >06/00</asp:ListItem> <asp:ListItem >07/00</asp:ListItem> <asp:ListItem >08/00</asp:ListItem> <asp:ListItem >09/00</asp:ListItem> <asp:ListItem >10/00</asp:ListItem> <asp:ListItem >11/00</asp:ListItem> <asp:ListItem >01/01</asp:ListItem> <asp:ListItem >02/01</asp:ListItem> <asp:ListItem >03/01</asp:ListItem> <asp:ListItem >04/01</asp:ListItem> <asp:ListItem >05/01</asp:ListItem> <asp:ListItem >06/01</asp:ListItem> <asp:ListItem >07/01</asp:ListItem> <asp:ListItem >08/01</asp:ListItem> <asp:ListItem >09/01</asp:ListItem> <asp:ListItem >10/01</asp:ListItem> <asp:ListItem >11/01</asp:ListItem> <asp:ListItem >12/01</asp:ListItem> </ASP:DropDownList> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator3" ControlToValidate="DropDownList1" ErrorMessage="Fecha de caducidad. " Display="Static" InitialValue="" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> <td> </tr> <tr> <td></td> <td> <ASP:Button id=Button1 text="Validar" runat=server /> </td> <td></td> </tr> </table> </td> <td valign=top> <table cellpadding=20><tr><td> <asp:ValidationSummary ID="valSum" runat="server" HeaderText="Escribir un valor en los siguientes campos:" Font-Name="verdana" Font-Size="12" /> </td></tr></table> </td> </tr> </table> <font face="verdana" size="-1">Seleccionar el tipo de presentacin de resumen de validacin que desee: </font>

<asp:DropDownList id="ListFormat" AutoPostBack=true OnSelectedIndexChanged="ListFormat_SelectedIndexChanged" runat=server > <asp:ListItem>Lista</asp:ListItem> <asp:ListItem selected>Lista con vietas</asp:ListItem> <asp:ListItem>Un prrafo</asp:ListItem> </asp:DropDownList> </form> </body> </html>

Trabajar con CompareValidator


El control de servidor CompareValidator compara los valores de dos controles. CompareValidator utiliza tres propiedades clave para realizar la validacin. ControlToValidate y ControlToCompare contienen los valores que se van a comparar. Operator define el tipo de comparacin que se va a realizar, como por ejemplo Equal o Not Equal. CompareValidator realiza la validacin mediante la evaluacin de estas propiedades como expresin, tal y como se muestra a continuacin:

( ControlToValidate ControlToCompare )
Si la expresin se evala como true, el resultado de la validacin es vlido. El siguiente ejemplo muestra cmo utilizar el control CompareValidator.

<%@ Page clienttarget=downlevel %> <html> <head> <script language="VB" runat="server"> Sub Button1_OnSubmit(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Resultado: vlido" Else lblOutput.Text = "Resultado: no vlido" End If End Sub Sub lstOperator_SelectedIndexChanged(sender As Object, e As EventArgs) comp1.Operator = lstOperator.SelectedIndex comp1.Validate End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo CompareValidator</font></h3> <p>Escribir un valor en el cuadro de texto, seleccionar un operador de comparacin y, a continuacin, hacer clic en "Validar" para probar.</p> <form runat=server> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td> <h5><font face="Verdana">Cadena 1:</font></h5> <asp:TextBox id="txtComp" runat="server"></asp:TextBox> </td>

<td> <h5><font face="Verdana">Operador de comparacin:</font></h5> <asp:ListBox id="lstOperator" OnSelectedIndexChanged="lstOperator_SelectedIndexChanged" runat="server"> <asp:ListItem Selected Value="Equal" >Equal</asp:ListItem> <asp:ListItem Value="NotEqual" >NotEqual</asp:ListItem> <asp:ListItem Value="GreaterThan" >GreaterThan</asp:ListItem> <asp:ListItem Value="GreaterThanEqual" >GreaterThanEqual</asp:ListItem> <asp:ListItem Value="LessThan" >LessThan</asp:ListItem> <asp:ListItem Value="LessThanEqual" >LessThanEqual</asp:ListItem> </asp:ListBox> </td> <td> <h5><font face="Verdana">Cadena 2:</font></h5> <asp:TextBox id="txtCompTo" runat="server"></asp:TextBox><p> <asp:Button runat=server Text="Validar" ID="Button1" onclick="Button1_OnSubmit" /> </td> </tr> </table> <asp:CompareValidator id="comp1" ControlToValidate="txtComp" ControlToCompare = "txtCompTo" Type="String" runat="server"/> <br> <asp:Label ID="lblOutput" Font-Name="verdana" Font-Size="10pt" runat="server"/> </form> </body> </html>

Trabajar con RangeValidator


El control de servidor RangeValidator prueba si un valor de entrada produce un error en un intervalo dado. CompareValidator utiliza tres propiedades clave para realizar la validacin. ControlToValidate contiene el valor que hay que validar. MinimumValue y MaximumValue definen los valores mximo y mnimo del intervalo vlido. En el siguiente ejemplo se muestra cmo utilizar el control RangeValidator.

<%@ Page clienttarget=downlevel %> <html> <head> <script language="VB" runat="server"> Sub Button1_Click(sender As Object, e As EventArgs) rangeValInteger.Validate() If (rangeValInteger.IsValid) Then lblOutput1.Text = "Resultado: vlido" Else lblOutput1.Text = "Resultado: no vlido" End If rangeValDate.Validate() If (rangeValDate.IsValid) Then lblOutput2.Text = "Resultado: vlido" Else

lblOutput2.Text = "Resultado: no vlido" End If rangeValString.Validate() If (rangeValString.IsValid) Then lblOutput3.Text = "Resultado: vlido" Else lblOutput3.Text = "Resultado: no vlido" End If If (Page.IsValid) Then lblOutput.Text = "Resultado: pgina vlida" Else lblOutput.Text = "Resultado: pgina no vlida" End If End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo RangeValidator</font></h3> <p> <form runat="server"> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td> <h5><font face="Verdana">Valor para comprobar:</font></h5> <asp:TextBox id="txtComp1" runat="server"/> </td> <td> <h5><font face="Verdana">Tipo de datos: entero mn.(1), mx(10)</font></h5> </td> <td> <asp:Label id="lblOutput1" Font-Name="verdana" Font-Size="10pt" runat="server" /> </td> </tr> <tr valign="top"> <td> <h5><font face="Verdana">Valor para comprobar:</font></h5> <asp:TextBox id="txtComp2" runat="server"/> </td> <td> <h5><font face="Verdana">Tipo de datos: fecha mn.(2000/1/1), mx.(2001/1/1)</font></h5> </td> <td> <asp:Label id="lblOutput2" Font-Name="verdana" Font-Size="10pt" runat="server" /> </td> </tr> <tr valign="top"> <td> <h5><font face="Verdana">Valor para comprobar:</font></h5> <asp:TextBox id="txtComp3" runat="server"/> </td> <td> <h5><font face="Verdana">Tipo de datos: Mn.(Cerdo hormiguero), mx.(Cebra)</font></h5> </td> <td> <asp:Label id="lblOutput3" Font-Name="verdana" Font-Size="10pt" runat="server" /> </td>

</tr> </table> <asp:Button Text="Validar" ID="Button1" onclick="Button1_Click" runat="server" /> <asp:RangeValidator id="rangeValInteger" Type="Integer" ControlToValidate="txtComp1" MaximumValue="10" MinimumValue="1" runat="server"/> <asp:RangeValidator id="rangeValDate" Type="Date" ControlToValidate="txtComp2" MaximumValue="2001/1/1" MinimumValue="2000/1/1" runat="server"/> <asp:RangeValidator id="rangeValString" Type="String" ControlToValidate="txtComp3" MaximumValue="Zebra" MinimumValue="Aardvark" runat="server"/> <br> <asp:Label id="lblOutput" Font-Name="verdana" Font-Size="10pt" runat="server" /> </form> </body> </html>

Trabajar con expresiones regulares


El control de servidor RegularExpressionValidator confirma que la entrada coincide con un patrn definido por una expresin regular. Este tipo de validacin permite comprobar secuencias de caracteres previsibles, como las de los nmeros de la seguridad social, las direcciones de correo electrnico, los nmeros de telfono y los cdigos postales, entre otras. RegularExpressionValidator utiliza dos propiedades clave para realizar la validacin. ControlToValidate contiene el valor que hay que validar. ValidationExpression contiene la expresin regular con la que debe coincidir. En el siguiente ejemplo se muestra cmo utilizar el control RegularExpressionValidator.

<html> <head> <script language="VB" runat="server"> Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Pgina vlida" Else lblOutput.Text = "Pgina no vlida :-(" End If End Sub

</script> </head> <body> <h3><font face="Verdana">Ejemplo simple RegularExpressionValidator</font></h3> <p> <form runat="server"> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Text="Escribir cdigo postal con 5 dgitos" Font-Name="Verdana" FontSize="10pt" runat="server"/> </td> </tr> <tr> <td colspan=3> <font face=Verdana size=2><b>Informacin personal</b></font> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Cdigo postal:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server" ControlToValidate="TextBox1" ValidationExpression="^\d{5}$" Display="Static" Font-Name="verdana" Font-Size="10pt"> El cdigo postal debe tener 5 dgitos numricos </asp:RegularExpressionValidator> </td> </tr> <tr> <td></td> <td> <ASP:Button text="Validar" OnClick="ValidateBtn_Click" runat=server /> </td> <td></td> </tr> </table> </form> </body> </html>

<%@ Page clienttarget="downlevel" %> <html> <head>

<script language="VB" runat="server"> Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Pgina vlida" Else lblOutput.Text = "Pgina no vlida :-(" End If End Sub </script> </head> <body> <h3><font face="Verdana">Ms ejemplos de expresiones regulares</font></h3> <p> <form runat="server"> <table cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Text="Escribir valores para cada campo" Font-Name="Verdana" FontSize="10pt" runat="server" /> </td> </tr> <tr> <td colspan=3> <font face=Verdana size=2><b>Informacin personal</b></font> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Correo electrnico:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" ControlToValidate="TextBox1" Display="Dynamic" Font-Name="Verdana" Font-Size="10pt" > * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server" ControlToValidate="TextBox1" ValidationExpression="^[\w-]+@[\w-]+\.(com|net|org|edu|mil)$" Display="Static" Font-Name="verdana" Font-Size="10pt"> Escribir una direccin de correo electrnico vlida </asp:RegularExpressionValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Telfono:</font> </td>

<td> <ASP:TextBox id=TextBox2 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ControlToValidate="TextBox2" Display="Dynamic" Font-Name="Verdana" Font-Size="10pt"> * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="RegularExpressionValidator2" ControlToValidate="TextBox2" ValidationExpression="(^x\s*[0-9]{5}$)|(^(\([1-9][0-9]{2}\)\s)?[1-9][0-9]{2}-[0-9]{4}(\sx\s*[0-9]{5})?$)" Display="Static" Font-Name="verdana" Font-Size="10pt" runat=server> Debe tener el siguiente formato: (XXX) XXX-XXXX </asp:RegularExpressionValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>Cdigo postal:</font> </td> <td> <ASP:TextBox id=TextBox3 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator3" runat="server" ControlToValidate="TextBox3" Display="Dynamic" Font-Name="Verdana" Font-Size="10pt"> * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="RegularExpressionValidator3" ControlToValidate="TextBox3" ValidationExpression="^\d{5}$" Display="Static" Width="100%" Font-Name="verdana" Font-Size="10pt" runat=server> El cdigo postal debe tener 5 dgitos numricos </asp:RegularExpressionValidator> </td> </tr> <tr> <td></td> <td> <ASP:Button text="Validar" OnClick="ValidateBtn_Click" runat=server /> </td> <td></td> </tr> </table> </form> </body> </html>

Realizar validaciones personalizadas

El control de servidor CustomValidator llama a una funcin definida por el usuario para realizar validaciones que los validadores estndar no pueden controlar. La funcin personalizada puede ejecutarse en el servidor o en la secuencia de comandos del cliente, como JScript o VBScript. Para una validacin personalizada en el cliente, el nombre de la funcin personalizada debe identificarse en la propiedad ClientValidationFunction. La funcin personalizada debe presentar la siguiente estructura:

function myvalidator(source, arguments)


Debe observarse que source es el objeto CustomValidator del cliente, mientras que arguments es un objeto con dos propiedades, Value e IsValid. La propiedad Value es el valor que se validar y la propiedad IsValid es el booleano utilizado para establecer el resultado devuelto de la validacin. Para obtener la validacin personalizada del servidor, coloque la validacin personalizada en el delegado OnServerValidate del validador. En el siguiente ejemplo se muestra cmo utilizar el control CustomValidator.

<html> <head> <script language="VB" runat="server"> Sub ValidateBtn_OnClick(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "Pgina vlida" Else lblOutput.Text = "Pgina no vlida :-(" End If End Sub Sub ServerValidate (sender As Object, value As ServerValidateEventArgs) Try Dim num As Int32 = Int32.Parse(value.Value) If num Mod 2 = 0 Then value.IsValid = True Exit Sub End If Catch exc As Exception End Try value.IsValid = False End Sub </script> </head> <body> <h3><font face="Verdana">Ejemplo CustomValidator</font></h3> <p> <form runat="server"> <asp:Label id=lblOutput runat="server" Text="Escribir nmero par:" Font-Name="Verdana" FontSize="10pt" /><br> <p> <asp:TextBox id=Text1 runat="server" /> <asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" ControlToValidate="Text1" ErrorMessage="Escribir un nmero" Display="Dynamic" Font-Name="verdana" Font-Size="10pt"> </asp:RequiredFieldValidator>

<asp:CustomValidator id="CustomValidator1" runat="server" ControlToValidate="Text1" ClientValidationFunction="ClientValidate" OnServerValidate="ServerValidate" Display="Static" Font-Name="verdana" Font-Size="10pt"> No es un nmero par </asp:CustomValidator> <p> <asp:Button text="Validar" onclick="ValidateBtn_OnClick" runat="server" /> <script language="javascript"> function ClientValidate(source, arguments) { // even number? if (arguments.Value%2 == 0) arguments.IsValid = true; else arguments.IsValid = false; } </script> </form> </body> </html>

Combinarlo todo
En este ejemplo se muestra un formulario de registro tpico con las variaciones de controles de validacin comentadas en este tema.

<%@ Page Language="VB" %> <html> <body> <h3><font face="Verdana">Iniciar sesin del ejemplo del formulario de validacin</font></h3> <form method=post runat=server> <hr width=600 size=1 noshade> <center> <asp:ValidationSummary ID="valSum" runat="server" HeaderText="Debe escribir un valor vlido en los siguientes campos:" DisplayMode="SingleParagraph" Font-Name="verdana" Font-Size="12" /> <p> <!-- sign-in --> <table border=0 width=600>

<tr><td colspan=3> <table border=0 cellpadding=0 cellspacing=0 width="100%"> <tr><td> <font face=geneva,arial size=-1><b>Informacin de inicio de sesin</b></font> </td></tr> </table> </td></tr> <tr> <td align=right> <font face=Arial size=2>Direccin de correo electrnico:</font> </td> <td> <asp:TextBox id=email width=200px maxlength=60 runat=server /> </td> <td> <asp:RequiredFieldValidator id="emailReqVal" ControlToValidate="email" ErrorMessage="Correo electrnico. " Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="emailRegexVal" ControlToValidate="email" ErrorMessage="Correo electrnico. " Display="Static" ValidationExpression="^[\w-]+@[\w-]+\.(com|net|org|edu|mil)$" Font-Name="Arial" Font-Size="11" runat=server> La direccin de correo electrnico no es vlida, debe tener el siguiente formato: correo_electrnico@host.dominio. </asp:RegularExpressionValidator> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Contrasea:</font> </td> <td> <asp:TextBox id=passwd TextMode="Password" maxlength=20 runat=server/> </td> <td> <asp:RequiredFieldValidator id="passwdReqVal" ControlToValidate="passwd" ErrorMessage="Contrasea. " Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="passwdRegexBal" ControlToValidate="passwd" ErrorMessage="Contrasea. " ValidationExpression=".*[!@#$%^&*+;:].*" Display="Static" Font-Name="Arial" Font-Size="11" Width="100%" runat=server> La contrasea debe incluir uno de los siguientes caracteres (!@#$%^&amp;*+;:) </asp:RegularExpressionValidator> </td> </tr>

<tr> <td align=right> <font face=Arial size=2>Volver a escribir la contrasea:</font> </td> <td> <asp:TextBox id=passwd2 TextMode="Password" maxlength=20 runat=server/> </td> <td> <asp:RequiredFieldValidator id="passwd2ReqVal" ControlToValidate="passwd2" ErrorMessage="Vuelva a escribir la contrasea. " Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> <asp:CompareValidator id="CompareValidator1" ControlToValidate="passwd2" ControlToCompare="passwd" ErrorMessage="Vuelva a escribir la contrasea. " Display="Static" Font-Name="Arial" Font-Size="11" runat=server> Los campos de contrasea no coinciden </asp:CompareValidator> </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <!-- personalization information --> <tr><td colspan=3> <table border=0 cellpadding=0 cellspacing=0 width="100%"> <tr><td><font face=geneva,arial size=-1> <b>Informacin personal</b></font> </td></tr> </table> </td></tr> <tr> <td align=right> <font face=Arial size=2>Nombre:</font> </td> <td> <asp:TextBox id=fn maxlength=20 width=200px runat=server /> </td> <td> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Apellido:</font> </td> <td> <asp:TextBox id=ln maxlength=40 width=200px runat=server /> </td> <td> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Direccin:</font> </td> <td> <asp:TextBox id=address width=200px runat=server />

</td> <td> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Estado:</font> </td> <td> <asp:TextBox id=state width=30px maxlength=2 runat=server />&nbsp; <font face=Arial size=2>Cdigo postal:</font>&nbsp; <ASP:TextBox id=zip width=60px maxlength=5 runat=server /> </td> <td> <asp:RegularExpressionValidator id="RegularExpressionValidator1" ControlToValidate="zip" ErrorMessage="Cdigo postal. " ValidationExpression="^\d{5}$" Display="Static" Font-Name="Arial" Font-Size="11" runat=server> El cdigo postal debe tener 5 dgitos numricos </asp:RegularExpressionValidator> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Telfono:</font> </td> <td> <asp:TextBox id="phone" maxlength=20 runat="server" /> </td> <td> <asp:RequiredFieldValidator id="phoneReqVal" ControlToValidate="phone" ErrorMessage="Telfono. " Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="phoneRegexVal" ControlToValidate="phone" ErrorMessage="Telfono. " ValidationExpression="(^x\s*[0-9]{5}$)|(^(\([1-9][0-9]{2}\)\s)?[1-9][0-9]{2}-[0-9]{4}(\sx\s*[0-9]{5})?$)" Display="Static" Font-Name="Arial" Font-Size="11" runat=server> Debe tener el siguiente formato: (XXX) XXX-XXXX </asp:RegularExpressionValidator> </td> </tr> <tr><td colspan=3>&nbsp;</td></tr> <!-- Credit Card Info --> <tr> <td colspan=3> <font face=Arial size=2><b>Informacin de la tarjeta de crdito</b></font> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Tipo de tarjeta:</font>

</td> <td> <ASP:RadioButtonList id=ccType Font-Name="Arial" RepeatLayout="flow" runat=server> <asp:ListItem>MasterCard</asp:ListItem> <asp:ListItem>Visa</asp:ListItem> </ASP:RadioButtonList> </td> <td> <asp:RequiredFieldValidator id="ccTypeReqVal" ControlToValidate="ccType" ErrorMessage="Tipo de tarjeta. " Display="Static" InitialValue="" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Nmero de tarjeta:</font> </td> <td> <ASP:TextBox id="ccNum" runat=server /> </td> <td> <asp:RequiredFieldValidator id="ccNumReqVal" ControlToValidate="ccNum" ErrorMessage="Nmero de tarjeta. " Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> <asp:CustomValidator id="ccNumCustVal" ControlToValidate="ccNum" ErrorMessage="Nmero de tarjeta. " clientvalidationfunction="ccClientValidate" Display="Static" Font-Name="Arial" Font-Size="11" runat=server> El nmero de la tarjeta de crdito no es vlido, debe contener 16 dgitos. </asp:CustomValidator> </td> </tr> <tr> <td align=right> <font face=Arial size=2>Fecha de caducidad:</font> </td> <td> <ASP:DropDownList id=expDate runat=server> <asp:ListItem></asp:ListItem> <asp:ListItem >06/00</asp:ListItem> <asp:ListItem >07/00</asp:ListItem> <asp:ListItem >08/00</asp:ListItem> <asp:ListItem >09/00</asp:ListItem> <asp:ListItem >10/00</asp:ListItem> <asp:ListItem >11/00</asp:ListItem> <asp:ListItem >01/01</asp:ListItem> <asp:ListItem >02/01</asp:ListItem> <asp:ListItem >03/01</asp:ListItem> <asp:ListItem >04/01</asp:ListItem>

<asp:ListItem >05/01</asp:ListItem> <asp:ListItem >06/01</asp:ListItem> <asp:ListItem >07/01</asp:ListItem> <asp:ListItem >08/01</asp:ListItem> <asp:ListItem >09/01</asp:ListItem> <asp:ListItem >10/01</asp:ListItem> <asp:ListItem >11/01</asp:ListItem> <asp:ListItem >12/01</asp:ListItem> </ASP:DropDownList> </td> <td> <asp:RequiredFieldValidator id="expDateReqVal" ControlToValidate="expDate" ErrorMessage="Fecha de caducidad. " Display="Static" InitialValue="" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> </td> </tr> </table> <p> <input runat="server" type=submit value="Inicio de sesin"> <p> <hr width=600 size=1 noshade> <script language="javascript"> function ccClientValidate(source, arguments) { var cc = arguments.Value; var ccSansSpace; var i, digits, total; // SAMPLE ONLY. Not a real world actual credit card algo. // Based on ANSI X4.13, the LUHN formula (also known as the modulus 10 -- or mod 10 -- algorithm ) // is used to generate and/or validate and verify the accuracy of some credit-card numbers. // Get the number, parse out any non digits, should have 16 left ccSansSpace = cc.replace(/\D/g, ""); if(ccSansSpace.length != 16) { arguments.IsValid = false; return; // invalid ccn } // Convert to array of digits digits = new Array(16); for(i=0; i<16; i++) digits[i] = Number(ccSansSpace.charAt(i)); // Double & sum digits of every other number for(i=0; i<16; i+=2) { digits[i] *= 2; if(digits[i] > 9) digits[i] -= 9; } // Sum the numbers total = 0; for(i=0; i<16; i++) total += digits[i];

// Results if( total % 10 == 0 ) { arguments.IsValid = true; return; // valid ccn } else { arguments.IsValid = false; return; // invalid ccn } } </script> </form> </center> </body> </html>

Resumen de la seccin
1. Los controles de validacin se pueden utilizar para validar entradas en cualquier pgina Web. 2. Se puede utilizar ms de un control en un campo de entrada dado. 3. La validacin en el cliente se puede utilizar junto con la validacin en el servidor para mejorar las prestaciones del formulario.

4.

El control CustomValidator permite que el usuario defina criterios de validacin personalizados.

Controles de usuario de formularios Web Introduccin a los controles de usuario


Adems de los controles de servidor integrados que proporciona ASP.NET, se pueden definir fcilmente controles propios mediante las mismas tcnicas de programacin que ya conoce el usuario para escribir pginas de formularios Web. De hecho, con slo unas pocas modificaciones, se puede volver a utilizar casi cualquier pgina de formularios Web en otra pgina como control de servidor (debe tenerse en cuenta que un control de usuario es de tipo System.Web.UI.UserControl, que se hereda directamente desde System.Web.UI.Control). Una pgina de formularios Web utilizada como un control de servidor recibe el nombre de control de usuario para abreviar. Como convencin, se utiliza la extensin .ascx para indicar dichos controles. De esta forma, se evita que el archivo del control de usuario pueda ejecutarse como una pgina de formularios Web independiente (ms adelante se ver brevemente que existen unas pocas diferencias, aunque importantes, entre un control de usuario y una pgina de formularios Web). Los controles de usuario se incluyen en una pgina de formularios mediante una directiva Register:

<%@ Register TagPrefix="Acme" TagName="Message" Src="pagelet1.ascx" %>


TagPrefix determina un nico espacio de nombres para el control de usuario (de forma que los controles de mltiples usuarios con el mismo nombre pueden diferenciarse entre s). TagName es el nico nombre del control de usuario (se puede elegir cualquier nombre). El atributo Src es la ruta de acceso virtual al control de usuario, por ejemplo, "MyPagelet.ascx" o "/MyApp/Include/MyPagelet.ascx". Despus de registrar el control de usuario, se puede colocar la etiqueta de control de usuario en la pgina de formularios Web del mismo modo que se hara para un control de servidor ordinario (incluido el atributo runat="server"):

<Acme:Message runat="server"/>
En el siguiente ejemplo se muestra cmo se importa un control de usuario a otra pgina de formularios Web. Debe observarse que, en este caso, el control de usuario es slo un archivo esttico simple.

<%@ Register TagPrefix="Acme" TagName="Message" Src="pagelet1.ascx" %> <html>

<body style="font: 10pt verdana"> <h3>Control de usuario simple</h3> <Acme:Message runat="server"/> </body> </html>

Exponer propiedades de controles de usuario


Cuando se trata a una pgina de formularios Web como a un control, los mtodos y campos pblicos de dicho formulario Web se ascienden a propiedades pblicas (es decir, a atributos de etiqueta) y los mtodos del control tambin. En el siguiente ejemplo, se muestra una extensin del ejemplo de control de usuario anterior que agrega dos campos String pblicos. Debe observarse que estos campos pueden establecerse en la pgina contenedora tanto de forma declarativa, como mediante programacin.

<%@ Register TagPrefix="Acme" TagName="Message" Src="pagelet2.ascx" %> <html> <script language="VB" runat="server"> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) MyMessage.MessageText = "El texto del mensaje ha cambiado" MyMessage.Color = "red" End Sub </script> <body style="font: 10pt verdana"> <h3>Control de usuario simple con propiedades</h3> <form runat="server"> <Acme:Message id="MyMessage" MessageText="Mensaje personalizado" Color="blue" runat="server"/> <p> <asp:button text="Cambiar propiedades" OnClick="SubmitBtn_Click" runat=server/> </form> </body> </html>

Adems de ascender los campos pblicos a propiedades de control, se puede utilizar la sintaxis de propiedades. La sintaxis de la propiedad tiene la ventaja de poder ejecutar cdigo cuando se establecen o se recuperan las propiedades. En el siguiente ejemplo se muestra un control de usuario Address que ajusta las propiedades de texto de los controles TextBox que contiene. La ventaja de hacerlo as es que el control hereda libremente la administracin de estado automtica del control TextBox. Debe observarse que hay dos controles de usuario Address en la pgina de formularios Web contenedora que establece la propiedad Caption en "Billing Address" y "Shipping Address", respectivamente. El poder real de los controles de usuario se encuentra en este tipo de reutilizacin.

<%@ Register TagPrefix="Acme" TagName="Address" Src="pagelet3.ascx" %>

<html> <script language="VB" runat="server"> Sub SubmitBtn_Click(Sender As Object, E As EventArgs) MyLabel.Text &= "<b>Direccin de envo</b> " _ & ShipAddr.Address & ", " _ & ShipAddr.City & ", " _ & ShipAddr.StateName & ", " _ & ShipAddr.Zip & "<br>" MyLabel.Text &= "<b>Direccin de facturacin:</b> " _ & BillAddr.Address & ", " _ & BillAddr.City & ", " _ & BillAddr.StateName & ", " _ & BillAddr.Zip & "<br>" End Sub </script> <body style="font: 10pt verdana"> <h3>Control de usuario simple con propiedades</h3> <form runat="server"> <Acme:Address id="ShipAddr" Caption="Direccin de envo" Address="One Microsoft Way" City="Redmond" StateName="WA" Zip="98052" runat="server"/> <p> <Acme:Address id="BillAddr" Caption="Direccin de facturacin" runat="server"/> <p> <asp:button Text="Enviar formulario" OnClick="SubmitBtn_Click" runat=server/> </form> <asp:Label id="MyLabel" runat="server"/> </body> </html>

Otro control de usuario til consiste en un control Login para recoger nombres de usuario y contraseas.

<%@ Register TagPrefix="Acme" TagName="Login" Src="pagelet4.ascx" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If (Page.IsPostBack) MyLabel.Text &= "Id. de usuario " & MyLogin.UserId & "<br>"

MyLabel.Text &= "Contrasea " & MyLogin.Password & "<br>" End If End Sub </script> <body style="font: 10pt verdana"> <h3>Control de usuario de inicio de sesin</h3> <form runat="server"> <Acme:Login id="MyLogin" UserId="John Doe" Password="Secret" BackColor="beige" runat="server"/> </form> <asp:Label id="MyLabel" runat="server"/> </body> </html>

En este ejemplo, los controles de validacin de formulario se agregan al control de usuario Login.

<%@ Register TagPrefix="Acme" TagName="Login" Src="pagelet5.ascx" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If (Page.IsPostBack) Page.Validate() If (Page.IsValid) MyLabel.Text &= "Id. de usuario " & MyLogin.UserId & "<br>" MyLabel.Text &= "Contrasea " & MyLogin.Password & "<br>" End If End If End Sub </script> <body style="font: 10pt verdana"> <h3>Control de usuario de inicio de sesin</h3> <form runat="server"> <Acme:Login id="MyLogin" BackColor="beige" runat="server"/> </form> <asp:Label id="MyLabel" runat="server"/> </body> </html>

Encapsular eventos en un control de usuario

Los controles de usuario participan en todo el periodo de duracin de la ejecucin de la solicitud, en gran medida de la misma forma que los controles de servidor. Esto significa que un control de usuario puede controlar los propios eventos mediante la encapsulacin de algo de lgica de pgina de la pgina de formularios Web contenedora. En el siguiente ejemplo se muestra un control de usuario que enumera el producto que controla internamente las devoluciones propias. Debe observarse que el mismo control de usuario no dispone de un control <form runat="server"> de ajuste. Debido a que slo un control de formulario puede estar presente en una pgina (ASP.NET no permite formularios de servidor anidados), se deja que sea la pgina de formularios Web contenedora la que lo defina.

<%@ Register TagPrefix="Acme" TagName="BookList" Src="pagelet6.ascx" %> <html> <body style="font: 10pt verdana"> <h3>Control de usuario con un evento</h3> <form runat="server"> <Acme:BookList runat="server"/> </form> </body> </html>

Crear controles de usuario mediante programacin


Al igual que se pueden crear mediante programacin controles de servidor ordinarios, tambin se puede con los controles de usuario. El mtodo LoadControl de la pgina se utiliza para cargar el control de usuario pasando la ruta de acceso virtual al archivo de cdigo fuente del control de usuario:

Dim c1 As Control = LoadControl("pagelet7.ascx") CType(c1, (Pagelet7VB)).Category = "business" Page.Controls.Add(c1)

El tipo de control de usuario viene determinado por un atributo ClassName de la directiva Control. Por ejemplo, a un control de usuario guardado con el nombre de archivo "pagelet7.ascx" se le asigna el tipo inflexible "Pagelet7CS" de la siguiente manera:

<%@ Control ClassName="Pagelet7CS" %>


Puesto que el mtodo LoadControl devuelve un tipo de System.Web.UI.Control, debe convertirse al tipo inflexible adecuado para establecer propiedades individuales del control. Finalmente, el control de usuario se agrega a la coleccin ControlCollection de la pgina base.

<%@ Register TagPrefix="Acme" TagName="BookList" Src="pagelet7.ascx" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Page.Controls.Add(New HtmlGenericControl("hr")) Dim c1 As Control = LoadControl("pagelet7.ascx") CType(c1, Pagelet7VB).Category = "business" Page.Controls.Add(c1) Page.Controls.Add(New HtmlGenericControl("hr"))

Dim c2 As Control = LoadControl("pagelet7.ascx") CType(c2, Pagelet7VB).Category = "trad_cook" Page.Controls.Add(c2) Page.Controls.Add(New HtmlGenericControl("hr")) Dim c3 As Control = LoadControl("pagelet7.ascx") CType(c3, Pagelet7VB).Category = "mod_cook" Page.Controls.Add(c3) End Sub </script> <body style="font: 10pt verdana"> <h3>Crear controles de usuario mediante programacin</h3> </body> </html>

Importante: El tipo inflexible de un control de usuario est disponible para la pgina de formularios Web contenedora slo si se incluye una directiva Register para el control de usuario (incluso si no hay realmente ninguna etiqueta de control de usuario declarada).

Resumen de la seccin
1. Los controles de usuario permiten a los programadores definir fcilmente controles personalizados mediante las mismas tcnicas de programacin que para escribir pginas de formularios Web. 2. Como convencin, se utiliza una extensin .ascx de nombre de archivo para indicar dichos controles. De esta forma, se evita que un archivo del control de usuario pueda ejecutarse como una pgina de formularios Web independiente.

3. 4.

Los controles de usuario se incluyen en otra pgina de formularios Web mediante una directiva Register que especifica TagPrefix, TagName y Src location. Despus de registrar el control de usuario, se puede colocar una etiqueta de control de usuario en una pgina de formularios Web del mismo modo que se hara para un control de servidor ordinario (incluido el atributo runat="server"). 5. Los campos, propiedades y mtodos pblicos de un control de usuario se ascienden a propiedades pblicas (atributos de etiqueta) y mtodos del control de la pgina de formularios Web contenedora. 6. Los controles de usuario participan en todo el perodo de duracin de la ejecucin de cada solicitud y puede controlar los propios eventos mediante la encapsulacin de la lgica de pgina de la pgina de formularios Web contenedora. 7. Los controles de usuario deberan contener cualquier control de formulario pero deberan confiar en la pgina de formularios Web contenedora para incluir una en caso necesario.

8. 9.

Los controles de usuario pueden crearse mediante programacin al utilizar el mtodo LoadControl de la clase System.Web.UI.Page. El tipo del control de usuario viene determinado por el motor de tiempo de ejecucin de ASP.NET, segn la convencin filename_extension. El tipo inflexible de un control de usuario est disponible para la pgina de formularios Web contenedora slo si se incluye una directiva Register para el control de usuario (incluso si no hay realmente ninguna etiqueta de control de usuario declarada).

Controles de servidor de enlace de datos Informacin general y sintaxis del enlace de datos
ASP.NET introduce una nueva sintaxis declarativa de enlace de datos. Esta sintaxis tan extremadamente flexible permite al programador enlazar no slo con orgenes de datos, sino tambin con propiedades simples, colecciones, expresiones e incluso con resultados de eventos devueltos de llamadas a mtodos. En la siguiente tabla se muestran algunos ejemplos de la nueva sintaxis. Propiedad simple Coleccin Expresin Resultado del mtodo Customer: <%# custID %> Orders: <asp:ListBox id="List1" datasource='<%# myArray %>' runat="server"> Contact: <%# ( customer.First Name + " " + customer.LastName ) %> Outstanding Balance: <%# GetBalance(custID) %>

Aunque esta sintaxis se parece al mtodo abreviado de ASP para Response.Write (<%= %>), su comportamiento es bastante diferente. Mientras que el mtodo abreviado Response.Write de ASP se evalu al procesar la pgina, la sintaxis de enlace de datos de ASP.NET slo se evala cuando se invoca al mtodo DataBind.

DataBind es un mtodo de Page y de todos los controles de servidor. Cuando se llama a DataBind en un control primario, desciende en cascada a todos los controles secundarios de dicho control. As pues, por ejemplo DataList1.DataBind() invoca al mtodo DataBind en cada control de las plantillas de DataList. Al llamar a DataBind en Page (Page.DataBind() o simplemente DataBind()) se provoca que todas las expresiones de enlace de datos de la pgina se evalen. DataBind suele llamarse desde el evento Page_Load, tal y como se muestra en el siguiente ejemplo.

Protected Sub Page_Load(Src As Object, E As EventArgs) DataBind() End Sub

Se puede utilizar una expresin de enlace casi en cualquier parte de la seccin declarativa de una pgina .aspx, suponiendo que evale el tipo de datos esperado en tiempo de ejecucin. Los anteriores ejemplos de propiedad simple, expresin y mtodo muestran texto al usuario cuando se evala. En estos casos, la expresin de enlace de datos debe evaluar a un valor de tipo String. En el ejemplo de la coleccin, la expresin de enlace de datos evala a un valor de tipo vlido para la propiedad DataSource de ListBox. Puede resultar necesario convertir el tipo de valor en la expresin de enlace para producir el resultado deseado. Por ejemplo, si count es de tipo integer:

Number of Records: <%# count.ToString() %>

Enlazar con propiedades simples


La sintaxis de enlace de datos de ASP.NET admite enlazar con variables pblicas, propiedades de Page y propiedades de otros controles de la pgina. En el siguiente ejemplo se muestra cmo enlazar con una variable pblica y una propiedad simple de la pgina. Debe observarse que estos valores se inicializan antes de llamar a DataBind().

<html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) Page.DataBind End Sub ReadOnly Property custID() As String Get Return "ALFKI" End Get End Property ReadOnly Property orderCount() As Integer Get Return 11 End Get End Property </script> </head> <body> <h3><font face="Verdana">Enlace de datos de una propiedad de la pgina</font></h3> <form runat=server> Cliente: <b><%# custID %></b><br> rdenes de apertura: <b><%# orderCount %></b>

</form> </body> </html>

En el siguiente ejemplo se muestra cmo enlazar con una propiedad de otro control.

<html> <head> <script language="VB" runat="server"> Sub SubmitBtn_Click(sender As Object, e As EventArgs) ' Rather than explictly pull out the variable from the "StateList" ' and then manipulate a label control, just call "Page.DataBind". ' This will evaluate any <%# %> expressions within the page Page.DataBind End Sub </script> </head> <body> <h3><font face="Verdana">Enlace de datos de una propiedad de otro control de servidor</font></h3> <form runat=server> <asp:DropDownList id="StateList" runat="server"> <asp:ListItem>CA</asp:ListItem> <asp:ListItem>IN</asp:ListItem> <asp:ListItem>KS</asp:ListItem> <asp:ListItem>MD</asp:ListItem> <asp:ListItem>MI</asp:ListItem> <asp:ListItem>OR</asp:ListItem> <asp:ListItem>TN</asp:ListItem> <asp:ListItem>UT</asp:ListItem> </asp:DropDownList> <asp:button Text="Enviar" OnClick="SubmitBtn_Click" runat=server/> <p> Estado seleccionado: <asp:label text='<%# StateList.SelectedItem.Text %>' runat=server/> </form> </body> </html>

Enlazar con colecciones y listas


Los controles de servidor de lista, como DataGrid, ListBox y HTMLSelect, utilizan una coleccin como origen de datos. En los siguientes ejemplos se muestra cmo enlazar con los tipos de coleccin de Common Language Runtime habituales. Estos controles slo se pueden enlazar a colecciones que admiten las interfaces IEnumerable, ICollection o IListSource. Lo ms habitual ser enlazar con ArrayList, Hashtable, DataView y DataReader.

En el siguiente ejemplo se muestra cmo enlazar con ArrayList.

<html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim values as ArrayList= new ArrayList() values.Add ("IN") values.Add ("KS") values.Add ("MD") values.Add ("MI") values.Add ("OR") values.Add ("TN") DropDown1.DataSource = values DropDown1.DataBind End If End Sub Sub SubmitBtn_Click(sender As Object, e As EventArgs) Label1.Text = "Su eleccin: " + DropDown1.SelectedItem.Text End Sub </script> </head> <body> <h3><font face="Verdana">Enlace de datos de DropDownList</font></h3> <form runat=server> <asp:DropDownList id="DropDown1" runat="server" /> <asp:button Text="Enviar" OnClick="SubmitBtn_Click" runat=server/> <p> <asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server" /> </form> </body> </html>

En el siguiente ejemplo se muestra cmo enlazar con DataView. Debe observarse que la clase DataView se define en el espacio de nombres System.Data.

<%@ Import namespace="System.Data" %> <html> <head>

<script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim dt As DataTable Dim dr As DataRow Dim i As Integer 'create a DataTable dt = New DataTable dt.Columns.Add(New DataColumn("IntegerValue", GetType(Integer))) dt.Columns.Add(New DataColumn("StringValue", GetType(String))) dt.Columns.Add(New DataColumn("DateTimeValue", GetType(DateTime))) dt.Columns.Add(New DataColumn("BooleanValue", GetType(Boolean))) 'Make some rows and put some sample data in For i = 1 To 9 dr = dt.NewRow() dr(0) = i dr(1) = "Elemento " + i.ToString() dr(2) = DateTime.Now.ToShortTimeString If (i Mod 2 <> 0) Then dr(3) = True Else dr(3) = False End If 'add the row to the datatable dt.Rows.Add(dr) Next dataGrid1.DataSource = new DataView(dt) dataGrid1.DataBind End If End Sub </script> </head> <body> <h3><font face="Verdana">Enlace de datos de DataView</font></h3> <form runat=server> <asp:DataGrid id="dataGrid1" runat="server" BorderColor="black" BorderWidth="1" GridLines="Both" CellPadding="3" CellSpacing="0" HeaderStyle-BackColor="#aaaadd" /> </form> </body> </html>

En el siguiente ejemplo se muestra cmo enlazar con Hashtable.

<html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim h As Hashtable = new Hashtable() h.Add ("key1", "valor1") h.Add ("key2", "valor2") h.Add ("key3", "valor3") MyDataList.DataSource = h MyDataList.DataBind End If End Sub </script> </head> <body> <h3><font face="Verdana">Enlace de datos de una tabla Hash</font></h3> <form runat=server> <asp:DataList id="MyDataList" runat="server" BorderColor="black" BorderWidth="1" GridLines="Both" CellPadding="4" CellSpacing="0" > <ItemTemplate> <%# Container.DataItem.Key %> : <%# Container.DataItem.Value %> </ItemTemplate> </asp:DataList> </form> </body> </html>

Enlazar expresiones o mtodos


A menudo se desea manipular los datos antes de enlazar con la pgina o con un control. En el siguiente ejemplo se muestra cmo enlazar con una expresin y con el valor devuelto de un mtodo.

<html> <head> <script language="VB" runat="server">

Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim values as ArrayList= new ArrayList() values.Add (0) values.Add (1) values.Add (2) values.Add (3) values.Add (4) values.Add (5) values.Add (6) DataList1.DataSource = values DataList1.DataBind End If End Sub Function EvenOrOdd(number As Integer) As String If (number Mod 2 <> 0) Then Return "Impar" Else Return "Par" End If End Function </script> </head> <body> <h3><font face="Verdana">Enlace de datos de mtodos y expresiones</font></h3> <form runat=server> <asp:DataList id="DataList1" runat="server" BorderColor="black" BorderWidth="1" GridLines="Both" CellPadding="3" CellSpacing="0" > <ItemTemplate> Valor del nmero: <%# Container.DataItem %> Par o impar: <%# EvenOrOdd(Container.DataItem) %> </ItemTemplate> </asp:datalist> </form> </body> </html>

DataBinder.Eval
El marco de trabajo ASP.NET proporciona un mtodo esttico que evala expresiones de enlace de datos enlazadas en tiempo de ejecucin y, de forma opcional, aplica un formato de cadena al resultado. DataBinder.Eval resulta prctico en cuanto a que elimina gran parte de la conversin de tipos explcita que debe realizar el programador para convertir valores en el tipo de datos deseado. Resulta especialmente til al enlazar datos con controles en una lista con plantillas, ya que con frecuencia la fila de datos y el campo de datos deben estar convertidos.

Considrese el siguiente ejemplo, en el que un entero se visualiza como una cadena de moneda. Con la sintaxis de enlace de datos estndar de ASP.NET, se debe realizar primero la conversin del tipo de la fila de datos para recuperar el campo de datos, IntegerValue. A continuacin, se pasa como argumento al mtodo String.Format.

<%# String.Format("{0:c}", (CType(Container.DataItem, DataRowView)("IntegerValue"))) %>

Esta sintaxis puede resultar compleja y difcil de recordar. En contraste, DataBinder.Eval es simplemente un mtodo con tres argumentos: el contenedor que da nombre al elemento de datos, el nombre del campo de datos y una cadena de formato. En una lista con plantillas, como DataList, DataGrid o Repeater, el contenedor que da nombre es siempre Container.DataItem. Page es otro contenedor de nombres que se puede utilizar con DataBinder.Eval.

<%# DataBinder.Eval(Container.DataItem, "IntegerValue", "{0:c}") %>

El argumento de cadena de formato es opcional. Si se omite, DataBinder.Eval devuelve un valor de tipo object, tal y como se muestra en el siguiente ejemplo.

<%# CType(DataBinder.Eval(Container.DataItem, "BoolValue"), Boolean) %>

Es importante tener en cuenta que DataBinder.Eval puede conllevar una notable reduccin de rendimiento sobre la sintaxis de enlace de datos estndar ya que utiliza la reflexin en tiempo de ejecucin. DataBinder.Eval debe utilizarse de forma juiciosa, sobre todo cuando no se necesita el formato de cadena.

<%@ Import namespace="System.Data" %> <html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim dt As DataTable Dim dr As DataRow Dim i As Integer 'create a DataTable dt = New DataTable dt.Columns.Add(New DataColumn("IntegerValue", GetType(Integer))) dt.Columns.Add(New DataColumn("StringValue", GetType(String))) dt.Columns.Add(New DataColumn("DateTimeValue", GetType(DateTime))) dt.Columns.Add(New DataColumn("BoolValue", GetType(Boolean))) 'Make some rows and put some sample data in For i = 0 To 8 dr = dt.NewRow() dr(0) = i dr(1) = "Elemento " + i.ToString() dr(2) = DateTime.Now.ToShortTimeString If (i Mod 2 <> 0) Then dr(3) = True Else dr(3) = False

End If 'add the row to the datatable dt.Rows.Add(dr) Next dataList1.DataSource = new DataView(dt) dataList1.DataBind End If End Sub </script> </head> <body> <h3><font face="Verdana">Enlace de datos utilizando DataBinder.Eval</font></h3> <form runat=server> <asp:DataList id="dataList1" runat="server" RepeatColumns="3" Width="80%" BorderColor="black" BorderWidth="1" GridLines="Both" CellPadding="4" CellSpacing="0" > <ItemTemplate> Fecha de pedido: <%# DataBinder.Eval(Container.DataItem, "DateTimeValue", "{0:d}") %> <p> Cantidad: <%# DataBinder.Eval(Container.DataItem, "IntegerValue", "{0:N2}") %> <p> Elemento: <%# DataBinder.Eval(Container.DataItem, "StringValue") %> Fecha de pedido: <asp:CheckBox id=chk1 Checked='<%# DataBinder.Eval(Container.DataItem, "BoolValue") %>' runat=server/> <p> </ItemTemplate> </asp:Datalist> </form> </body> </html>

Resumen de la seccin
1. La sintaxis declarativa del enlace de datos de ASP.NET utiliza la notacin <%# %>. 2. Se puede enlazar con orgenes de datos, propiedades de la pgina u otro control, colecciones, expresiones y resultados devueltos desde llamadas a mtodos.

3.

Los controles de lista slo se pueden enlazar con colecciones que admiten las interfaces IEnumerable, ICollection o IListSource, como ArrayList, Hashtable, DataView y DataReader.

4.

DataBinder.Eval es un mtodo esttico para enlazar en tiempo de ejecucin. La sintaxis correspondiente puede ser ms simple que la sintaxis de enlace de datos estndar, pero el rendimiento es ms lento.

Acceso a datos en el servidor


Introduccin a los datos del servidor
El acceso a datos es la esencia de cualquier aplicacin del mundo real y ASP.NET proporciona un nutrido conjunto de controles que se integran bien con las API de acceso administrado a datos que proporciona Common Language Runtime. En esta seccin se describen varias iteraciones de un ejemplo que utiliza el control DataGrid de ASP.NET para enlazar con los resultados de consultas SQL y archivos de datos XML. Tambin se supone cierta familiaridad con los fundamentos de bases de datos y el lenguaje de consulta SQL. El acceso a datos en el servidor es exclusivo en cuanto a la ausencia bsica de informacin de estado de las pginas Web, lo que presenta algunas dificultades al intentar realizar transacciones como insertar o actualizar registros a partir de un conjunto de datos recuperados desde una base de datos. Como se ver en esta misma seccin, el control DataGrid puede ayudar a administrar estas dificultades, lo que permite concentrarse ms en la lgica de la aplicacin y menos en los detalles de la administracin del estado y el control de eventos.

Conexiones, comandos y conjuntos de datos


Common Language Runtime proporciona un conjunto completo de interfaces API de acceso a datos administrados para el desarrollo de aplicaciones con un uso intensivo de datos. Estas API ayudan a extraer los datos y a presentarlos de forma coherente sin importar el origen real (SQL Server, OLEDB, XML, entre otros). Bsicamente, hay tres objetos con los que ms se trabaja: conexiones, comandos y conjuntos de datos.

Una conexin representa una conexin fsica a algn almacn de datos, como SQL Server o un archivo XML.

Un comando representa una directiva para recuperar (select) desde el almacn de datos o manipular dicho almacn (insert, update, delete). Un conjunto de datos representa los datos reales con los que trabaja una aplicacin. Hay que tener en cuenta que los conjuntos de datos se encuentran siempre desconectados de la conexin de origen y el modelo de datos correspondiente, y que pueden modificarse de forma independiente. Sin embargo, los cambios que se realizan en un conjunto de datos pueden reconciliarse fcilmente con el modelo de datos originario. Para ver una descripcin ms detallada de la solucin de acceso a datos administrada en Common Language Runtime, lea la seccin Informacin general de ADO.NET de este tutorial.

Obtener acceso a datos basados en SQL


Una aplicacin suele necesitar realizar una o ms consultas a la base de datos de SQL en lo que respecta a seleccionar, insertar, actualizar o eliminar. En la siguiente tabla se muestra un ejemplo de cada una de estas consultas. Consulta Seleccin simple Seleccin combinada Insertar Actualizar Eliminar Ejemplo SELECT * from Employees WHERE FirstName = 'Bradley'; SELECT * from Employees E, Managers M WHERE E.FirstName = M.FirstName; INSERT into Employees VALUES ('123-45-6789','Bradley','Millington','Program Manager'); UPDATE Employees SET Title = 'Development Lead' WHERE FirstName = 'Bradley'; DELETE from Employees WHERE Productivity < 10;

Con el fin de proporcionar a la pgina acceso a las clases que se necesitarn para realizar un acceso a datos de SQL, hay que importar los espacios de nombres System.Data y System.Data.SqlClient a la pgina en cuestin.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>


Para realizar una consulta de seleccin en una base de datos de SQL, es necesario crear SqlConnection para la base de datos pasando la cadena de conexin y, a continuacin, hay que construir un objeto SqlDataAdapter con la instruccin de consulta. Para llenar un objeto DataSet con los resultados de la consulta, hay que llamar al mtodo Fill del comando.

Dim myConnection As New

SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim myCommand As New SqlDataAdapter("select * from Authors", myConnection) Dim ds As New DataSet() myCommand.Fill(ds, "Authors")

Tal y como ya se ha comentado en esta misma seccin, la ventaja de utilizar un conjunto de datos consiste en que proporciona una vista desconectada de la base de datos. Se puede operar con un conjunto de datos de la aplicacin y, posteriormente, cotejar los cambios con la base de datos real. En el caso de aplicaciones cuya ejecucin es de larga duracin, ste suele ser el mejor enfoque. En el caso de aplicaciones Web, se suelen realizar operaciones breves con cada solicitud (normalmente, slo para visualizar los datos). A menudo, no se necesita mantener un objeto DataSet en una serie de varias solicitudes. Para situaciones como stas, se puede utilizar SqlDataReader. SqlDataReader proporciona un puntero de tipo slo hacia delante de slo lectura sobre los datos recuperados desde una base de datos de SQL. Para utilizar SqlDataReader, se declara un SqlCommand en vez de un SqlDataAdapter. SqlCommand expone un mtodo ExecuteReader que devuelve SqlDataReader. Tambin hay que observar que se debe abrir y cerrar explcitamente SqlConnection cuando se utiliza SqlCommand. Despus de una llamada a ExecuteReader, SqlDataReader puede enlazarse a un control del servidor ASP.NET, tal y como se ver en la siguiente seccin.

Dim myConnection As SqlConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim myCommand As SqlCommand = New SqlCommand("select * from Authors", myConnection) myConnection.Open() Dim dr As SqlDataReader = myCommand.ExecuteReader() ... myConnection.Close()

Al ejecutar comandos que no necesitan devolucin de datos, como los de insertar, actualizar y eliminar, tambin se utiliza SqlCommand. El comando se emite llamando a un mtodo ExecuteNonQuery, que devuelve el nmero de filas afectadas. Hay que tener en cuenta que la conexin debe abrirse de forma explcita cuando se utiliza el comando SqlCommand. SqlDataAdapter controla automticamente la apertura de la conexin para el usuario.

Dim myConnection As New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim myCommand As New SqlCommand( _ "UPDATE Authors SET phone='(800) 555-5555' WHERE au_id = '123-45-6789'", _ myConnection) myCommand.Connection.Open() myCommand.ExecuteNonQuery() myCommand.Connection.Close()

Importante: siempre hay que acordarse de cerrar la conexin en el modelo de datos antes de que se termine de ejecutar la pgina. Si el usuario no cierra la conexin, se puede agotar el lmite de conexin de forma inadvertida mientras se espera a que el recolector de elementos no utilizados controle las instancias de pginas.

Enlazar datos SQL a DataGrid


En el siguiente ejemplo se muestra una consulta de seleccin simple enlazada a un control DataGrid. DataGrid procesa una tabla que contiene los datos de SQL.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>

<html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(ds, "Authors") MyDataGrid.DataSource=ds.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Seleccin simple del control DataGrid</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </body> </html>

Al igual que el control DropDownList que se muestra en la seccin Enlace de datos, el control DataGrid admite una propiedad DataSource que toma IEnumerable o ICollection, as como DataSet. Se puede utilizar DataSet asignando la propiedad DefaultView de una tabla incluida en DataSet al nombre de la tabla que se desea utilizar dentro de DataSet. La propiedad DefaultView representa el estado actual de una tabla dentro de DataSet, incluido cualquier cambio que haya realizado el cdigo de la aplicacin (como eliminar filas o cambiar valores). Despus de establecer la propiedad DataSource, se llama a DataBind() para llenar el control.

MyDataGrid.DataSource=ds.Tables("Authors").DefaultView MyDataGrid.DataBind()

Se recurre a una sintaxis alternativa para especificar tanto DataSource como DataMember. En este caso, ASP.NET obtiene automticamente DefaultView.

MyDataGrid.DataSource=ds MyDataGrid.DataMember="Authors" MyDataGrid.DataBind()

Tambin se puede enlazar directamente con SqlDataReader. En este caso slo se muestran datos, por lo que la naturaleza slo hacia delante de SqlDataReader se adapta perfectamente a este escenario y el usuario se beneficia del aumento de rendimiento que proporciona SqlDataReader.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim MyConnection As SqlConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim MyCommand As SqlCommand = New SqlCommand("select * from Authors", MyConnection) MyConnection.Open() Dim dr As SqlDataReader = MyCommand.ExecuteReader() MyDataGrid.DataSource = dr MyDataGrid.DataBind() MyConnection.Close() End Sub </script> <body> <h3><font face="Verdana">Seleccin simple del control DataGrid</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </body> </html>

Nota: en el resto de esta seccin, slo se muestra el modelo DataSet de acceso a datos; no obstante, cualquiera de estos ejemplos puede volver a escribirse para beneficiarse tambin de SQLDataReader.

Realizar una seleccin parametrizada


Tambin se puede realizar una seleccin parametrizada mediante el objeto SqlDataAdapter. En el siguiente ejemplo se muestra cmo se pueden modificar los datos seleccionados mediante el valor expuesto desde un control HtmlControl seleccionado.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>

<html> <script language="VB" runat="server"> Sub GetAuthors_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter Dim SelectCommand As String = "select * from Authors where state = @State" MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter(SelectCommand, MyConnection) MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NVarChar, 2)) MyCommand.SelectCommand.Parameters("@State").Value = MySelect.Value DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Seleccin con parmetros de un control DataGrid</font></h3> Seleccionar un estado: <select id="MySelect" runat="server"> <option>CA</option> <option>IN</option> <option>KS</option> <option>MD</option> <option>MI</option> <option>OR</option> <option>TN</option> <option>UT</option> </select> <input type="submit" OnServerClick="GetAuthors_Click" Value="Obtener autores" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </form>

</body> </html>

SqlDataAdapter mantiene una coleccin Parameters que puede utilizarse para reemplazar identificadores variables (indicado por un smbolo "@" delante del nombre) con valores. Se agrega un nuevo objeto SqlParameter a la coleccin que especifica el nombre, el tipo y el tamao del parmetro y, a continuacin, se establece la propiedad Value en el valor de la seleccin.

myCommand.SelectCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NVarChar, 2)) myCommand.SelectCommand.Parameters("@State").Value = MySelect.Value

Importante: obsrvese que la propiedad EnableViewState de DataGrid se ha establecido en false. Si se rellenan los datos en cada solicitud, no supone ningn beneficio hacer que DataGrid almacene informacin de estado para que se enve en un viaje de ida y vuelta con devoluciones de formularios. Dado que DataGrid almacena todos los datos cuando se mantiene el estado, es importante desactivarlo en aquellos momentos en los que sea adecuado para mejorar el rendimiento de las pginas. En DataGrid2.aspx, los valores del cuadro de seleccin se llenan estticamente, pero esto no funcionar bien si dichos valores cambian en la base de datos. Dado que el HtmlControl seleccionado tambin admite una propiedad IEnumerable DataSource, se puede utilizar una consulta de seleccin para llenar dinmicamente el cuadro de seleccin, lo que garantiza que la base de datos y la interfaz de usuario estn siempre sincronizadas. En el siguiente ejemplo se muestra este proceso.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = New SqlDataAdapter("select distinct State from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "States") MySelect.DataSource= DS.Tables("States").DefaultView MySelect.DataBind() End If End Sub Sub GetAuthors_Click(Sender As Object, E As EventArgs) Dim SelectCmd As String = "select * from Authors where state = @State" Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = New SqlDataAdapter(SelectCmd, MyConnection) MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NVarChar, 2)) MyCommand.SelectCommand.Parameters("@State").Value = MySelect.Value

DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource= DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Seleccin dinmica con parmetros de un control DataGrid</font></h3> Seleccionar un estado: <select id="MySelect" DataTextField="State" runat="server"/> <input type="submit" OnServerClick="GetAuthors_Click" Value="Obtener autores" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </form> </body> </html>

Insertar datos en una base de datos de SQL


Para insertar una fila en una base de datos, se puede agregar a la pgina un formulario de entrada sencillo y ejecutar un comando de insercin en el controlador de eventos de envo de formularios. Al igual que en los dos ejemplos anteriores, se utiliza la coleccin Parameters del objeto de comando para llenar los valores del comando. Hay que tener en cuenta que tambin hay que realizar una comprobacin para asegurarse de que los valores requeridos no son nulos antes de intentar insertarlos en la base de datos. Esto evita una infraccin accidental de las restricciones de campo de la base de datos. El comando de insercin tambin se ejecuta dentro de un bloque try/catch, por si se da el caso de que ya exista la clave primaria de la fila insertada.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes")

If Not (IsPostBack) BindGrid() End If End Sub Sub AddAuthor_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyCommand As SqlCommand If au_id.Value = "" Or au_fname.Value = "" Or au_lname.Value = "" Or phone.Value = "" Message.InnerHtml = "ERROR: los campos id. de autor, nombre o telfono no admiten valores nulos" Message.Style("color") = "red" BindGrid() End If Dim InsertCmd As String = "insert into Authors (au_id, au_lname, au_fname, phone, address, city, state, zip, contract) values (@Id, @LName, @FName, @Phone, @Address, @City, @State, @Zip, @Contract)" MyCommand = New SqlCommand(InsertCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters("@Id").Value = au_id.Value MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters("@LName").Value = au_lname.Value MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters("@FName").Value = au_fname.Value MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters("@Phone").Value = phone.Value MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters("@Address").Value = address.Value MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters("@City").Value = city.Value MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters("@State").Value = stateabbr.Value MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters("@Zip").Value = zip.Value MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Contract").Value = contract.Value MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro agregado</b><br>" & InsertCmd.ToString() Catch Exp As SQLException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo agregar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red"

End Try MyCommand.Connection.Close() BindGrid() End Sub Sub BindGrid() Dim MyCommand As SqlDataAdapter = new SqlDataAdapter("select * from Authors", MyConnection) Dim DS As DataSet = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Insertar una fila de datos</font></h3> <table width="95%"> <tr> <td valign="top"> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </td> <td valign="top"> <table style="font: 8pt verdana"> <tr> <td colspan="2" bgcolor="#aaaadd" style="font:10pt verdana">Agregar un nuevo autor:</td> </tr> <tr> <td nowrap>Id. del autor: </td> <td><input type="text" id="au_id" value="000-00-0000" runat="server"></td> </tr> <tr> <td nowrap>Apellido: </td> <td><input type="text" id="au_lname" value="Doe" runat="server"></td> </tr> <tr nowrap> <td>Nombre: </td> <td><input type="text" id="au_fname" value="John" runat="server"></td> </tr>

<tr> <td>Telfono: </td> <td><input type="text" id="phone" value="808 555-5555" runat="server"></td> </tr> <tr> <td>Direccin: </td> <td><input type="text" id="address" value="One Microsoft Way" runat="server"></td> </tr> <tr> <td>Ciudad: </td> <td><input type="text" id="city" value="Redmond" runat="server"></td> </tr> <tr> <td>Estado: </td> <td> <select id="stateabbr" runat="server"> <option>CA</option> <option>IN</option> <option>KS</option> <option>MD</option> <option>MI</option> <option>OR</option> <option>TN</option> <option>UT</option> </select> </td> </tr> <tr> <td nowrap>Cdigo postal: </td> <td><input type="text" id="zip" value="98005" runat="server"></td> </tr> <tr> <td>Contrato: </td> <td> <select id="contract" runat="server"> <option value="0">False</option> <option value="1">True</option> </select> </td> </tr> <tr> <td></td> <td style="padding-top:15"> <input type="submit" OnServerClick="AddAuthor_Click" value="Agregar autor" runat="server"> </td> </tr> <tr> <td colspan="2" style="padding-top:15" align="center"> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/> </td> </tr> </table> </td> </tr> </table> </form> </body> </html>

En vez de comprobar explcitamente los valores de entrada, se podra haber utilizado perfectamente los controles de validacin proporcionados con ASP.NET. En el siguiente ejemplo se muestra cmo hacerlo. Obsrvese que mediante RegEx Validator se proporciona el beneficio adicional de comprobar el formato de los campos del identificador de autor, del cdigo postal y del nmero de telfono.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If End Sub Sub AddAuthor_Click(Sender As Object, E As EventArgs) Message.InnerHtml = "" If (Page.IsValid) Dim DS As DataSet Dim MyCommand As SqlCommand Dim InsertCmd As String = "insert into Authors (au_id, au_lname, au_fname, phone, address, city, state, zip, contract) values (@Id, @LName, @FName, @Phone, @Address, @City, @State, @Zip, @Contract)" MyCommand = New SqlCommand(InsertCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters("@Id").Value = au_id.Value MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters("@LName").Value = au_lname.Value MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters("@FName").Value = au_fname.Value MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters("@Phone").Value = phone.Value MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters("@Address").Value = address.Value MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters("@City").Value = city.Value MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters("@State").Value = stateabbr.Value MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters("@Zip").Value = zip.Value MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Contract").Value = contract.Value

MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro agregado</b><br>" & InsertCmd.ToString() Catch Exp As SQLException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo agregar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red" End Try MyCommand.Connection.Close() End If BindGrid() End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = new SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Insertar una fila de datos con validacin</font></h3> <table width="95%"> <tr> <td valign="top"> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </td> <td valign="top">

<table style="font: 8pt verdana"> <tr> <td colspan="2" bgcolor="#aaaadd" style="font:10pt verdana">Agregar un nuevo autor:</td> </tr> <tr> <td nowrap>Id. del autor: </td> <td> <input type="text" id="au_id" value="000-00-0000" runat="server"> <asp:RequiredFieldValidator id="au_idReqVal" ControlToValidate="au_id" Display="Static" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </td> </tr> <tr> <td nowrap>Apellido: </td> <td> <input type="text" id="au_lname" value="Doe" runat="server"> <asp:RequiredFieldValidator id="au_lnameReqVal" ControlToValidate="au_lname" Display="Static" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </td> </tr> <tr> <td nowrap>Nombre: </td> <td> <input type="text" id="au_fname" value="John" runat="server"> <asp:RequiredFieldValidator id="au_fnameReqVal" ControlToValidate="au_fname" Display="Static" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </td> </tr> <tr> <td>Telfono: </td> <td><nobr> <input type="text" id="phone" value="808 555-5555" runat="server"> <asp:RequiredFieldValidator id="phoneReqVal" ControlToValidate="phone" Display="Static" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </td> </tr> <tr> <td>Direccin: </td> <td><input type="text" id="address" value="One Microsoft Way" runat="server"></td> </tr> <tr> <td>Ciudad: </td>

<td><input type="text" id="city" value="Redmond" runat="server"></td> </tr> <tr> <td>Estado: </td> <td> <select id="stateabbr" runat="server"> <option>CA</option> <option>IN</option> <option>KS</option> <option>MD</option> <option>MI</option> <option>OR</option> <option>TN</option> <option>UT</option> </select> </td> </tr> <tr> <td nowrap>Cdigo postal: </td> <td><input type="text" id="zip" value="98005" runat="server"></td> </tr> <tr> <td>Contrato: </td> <td> <select id="contract" runat="server"> <option value="0">False</option> <option value="1">True</option> </select> </td> </tr> <tr> <td></td> <td style="padding-top:15"> <input type="submit" OnServerClick="AddAuthor_Click" value="Agregar autor" runat="server"> </td> </tr> <tr> <td colspan="2" style="padding-top:15" align="center"> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/> <asp:RegularExpressionValidator id="RegularExpressionValidator1" ASPClass="RegularExpressionValidator" ControlToValidate="zip" ValidationExpression="[0-9]{5}" Display="Dynamic" Font-Name="Arial" Font-Size="11" runat=server> * El cdigo postal debe tener 5 dgitos numricos <br> </asp:RegularExpressionValidator> <asp:RegularExpressionValidator id="phoneRegexVal" ControlToValidate="phone" ValidationExpression="[0-9]{3} [0-9]{3}-[0-9]{4}" Display="Dynamic" Font-Name="Arial" Font-Size="11" runat=server> * El telfono debe tener el siguiente formato: XXX XXX-XXXX <br> </asp:RegularExpressionValidator> <asp:RegularExpressionValidator id="au_idRegexVal" ControlToValidate="au_id" ValidationExpression="[0-9]{3}-[0-9]{2}-[0-9]{4}" Display="Dynamic" Font-Name="Arial" Font-Size="11" runat=server> * El campo Id. del autor debe estar compuesto por dgitos: XXX-XX-XXXX <br> </asp:RegularExpressionValidator>

</td> </tr> </table> </td> </tr> </table> </form> </body> </html>

Actualizar datos en una base de datos de SQL


Actualizar una base de datos puede resultar a menudo complicado en aplicaciones Web. El control DataGrid proporciona soporte integrado para este escenario que simplifica las actualizaciones. Para permitir que se editen filas, DataGrid admite una propiedad EditItemIndex de tipo entero que indica qu fila de la cuadrcula se podr editar. Cuando se establece esta propiedad, DataGrid procesa la fila en el ndice como cuadros de entrada de texto en vez de simples etiquetas. Un valor de -1 (el predeterminado) indica que no se puede editar ninguna fila. La pgina puede incluir el control DataGrid en un formulario del servidor y obtener acceso a los datos editados a travs del modelo de objeto de DataGrid. Para saber qu fila se puede editar, se necesita una forma de aceptar alguna entrada del usuario relacionada con la fila que se deseara editar. DataGrid puede incluir una EditCommandColumn que procesa vnculos para desencadenar tres eventos especiales: EditCommand, UpdateCommand, y CancelCommand. EditCommandColumn se agrega de forma declarativa a la coleccin Columns de DataGrid, tal y como se muestra en el siguiente ejemplo.

<ASP:DataGrid id="MyDataGrid" runat="server" ... OnEditCommand="MyDataGrid_Edit" OnCancelCommand="MyDataGrid_Cancel" OnUpdateCommand="MyDataGrid_Update" DataKeyField="au_id" > <Columns> <asp:EditCommandColumn EditText="Edit" CancelText="Cancel" UpdateText="Update" /> </Columns> </ASP:DataGrid>
En la misma etiqueta DataGrid, se conectan controladores de eventos con cada uno de los comandos desencadenados desde EditCommandColumn. El argumento DataGridCommandEventArgs de estos controladores proporciona acceso directo al ndice seleccionado por el cliente que se utiliza para establecer el EditItemIndex de DataGrid. Hay que tener en cuenta que se necesita volver a enlazar el control DataGrid para que se produzca el cambio, tal y como se muestra en el siguiente ejemplo.

Public Sub MyDataGrid_Edit(sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = E.Item.ItemIndex BindGrid() End Sub

Cuando se est editando una fila de DataGrid, EditCommandColumn procesa los vnculos Update y Cancel. Si el cliente selecciona Cancel, EditItemIndex simplemente se vuelve a establecer en -1. No obstante, si el cliente selecciona Update, es necesario ejecutar el comando de actualizacin en la base de datos. Para realizar una consulta de actualizacin se necesita conocer la clave principal de la base de datos para la fila que se desea actualizar. Para admitirlo, DataGrid expone una propiedad DataKeyField que puede establecerse en el nombre del campo de la clave principal. En el controlador de eventos conectado a UpdateCommand, se puede recuperar el nombre de la clave desde la coleccin DataKeys de DataGrid. Para indizar en esta coleccin, se utiliza el ItemIndex del evento, tal y como se muestra en el siguiente ejemplo.

myCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CType(E.Item.ItemIndex, Integer))

Al final del controlador de eventos de actualizacin, EditItemIndex se vuelve a establecer en -1. En el siguiente ejemplo se muestra cmo acta este cdigo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If End Sub Sub MyDataGrid_Edit(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = CInt(E.Item.ItemIndex) BindGrid() End Sub Sub MyDataGrid_Cancel(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = -1 BindGrid() End Sub Sub MyDataGrid_Update(Sender As Object, E As DataGridCommandEventArgs) Dim DS As DataSet Dim MyCommand As SqlCommand Dim UpdateCmd As String = "UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = " _ & " @Phone, address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id" MyCommand = New SqlCommand(UpdateCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CInt(E.Item.ItemIndex)) Dim Cols As String() = {"@Id","@LName","@FName","@Phone","@Address","@City","@State","@Zip","@Contract"} Dim NumCols As Integer = E.Item.Cells.Count Dim I As Integer For I=2 To NumCols-2 'skip first, second and last column

Dim CurrentTextBox As TextBox CurrentTextBox = E.Item.Cells(I).Controls(0) Dim ColValue As String = CurrentTextBox.Text ' Check for null values in required fields If I<6 And ColValue = "" Message.InnerHtml = "ERROR: los campos id. de autor, nombre o telfono no admiten valores nulos" Message.Style("color") = "red" Return End If MyCommand.Parameters(Cols(I-1)).Value = ColValue Next ' Append last row, converting true/false values to 0/1 Dim ContractTextBox As TextBox ContractTextBox = E.Item.Cells(NumCols-1).Controls(0) If ContractTextBox.Text = "true" MyCommand.Parameters("@Contract").Value = "1" Else MyCommand.Parameters("@Contract").Value = "0" End If MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro actualizado</b><br>" & UpdateCmd.ToString() MyDataGrid.EditItemIndex = -1 Catch Exp As SQLException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo actualizar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red" End Try MyCommand.Connection.Close() BindGrid() End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = new SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana">

<form runat="server"> <h3><font face="Verdana">Actualizar fila de datos</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="800" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" OnEditCommand="MyDataGrid_Edit" OnCancelCommand="MyDataGrid_Cancel" OnUpdateCommand="MyDataGrid_Update" DataKeyField="au_id" > <Columns> <asp:EditCommandColumn EditText="Editar" CancelText="Cancelar" UpdateText="Actualizar" ItemStyle-Wrap="false"/> </Columns> </ASP:DataGrid> </form> </body> </html>

Existe un problema con el ejemplo anterior que consiste en que el campo clave principal (au_id) tambin se procesa como un cuadro de entrada de texto cuando se puede editar una fila. No se desea que el cliente cambie este valor, ya que se necesita que determine qu fila va a actualizar en la base de datos. Afortunadamente, se puede deshabilitar esta columna para que no se procese como cuadro de texto especificando exactamente la apariencia de cada columna en la fila que se puede editar. Esto se hace definiendo cada fila en la coleccin Columns de DataGrid mediante el control BoundColumn para asignar campos de datos a cada columna. Mediante esta tcnica se dispone de control total sobre el orden de las columnas, as como de las propiedades ReadOnly. Para la columna au_id, se establece la propiedad ReadOnly en true. Cuando una fila se encuentra en modo de edicin, se seguir procesando la columna como etiqueta. En el siguiente ejemplo se muestra esta tcnica.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If End Sub

Sub MyDataGrid_Edit(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = CInt(E.Item.ItemIndex) BindGrid() End Sub Sub MyDataGrid_Cancel(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = -1 BindGrid() End Sub Sub MyDataGrid_Update(Sender As Object, E As DataGridCommandEventArgs) Dim DS As DataSet Dim MyCommand As SqlCommand Dim UpdateCmd As String = "UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = " _ & " @Phone, address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id" MyCommand = New SqlCommand(UpdateCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CInt(E.Item.ItemIndex)) Dim Cols As String() = {"@Id","@LName","@FName","@Phone","@Address","@City","@State","@Zip","@Contract"} Dim NumCols As Integer = E.Item.Cells.Count Dim I As Integer For I=2 To NumCols-2 'skip first, second and last column Dim CurrentTextBox As TextBox CurrentTextBox = E.Item.Cells(I).Controls(0) Dim ColValue As String = CurrentTextBox.Text ' Check for null values in required fields If I<6 And ColValue = "" Message.InnerHtml = "ERROR: los campos id. de autor, nombre o telfono no admiten valores nulos" Message.Style("color") = "red" Return End If MyCommand.Parameters(Cols(I-1)).Value = ColValue Next ' Append last row, converting true/false values to 0/1 Dim ContractTextBox As TextBox ContractTextBox = E.Item.Cells(NumCols-1).Controls(0)

If ContractTextBox.Text = "true" MyCommand.Parameters("@Contract").Value = "1" Else MyCommand.Parameters("@Contract").Value = "0" End If MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro actualizado</b><br>" & UpdateCmd.ToString() MyDataGrid.EditItemIndex = -1 Catch Exp As SQLException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo actualizar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red" End Try MyCommand.Connection.Close() BindGrid() End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = new SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Actualizar fila de datos con una columna de slo lectura</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="800" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" OnEditCommand="MyDataGrid_Edit" OnCancelCommand="MyDataGrid_Cancel" OnUpdateCommand="MyDataGrid_Update"

DataKeyField="au_id" AutoGenerateColumns="false" > <Columns> <asp:EditCommandColumn EditText="Editar" CancelText="Cancelar" UpdateText="Actualizar" ItemStyle-Wrap="false"/> <asp:BoundColumn HeaderText="au_id" SortExpression="au_id" ReadOnly="True" DataField="au_id" ItemStyle-Wrap="false"/> <asp:BoundColumn HeaderText="au_lname" SortExpression="au_lname" DataField="au_lname"/> <asp:BoundColumn HeaderText="au_fname" SortExpression="au_fname" DataField="au_fname"/> <asp:BoundColumn HeaderText="phone" SortExpression="phone" DataField="phone"/> <asp:BoundColumn HeaderText="address" SortExpression="address" DataField="address"/> <asp:BoundColumn HeaderText="city" SortExpression="city" DataField="city"/> <asp:BoundColumn HeaderText="state" SortExpression="state" DataField="state"/> <asp:BoundColumn HeaderText="zip" SortExpression="zip" DataField="zip"/> <asp:BoundColumn HeaderText="contract" SortExpression="contract" DataField="contract"/> </Columns> </ASP:DataGrid> </form> </body> </html>

Los controles BoundColumn no son los nicos que se pueden establecer en la coleccin Columns de DataGrid. Tambin se puede especificar TemplateColumn, que proporciona un control total sobre el contenido de la columna. La plantilla slo tiene contenido arbitrario; se puede procesar cualquier cosa que se desee, incluyendo controles de servidor, dentro de las columnas de DataGrid. En el siguiente ejemplo se muestra cmo utilizar el control TemplateColumn para procesar la columna "State" como una lista desplegable y la columna "Contract" como una casilla de verificacin HtmlControl. La sintaxis de enlace de datos de ASP.NET se utiliza para extraer el valor del campo de datos de la plantilla. Debe observarse que hay algo de lgica complicada para hacer que la lista desplegable y la casilla de verificacin reflejen el estado de los datos dentro de la fila.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Public StateIndex As Hashtable Sub Page_Load(Src As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If StateIndex = New Hashtable() StateIndex("CA") = 0 StateIndex("IN") = 1 StateIndex("KS") = 2 StateIndex("MD") = 3 StateIndex("MI") = 4 StateIndex("OR") = 5 StateIndex("TN") = 6

StateIndex("UT") = 7 End Sub Public Function GetStateIndex(StateName As String) As Integer If StateIndex(stateName) <> Nothing Return CInt(StateIndex(stateName)) Else Return 0 End If End Function Sub MyDataGrid_Edit(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = CInt(E.Item.ItemIndex) BindGrid() End Sub Sub MyDataGrid_Cancel(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = -1 BindGrid() End Sub Sub MyDataGrid_Update(Sender As Object, E As DataGridCommandEventArgs) Dim DS As DataSet Dim MyCommand As SqlCommand Dim UpdateCmd As String = "UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = " _ & " @Phone, address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id" MyCommand = New SqlCommand(UpdateCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CInt(E.Item.ItemIndex)) Dim Cols As String() = {"LName","FName","Phone","Address","City","Zip"} Dim I As Integer For I = 0 To 5 Dim CurrentTextBox As TextBox CurrentTextBox = E.Item.FindControl("edit_" & Cols(I)) Dim ColValue As String = CurrentTextBox.Text ' Check for null values in required fields If I<3 And ColValue = "" Message.InnerHtml = "ERROR: los campos Nombre o Telfono no admiten valores nulos" Message.Style("color") = "red" Return

End If MyCommand.Parameters("@" & Cols(I)).Value = ColValue Next Dim StateDropDownList As DropDownList StateDropDownList = E.Item.FindControl("edit_State") MyCommand.Parameters("@State").Value = StateDropDownList.SelectedItem.ToString() Dim ContractCheckBox As CheckBox ContractCheckBox = E.Item.FindControl("edit_Contract") If ContractCheckBox.Checked = true MyCommand.Parameters("@Contract").Value = "1" Else MyCommand.Parameters("@Contract").Value = "0" End If MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro actualizado</b><br>" & UpdateCmd MyDataGrid.EditItemIndex = -1 Catch Exp As SqlException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo actualizar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red" End Try MyCommand.Connection.Close() BindGrid() End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = new SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Actualizar fila de datos con una columna con plantillas</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server"

Width="800" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" OnEditCommand="MyDataGrid_Edit" OnCancelCommand="MyDataGrid_Cancel" OnUpdateCommand="MyDataGrid_Update" DataKeyField="au_id" AutoGenerateColumns="false" > <Columns> <asp:EditCommandColumn EditText="Editar" CancelText="Cancelar" UpdateText="Actualizar" ItemStyle-Wrap="false"/> <asp:BoundColumn HeaderText="au_id" SortExpression="au_id" ReadOnly="True" DataField="au_id" ItemStyle-Wrap="false"/> <asp:TemplateColumn HeaderText="au_lname" SortExpression="au_lname"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "au_lname") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_LName" Text='<%# DataBinder.Eval(Container.DataItem, "au_lname") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="au_fname" SortExpression="au_fname"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "au_fname") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_FName" Text='<%# DataBinder.Eval(Container.DataItem, "au_fname") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="phone" SortExpression="phone"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "phone") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_Phone" Text='<%# DataBinder.Eval(Container.DataItem, "phone") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="address" SortExpression="address"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "address") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_Address" Text='<%# DataBinder.Eval(Container.DataItem, "address") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="city" SortExpression="city"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "city") %>'/> </ItemTemplate> <EditItemTemplate>

<asp:TextBox runat="server" id="edit_City" Text='<%# DataBinder.Eval(Container.DataItem, "city") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="state" SortExpression="state"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "state") %>'/> </ItemTemplate> <EditItemTemplate> <asp:DropDownList runat="server" SelectedIndex='<%# GetStateIndex(Container.DataItem("state")) %>' id="edit_State"> <asp:ListItem>CA</asp:ListItem> <asp:ListItem>IN</asp:ListItem> <asp:ListItem>KS</asp:ListItem> <asp:ListItem>MD</asp:ListItem> <asp:ListItem>MI</asp:ListItem> <asp:ListItem>OR</asp:ListItem> <asp:ListItem>TN</asp:ListItem> <asp:ListItem>UT</asp:ListItem> </asp:DropDownList> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="zip" SortExpression="zip"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "zip") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_Zip" Text='<%# DataBinder.Eval(Container.DataItem, "zip") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="contract" SortExpression="contract"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "contract", "{0}") %>'/> </ItemTemplate> <EditItemTemplate> <asp:CheckBox runat="server" id="edit_Contract" Checked='<%# DataBinder.Eval(Container.DataItem, "contract") %>'/> </EditItemTemplate> </asp:TemplateColumn> </Columns> </ASP:DataGrid> </form> </body> </html>

Al igual que se puede colocar una lista desplegable o una casilla de verificacin HtmlControl en TemplateColumn, tambin pueden colocarse otros controles. En el siguiente ejemplo se agregan controles Validator a las columnas para comprobar la entrada del cliente antes de intentar realizar la actualizacin.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <script language="VB" runat="server">

Dim MyConnection As SqlConnection Public StateIndex As Hashtable Sub Page_Load(Src As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If StateIndex = New Hashtable() StateIndex("CA") = 0 StateIndex("IN") = 1 StateIndex("KS") = 2 StateIndex("MD") = 3 StateIndex("MI") = 4 StateIndex("OR") = 5 StateIndex("TN") = 6 StateIndex("UT") = 7 End Sub Sub MyDataGrid_Edit(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = CInt(E.Item.ItemIndex) BindGrid() End Sub Sub MyDataGrid_Cancel(Sender As Object, E As DataGridCommandEventArgs) MyDataGrid.EditItemIndex = -1 BindGrid() End Sub Sub MyDataGrid_Update(Sender As Object, E As DataGridCommandEventArgs) If (Page.IsValid) Dim DS As DataSet Dim MyCommand As SqlCommand Dim UpdateCmd As String = "UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = " _ & " @Phone, address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id" MyCommand = New SqlCommand(UpdateCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters.Add(New SqlParameter("@LName", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@FName", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@Phone", SqlDbType.NChar, 12)) MyCommand.Parameters.Add(New SqlParameter("@Address", SqlDbType.NVarChar, 40)) MyCommand.Parameters.Add(New SqlParameter("@City", SqlDbType.NVarChar, 20)) MyCommand.Parameters.Add(New SqlParameter("@State", SqlDbType.NChar, 2)) MyCommand.Parameters.Add(New SqlParameter("@Zip", SqlDbType.NChar, 5)) MyCommand.Parameters.Add(New SqlParameter("@Contract", SqlDbType.NVarChar,1)) MyCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CInt(E.Item.ItemIndex)) Dim Cols As String() = {"LName","FName","Phone","Address","City","Zip"} Dim I As Integer

For I = 0 To 5 Dim CurrentTextBox As TextBox CurrentTextBox = E.Item.FindControl("edit_" & Cols(I)) Dim ColValue As String = CurrentTextBox.Text MyCommand.Parameters("@" & Cols(I)).Value = ColValue Next Dim StateDropDownList As DropDownList StateDropDownList = E.Item.FindControl("edit_State") MyCommand.Parameters("@State").Value = StateDropDownList.SelectedItem.ToString() Dim ContractCheckBox As CheckBox ContractCheckBox = E.Item.FindControl("edit_Contract") If ContractCheckBox.Checked = true MyCommand.Parameters("@Contract").Value = "1" Else MyCommand.Parameters("@Contract").Value = "0" End If MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro actualizado</b><br>" & UpdateCmd MyDataGrid.EditItemIndex = -1 Catch Exp As SqlException If Exp.Number = 2627 Message.InnerHtml = "ERROR: ya existe un registro con la misma clave principal" Else Message.InnerHtml = "ERROR: no se pudo actualizar el registro, compruebe que los campos estn rellenos correctamente" End If Message.Style("color") = "red" End Try MyCommand.Connection.Close() BindGrid() Else Message.InnerHtml = "ERROR: compruebe las condiciones de error de cada campo." Message.Style("color") = "red" End If End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = new SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource=DS.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> </head> <body style="font: 10pt verdana">

<form runat="server"> <h3><font face="Verdana">Actualizar fila de datos con validacin</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="800" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" OnEditCommand="MyDataGrid_Edit" OnCancelCommand="MyDataGrid_Cancel" OnUpdateCommand="MyDataGrid_Update" DataKeyField="au_id" AutoGenerateColumns="false" > <Columns> <asp:EditCommandColumn EditText="Editar" CancelText="Cancelar" UpdateText="Actualizar" ItemStyle-Wrap="false"/> <asp:BoundColumn HeaderText="au_id" SortExpression="au_id" ReadOnly="True" DataField="au_id" ItemStyle-Wrap="false"/> <asp:TemplateColumn HeaderText="au_lname" SortExpression="au_lname"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "au_lname") %>'/> </ItemTemplate> <EditItemTemplate> <nobr> <asp:TextBox runat="server" id="edit_LName" Text='<%# DataBinder.Eval(Container.DataItem, "au_lname") %>'/> <asp:RequiredFieldValidator id="au_lnameReqVal" ControlToValidate="edit_LName" Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="au_fname" SortExpression="au_fname"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "au_fname") %>'/> </ItemTemplate> <EditItemTemplate> <nobr> <asp:TextBox runat="server" id="edit_FName" Text='<%# DataBinder.Eval(Container.DataItem, "au_fname") %>'/> <asp:RequiredFieldValidator id="au_fnameReqVal" ControlToValidate="edit_FName" Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="phone" SortExpression="phone">

<ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "phone") %>'/> </ItemTemplate> <EditItemTemplate> <nobr> <asp:TextBox runat="server" id="edit_Phone" Text='<%# DataBinder.Eval(Container.DataItem, "phone") %>'/> <asp:RequiredFieldValidator id="phoneReqVal" ControlToValidate="edit_Phone" Display="Dynamic" Font-Name="Verdana" Font-Size="12" runat=server> &nbsp;* </asp:RequiredFieldValidator> <asp:RegularExpressionValidator id="phoneRegexVal" ControlToValidate="edit_Phone" ValidationExpression="[0-9]{3} [0-9]{3}-[0-9]{4}" Display="Dynamic" Font-Name="Arial" Font-Size="11" runat=server> * El telfono debe tener el siguiente formato: XXX XXX-XXXX <br> </asp:RegularExpressionValidator> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="address" SortExpression="address"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "address") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_Address" Text='<%# DataBinder.Eval(Container.DataItem, "address") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="city" SortExpression="city"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "city") %>'/> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_City" Text='<%# DataBinder.Eval(Container.DataItem, "city") %>'/> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="state" SortExpression="state"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "state") %>'/> </ItemTemplate> <EditItemTemplate> <asp:DropDownList runat="server" SelectedIndex='<%# StateIndex(Container.DataItem("state")) %>' id="edit_State"> <asp:ListItem>CA</asp:ListItem> <asp:ListItem>IN</asp:ListItem> <asp:ListItem>KS</asp:ListItem> <asp:ListItem>MD</asp:ListItem> <asp:ListItem>MI</asp:ListItem> <asp:ListItem>OR</asp:ListItem> <asp:ListItem>TN</asp:ListItem> <asp:ListItem>UT</asp:ListItem> </asp:DropDownList> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="zip" SortExpression="zip"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "zip") %>'/>

</ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="edit_Zip" Text='<%# DataBinder.Eval(Container.DataItem, "zip") %>'/> <asp:RegularExpressionValidator id="RegularExpressionValidator1" ASPClass="RegularExpressionValidator" ControlToValidate="edit_Zip" ValidationExpression="[0-9]{5}" Display="Dynamic" Font-Name="Arial" Font-Size="11" runat=server> * El cdigo postal debe tener 5 dgitos numricos <br> </asp:RegularExpressionValidator> </EditItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="contract" SortExpression="contract"> <ItemTemplate> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "contract", "{0}") %>'/> </ItemTemplate> <EditItemTemplate> <asp:CheckBox runat="server" id="edit_Contract" Checked='<%# DataBinder.Eval(Container.DataItem, "contract") %>'/> </EditItemTemplate> </asp:TemplateColumn> </Columns> </ASP:DataGrid> </form> </body> </html>

Eliminar datos en una base de datos de SQL


Realizar eliminaciones en una base de datos es muy similar a una actualizacin o a un comando de insercin, pero se necesita una forma de determinar la fila concreta de la cuadrcula que se va a eliminar. Otro control que puede agregarse a la coleccin Columns de DataGrid es el control ButtonColumn, que simplemente procesa un control de botn. ButtonColumn admite una propiedad CommandName que puede establecerse en Delete. En DataGrid, se conecta un controlador de eventos a DeleteCommand, donde se realiza la operacin de eliminacin. De nuevo, se utiliza la coleccin DataKeys para determinar la fila seleccionada por el cliente. En el siguiente ejemplo se muestra este proceso.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid() End If End Sub Sub MyDataGrid_Delete(Sender As Object, E As DataGridCommandEventArgs)

Dim MyCommand As SqlCommand Dim DeleteCmd As String = "DELETE from Employee where emp_id = @Id" MyCommand = New SqlCommand(DeleteCmd, MyConnection) MyCommand.Parameters.Add(New SqlParameter("@Id", SqlDbType.NVarChar, 11)) MyCommand.Parameters("@Id").Value = MyDataGrid.DataKeys(CInt(E.Item.ItemIndex)) MyCommand.Connection.Open() Try MyCommand.ExecuteNonQuery() Message.InnerHtml = "<b>Registro eliminado</b><br>" & DeleteCmd Catch Exc As SQLException Message.InnerHtml = "ERROR: no se pudo eliminar el registro" Message.Style("color") = "red" End Try MyCommand.Connection.Close() BindGrid() End Sub Sub BindGrid() Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = New SqlDataAdapter("select * from Employee", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Employee") MyDataGrid.DataSource=DS.Tables("Employee").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Eliminar la fila de datos</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="800" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" DataKeyField="emp_id" OnDeleteCommand="MyDataGrid_Delete" > <Columns> <asp:ButtonColumn Text="Delete Employee" CommandName="Delete"/> </Columns>

</ASP:DataGrid> </form> </body> </html>

Ordenar datos de una base de datos de SQL


Un requisito comn de cualquier cuadrcula radica en la capacidad de ordenar los datos que contiene. Mientras que el control DataGrid no ordena explcitamente los datos, proporciona una forma de llamar a un controlador de eventos cuando el usuario hace clic en un encabezado de columna, que se puede utilizar para ordenar los datos. Cuando la propiedad AllowSorting de DataGrid se establece en true, procesa hipervnculos para los encabezados de columna que desencadenan un comando Sort de nuevo en la cuadrcula. La propiedad OnSortCommand de DataGrid se establece en el controlador al que se desea llamar cuando el usuario hace clic en un vnculo de columna. El nombre de la columna se pasa como una propiedad SortExpression en el argumento DataGridSortCommandEventArgs, que se puede utilizar para establecer la propiedad Sort del enlace DataView en la cuadrcula. En el siguiente ejemplo se muestra este proceso.

<script> Protected Sub MyDataGrid_Sort(Src As Object, E As DataGridSortCommandEventArgs) ... DataView Source = ds.Tables("Authors").DefaultView Source.Sort = E.SortExpression MyDataGrid.DataBind() End Sub </script> <form runat="server"> <ASP:DataGrid id="MyDataGrid" OnSortCommand="MyDataGrid_Sort" AllowSorting="true" runat="server" /> </form>

En el siguiente ejemplo se muestra cmo acta este cdigo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid("au_id") End If End Sub Sub MyDataGrid_Sort(Sender As Object, E As DataGridSortCommandEventArgs) BindGrid(E.SortExpression) End Sub Sub BindGrid(SortField As String) Dim DS As DataSet

Dim MyCommand As SqlDataAdapter MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") Dim Source As DataView = DS.Tables("Authors").DefaultView Source.Sort = SortField MyDataGrid.DataSource = Source MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Ordenar datos en un control DataGrid</font></h3> <form runat="server"> <ASP:DataGrid id="MyDataGrid" runat="server" OnSortCommand="MyDataGrid_Sort" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" AllowSorting="true" /> </form> </body> </html>

Al utilizar controles BoundColumn, se puede establecer explcitamente la propiedad SortExpression para cada columna, tal y como se muestra en el siguiente ejemplo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (IsPostBack) BindGrid("au_id") End If End Sub

Sub MyDataGrid_Sort(Src As Object, E As DataGridSortCommandEventArgs) BindGrid(E.SortExpression) End Sub Sub BindGrid(SortField As String) Dim DS As DataSet Dim MyCommand As SqlDataAdapter MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(DS, "Authors") Dim Source As DataView = DS.Tables("Authors").DefaultView Source.Sort = SortField MyDataGrid.DataSource = Source MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Ordenar datos en el control DataGrid con columnas enlazadas</font></h3> <form runat="server"> <ASP:DataGrid id="MyDataGrid" runat="server" OnSortCommand="MyDataGrid_Sort" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" AllowSorting="true" AutoGenerateColumns="false" > <Columns> <asp:BoundColumn HeaderText="au_id" SortExpression="au_id" DataField="au_id" ItemStyleWrap="false"/> <asp:BoundColumn HeaderText="au_lname" SortExpression="au_lname" DataField="au_lname"/> <asp:BoundColumn HeaderText="au_fname" SortExpression="au_fname" DataField="au_fname"/> <asp:BoundColumn HeaderText="telfono" SortExpression="phone" DataField="phone"/> <asp:BoundColumn HeaderText="direccin" SortExpression="address" DataField="address"/> <asp:BoundColumn HeaderText="ciudad" SortExpression="city" DataField="city"/> <asp:BoundColumn HeaderText="estado" SortExpression="state" DataField="state"/> <asp:BoundColumn HeaderText="cdigo postal" SortExpression="zip" DataField="zip"/> <asp:BoundColumn HeaderText="contrato" SortExpression="contract" DataField="contract"/> </Columns> </ASP:DataGrid> </form> </body> </html>

Trabajar con relaciones de detalles maestros


A menudo el modelo de datos contiene relaciones que no se pueden representar slo mediante una cuadrcula sencilla. Una interfaz Web muy comn es aquella en la que una fila de datos, que se puede seleccionar, desplaza al cliente hacia una pgina "details" que muestra informacin detallada acerca de la fila seleccionada. Para conseguirlo mediante DataGrid, se puede agregar una columna HyperLinkColumn a la coleccin Columns, que especifica la pgina de detalles a la que se desplazar el cliente al hacer clic en el vnculo. La sintaxis de cadena de formato se utiliza para sustituir un valor del campo en este vnculo que se pasa como un argumento querystring. En el siguiente ejemplo se muestra este proceso.

<ASP:DataGrid id="MyDataGrid" runat="server"> <Columns> <asp:HyperLinkColumn DataNavigateUrlField="au_id" DataNavigateUrlFormatString="datagrid13_details.aspx?id={0}" Text="Get Details" /> </Columns> </ASP:DataGrid>
En la pgina de detalles, se recupera el argumento querystring y se realiza una seleccin combinada para obtener detalles a partir de la base de datos. En el siguiente ejemplo se muestra este escenario.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) DS = new DataSet() MyCommand.Fill(ds, "Authors") MyDataGrid.DataSource=ds.Tables("Authors").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Trabajar con relaciones principal-detalle</font></h3> <span id="Message" EnableViewState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="800" BackColor="#ccccff" BorderColor="black"

ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" DataKeyField="au_id" > <Columns> <asp:HyperLinkColumn DataNavigateUrlField="au_id" DataNavigateUrlFormatString="datagrid13_details.aspx?id={0}" Text="Obtener detalles" /> </Columns> </ASP:DataGrid> </form> </body> </html>

Escribir y utilizar procedimientos almacenados


En general, realizar consultas ad hoc se produce a costa del rendimiento. La utilizacin de procedimientos almacenados puede reducir el coste de realizar importantes operaciones en la base de datos de una aplicacin. Resulta fcil crear un procedimiento almacenado e incluso puede hacerse mediante una instruccin de SQL. En el siguiente ejemplo de cdigo se crea un procedimiento almacenado que simplemente devuelve una tabla.

CREATE Procedure GetAuthors AS SELECT * FROM Authors return GO


Tambin se pueden crear procedimientos almacenados que aceptan parmetros. Por ejemplo:

CREATE Procedure LoadPersonalizationSettings (@UserId varchar(50)) AS SELECT * FROM Personalization WHERE UserID=@UserId return GO
El uso de un procedimiento almacenado de una pgina ASP.NET es tan slo una extensin de lo que se ha aprendido hasta ahora acerca del objeto SqlCommand. CommandText slo es el nombre del procedimiento almacenado en vez del texto de consulta ad hoc. Para indicar a SqlCommand que CommandText es un procedimiento almacenado, se establece la propiedad CommandType.

myCommand.SelectCommand.CommandType = CommandType.StoredProcedure

En el siguiente ejemplo se muestra una llamada a un procedimiento almacenado para llenar DataSet.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server">

Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=northwind;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("Ten Most Expensive Products", MyConnection) MyCommand.SelectCommand.CommandType = CommandType.StoredProcedure DS = new DataSet() MyCommand.Fill(DS, "Products") MyDataGrid.DataSource=DS.Tables("Products").DefaultView MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Seleccin de procedimiento almacenado simple de un control DataGrid</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="360" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </body> </html>

Los parmetros en procedimientos almacenados se pasan tal cual a consultas ad hoc, tal y como se muestra en los siguientes ejemplos.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub GetEmployees_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=northwind;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("SalesByCategory", MyConnection) MyCommand.SelectCommand.CommandType = CommandType.StoredProcedure

MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@CategoryName", SqlDbType.NVarChar, 15)) MyCommand.SelectCommand.Parameters("@CategoryName").Value = SelectCategory.Value MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@OrdYear", SqlDbType.NVarChar, 4)) MyCommand.SelectCommand.Parameters("@OrdYear").Value = SelectYear.Value DS = new DataSet() MyCommand.Fill(DS, "Sales") MyDataGrid.DataSource=DS.Tables("Sales").DefaultView MyDataGrid.DataBind() End Sub </script> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">Seleccin de un procedimiento con parmetros almacenado de un control DataGrid</font></h3> Seleccionar una categora: <select id="SelectCategory" runat="server"> <option>Beverages</option> <option>Condiments</option> <option>Confections</option> <option>Dairy Products</option> <option>Grains/Cereals</option> <option>Meat/Poultry</option> <option>Produce</option> <option>Seafood</option> </select> &nbsp; Seleccionar un ao: <select id="SelectYear" runat="server"> <option>1996</option> <option>1997</option> <option>1998</option> </select> &nbsp; <input type="submit" OnServerClick="GetEmployees_Click" Value="Obtener ventas" runat="server"/><p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="650" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" />

</form> </body> </html>

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub GetSales_Click(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=northwind;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("Employee Sales By Country", MyConnection) MyCommand.SelectCommand.CommandType = CommandType.StoredProcedure MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@Beginning_Date", SqlDbType.DateTime)) MyCommand.SelectCommand.Parameters("@Beginning_Date").Value = BeginDate.SelectedDate MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@Ending_Date", SqlDbType.DateTime)) MyCommand.SelectCommand.Parameters("@Ending_Date").Value = EndDate.SelectedDate DS = new DataSet() MyCommand.Fill(DS, "Sales") MyDataGrid.DataSource=DS.Tables("Sales").DefaultView MyDataGrid.DataBind() End Sub </script> <body> <form runat="server"> <h3><font face="Verdana">Seleccin de un procedimiento con parmetros almacenado de un control DataGrid</font></h3> <table width="700"> <tr> <td valign="top" > <b>Fecha de inicio </b> <ASP:Calendar id="BeginDate" BorderWidth="2" BorderColor="lightblue" Font-Size="8pt" TitleStyle-Font-Size="8pt" TitleStyle-BackColor="#cceecc" DayHeaderStyle-BackColor="#ddffdd" DayHeaderStyle-Font-Size="10pt" WeekendDayStyle-BackColor="#ffffcc" SelectedDate="7/1/1996" VisibleDate="7/1/1996"

SelectedDayStyle-BackColor="lightblue" runat="server"/> </td> <td valign="top" > <b>Fecha final</b> <ASP:Calendar id="EndDate" BorderWidth="2" BorderColor="lightblue" Font-Size="8pt" TitleStyle-Font-Size="8pt" TitleStyle-BackColor="#cceecc" DayHeaderStyle-BackColor="#ddffdd" DayHeaderStyle-Font-Size="10pt" WeekendDayStyle-BackColor="#ffffcc" SelectedDate="7/25/1996" VisibleDate="7/25/1996" SelectedDayStyle-BackColor="lightblue" runat="server"/> </td> <td valign="top" style="padding-top:20"> <input type="submit" OnServerClick="GetSales_Click" Value="Obtener ventas por empleado" runat="server"/><p> </td> </tr> <tr> <td colspan="3" style="padding-top:20"> <ASP:DataGrid id="MyDataGrid" runat="server" Width="500" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </td> </tr> </table> </form> </body> </html>

Obtener acceso a datos basados en XML


Al principio de esta seccin, se mencion que DataSet estaba diseado para datos abstractos de tal forma que es independiente del origen de datos real. Esto puede verse cambiando el enfoque de los ejemplos de SQL a XML. DataSet admite un mtodo ReadXml que toma un objeto FileStream como parmetro. El archivo que se lee en este caso debe contener un esquema y los datos que se desean leer. DataSet espera que los datos estn en el formulario tal y como se muestra en el siguiente ejemplo.

<DocumentElement> <TableName> <ColumnName1>column value</ColumnName1> <ColumnName2>column value</ColumnName2> <ColumnName3>column value</ColumnName3> <ColumnName4>column value</ColumnName4> </TableName>

<TableName> <ColumnName1>column value</ColumnName1> <ColumnName2>column value</ColumnName2> <ColumnName3>column value</ColumnName3> <ColumnName4>column value</ColumnName4> </TableName> </DocumentElement>
Cada seccin TableName se corresponde con una sola fila de la tabla. En el siguiente ejemplo se muestra cmo leer esquemas y datos a partir de un archivo XML mediante el mtodo ReadXml de DataSet. Debe observarse que tras la lectura de los datos en DataSet, stos no se pueden distinguir de los datos SQL; DataGrid los enlaza del mismo modo, tal y como se muestra en el siguiente ejemplo.

<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As New DataSet Dim FS As FileStream Dim Reader As StreamReader FS = New FileStream(Server.MapPath("schemadata.xml"),FileMode.Open,FileAccess.Read) Reader = New StreamReader(FS) DS.ReadXml(Reader) FS.Close() Dim Source As DataView Source = new DataView(ds.Tables(0)) MyLiteral.Text = Source.Table.TableName MyDataGrid.DataSource = Source MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Datos XML para la tabla: <asp:Literal id="MyLiteral" runat="server" /></font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="900" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </body> </html>

Tambin es posible leer los datos y el esquema por separado mediante los mtodos ReadXmlData y ReadXmlSchema de DataSet, tal y como se muestra en el siguiente ejemplo.

<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As New DataSet Dim FS As FileStream Dim Schema, Reader As StreamReader FS = New FileStream(Server.MapPath("schema.xml"),FileMode.Open,FileAccess.Read) Schema = new StreamReader(FS) DS.ReadXmlSchema(Schema) FS.Close() FS = New FileStream(Server.MapPath("data.xml"),FileMode.Open,FileAccess.Read) Reader = New StreamReader(FS) DS.ReadXml(Reader) FS.Close() Dim Source As DataView Source = new DataView(ds.Tables(0)) MyLiteral.Text = Source.Table.TableName MyDataGrid.DataSource = Source MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Datos XML para la tabla: <asp:Literal id="MyLiteral" runat="server" /></font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="900" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </body> </html>

Al igual que DataSet admite mtodos de lectura de datos XML, tambin admite la escritura de los datos. En el siguiente ejemplo se implementa una herramienta para seleccionar datos a partir de SQL y para escribir el resultado como datos XML o texto de esquema.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <head> <script language="VB" runat="server"> Public Source As DataView Public DS As DataSet Public GetSchemaChecked, GetDataChecked As Boolean Sub Submit_Click(Sender As Object, E As EventArgs) If (Page.IsPostBack) Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection(ConnectString.Value) MyCommand = New SqlDataAdapter(MyText.Value, MyConnection) DS = New DataSet() MyCommand.Fill(DS, "Tabla") Source = New DataView(DS.Tables(0)) GetSchemaChecked = GetSchema.Checked GetDataChecked = GetData.Checked MyDataGrid.DataSource=Source MyDataGrid.DataBind() End If End Sub </script> </head> <body bgcolor="ffffcc"> <h3><font face="Verdana">Generador SQL a XML</font></h3> <form runat="server"> <table border=0 cellpadding=5 style="font:10pt verdana"> <tr> <td colspan="2"> <b>Cadena de conexin:</b><br> <input id="ConnectString" type="text" value="server=(local)\NetSDK;database=pubs;Trusted_Connection=yes" size="85" runat="server"> </td> </tr> <tr> <td colspan="2"> <b>Consulta:</b><br> <input id="myText" type="text" value="select * from Authors" size="85" runat="server"> </td> </tr> <tr> <td> <input type="radio" id="GetSchema" name="Mode" runat="server"/>Obtener esquema XML<br> <input type="radio" id="GetData" name="Mode" runat="server"/>Obtener datos XML<br>

<input type="radio" id="GetBoth" name="Mode" checked runat="server"/>Obtener ambos </td> <td valign="top"> <input type="submit" runat="server" OnServerClick="Submit_Click"> </td> </tr> <tr> <td colspan="2"> <% If Page.IsPostBack %> <b>Resultado:</b><br> <textarea cols=80 rows=25> <% If GetSchemaChecked DS.WriteXmlSchema(Response.Output) Else If GetDataChecked DS.WriteXml(Response.Output, XmlWriteMode.IgnoreSchema) Else DS.WriteXml(Response.Output, XmlWriteMode.WriteSchema) End If %> </textarea> <% End If %> </td> </tr> <tr> <td colspan="2"> <% If (Page.IsPostBack) %> <b>Datos:</b><br> <% End If %> <ASP:DataGrid id="MyDataGrid" BackColor="#EDBE7B" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#DC6035" EnableViewState="false" runat="server" /> </td> <tr> </table> </form> </body> </html>

Resumen de la seccin
1. Las API de acceso administrado a datos de Common Language Runtime extraen los datos y los presentan de forma coherente sin importar el origen real (SQL Server, OLEDB, XML, entre otros).

2.

Con el fin de proporcionar a la pgina acceso a las clases que se necesitarn para realizar un acceso a datos de SQL, hay que importar los espacios de nombres System.Data y System.Data.SqlClient a la pgina en cuestin.

3. 4. 5. 6. 7. 8. 9.

Llenar un conjunto de datos a partir de una consulta de SQL implica crear un objeto SqlConnection, mediante la asociacin de un objeto SqlDataAdapter con la conexin que contiene la instruccin de consulta, y llenar el conjunto de datos a partir del comando. El control DataGrid admite una propiedad DataSource que toma un tipo IEnumerable (o ICollection). Esto se puede establecer en el resultado de una consulta de SQL asignando la propiedad DefaultView de DataSet que es del tipo DataView. SqlDataAdapter mantiene una coleccin Parameters que puede utilizarse para reemplazar identificadores variables (indicado por un smbolo "@" delante del nombre) con valores. Al ejecutar comandos que no necesitan devolucin de datos, como los de insertar, actualizar y eliminar, se utiliza SqlCommand en vez de SqlDataAdapter. El comando se emite llamando a un mtodo ExecuteNonQuery, que devuelve el nmero de filas afectadas. SqlConnection debe abrirse de forma explcita cuando se utiliza el comando SqlCommand (SqlDataAdapter controla automticamente la apertura de la conexin para el usuario). Siempre hay que acordarse de cerrar SqlConnection en el modelo de datos antes de que se termine de ejecutar la pgina. Si el usuario no cierra la conexin, se puede agotar el lmite de conexin de forma inadvertida mientras se espera a que las instancias de pginas se liberen en el recolector de elementos no utilizados. Para permitir que se editen filas, DataGrid admite una propiedad EditItemIndex de tipo entero que indica qu fila de la cuadrcula se podr editar. Cuando se establece esta propiedad, DataGrid procesa la fila en el ndice como cuadros de entrada de texto en vez de simples etiquetas. DataGrid expone una propiedad DataKeyField que puede establecerse en el nombre del campo de la clave principal. En el controlador de eventos conectado a UpdateCommand, se puede recuperar el nombre de la clave desde la coleccin DataKeys de DataGrid.

10. 11. 12. 13. 14. 15.

Mediante los controles BoundColumn de DataGrid se dispone de control total sobre el orden de las columnas, as como de las propiedades ReadOnly. Mediante los controles TemplateColumn de DataGrid se dispone de control total sobre el contenido de la columna. El control ButtonColumn puede utilizarse simplemente para procesar un control de botn en cada fila de la columna, que puede estar asociado a un evento. Se puede agregar una columna HyperLinkColumn a la coleccin Columns de DataGrid, que admite desplazarse a otra pgina al hacer clic en el vnculo. Cuando la propiedad AllowSorting de DataGrid se establece en true, procesa hipervnculos para los encabezados de columna que desencadenan un comando Sort de nuevo en la cuadrcula. La propiedad OnSortCommand de DataGrid se establece en el controlador al que se desea llamar cuando el usuario hace clic en un vnculo de columna. DataSet admite los mtodos ReadXml, ReadXmlData y ReadXmlSchema que toman a FileStream como parmetro; esto puede utilizarse para llenar un DataSet a partir de un archivo XML. 16. La utilizacin de procedimientos almacenados puede reducir el coste de realizar importantes operaciones en la base de datos de una aplicacin.

Acceso a datos y personalizacin Introduccin a controles con plantilla


Mientras que el control de servidor DataGrid que se mostr en la seccin anterior es apto para muchos escenarios de aplicaciones Web en los que la representacin de datos en forma de cuadrcula resulta adecuada, en numerosas ocasiones se necesita que la presentacin de datos sea ms rica. ASP.NET ofrece dos controles (DataList y Repeater) que proporcionan mayor flexibilidad sobre el procesamiento de datos en forma de lista. Estos controles estn basados en plantillas, por lo que no tienen ningn procesamiento predeterminado propio. La forma de procesar datos viene completamente predeterminada por la implementacin de las plantillas del control que describen cmo presentar los elementos de datos. Al igual que el control DataGrid, DataList y Repeater admiten una propiedad DataSource que puede establecerse en cualquier tipo de ICollection, IEnumerable o IListSource. Los datos de DataSource se enlazan con el control mediante el mtodo DataBind correspondiente. Una vez enlazados los datos, el formato de cada elemento de datos lo describe una plantilla. La propiedad ItemTemplate controla el procesamiento de cada elemento de la coleccin DataSource. Dentro de una plantilla ItemTemplate, se puede definir cualquier cdigo de presentacin arbitrario (HTML o de otra forma). Mediante la sintaxis de enlace de datos de ASP.NET, se pueden insertar valores a partir del enlace de datos con el control DataList o Repeater, tal y como se muestra en el siguiente ejemplo.

<ASP:Repeater id="MyRepeater" runat="server"> <ItemTemplate> Hello <%# DataBinder.Eval(Container.DataItem, "name") %> ! </ItemTemplate> </ASP:Repeater>
Container representa el primer control de la jerarqua inmediata que admite la interfaz de marcador System.Web.UI.INamingContainer. En este caso, Container se resuelve en un objeto de tipo System.Web.UI.WebControls.RepeaterItem con una propiedad DataItem. Como Repeater itera por la coleccin DataSource, DataItem contiene el elemento actual de la coleccin. Por ejemplo, si el origen de datos se

establece en ArrayList de objetos Employee, DataItem es de tipo Employees. Cuando se enlaza con DataView, DataItem es de tipo DataRowView. En el siguiente ejemplo se muestra un control Repeater enlazado con DataView (devuelto desde una consulta de SQL). HeaderTemplate y FooterTemplate tambin se han definido y procesado al principio y al final de la lista respectivamente.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles", MyConnection) DS = New DataSet() MyCommand.Fill(ds, "Titles") MyRepeater.DataSource = ds.Tables("Titles").DefaultView MyRepeater.DataBind() End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <ASP:Repeater id="MyRepeater" runat="server"> <HeaderTemplate> <table width="100%" style="font: 8pt verdana"> <tr style="background-color:DFA894"> <th> Ttulo </th> <th> Id. del ttulo </th> <th> Tipo </th> <th> Id. del editor </th> <th> Precio </th> </tr> </HeaderTemplate> <ItemTemplate>

<tr style="background-color:FFECD8"> <td> <%# DataBinder.Eval(Container.DataItem, "title") %> </td> <td> <%# DataBinder.Eval(Container.DataItem, "title_id") %> </td> <td> <%# DataBinder.Eval(Container.DataItem, "type") %> </td> <td> <%# DataBinder.Eval(Container.DataItem, "pub_id") %> </td> <td> <%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </ASP:Repeater> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> </body> </html>

El control Repeater slo itera por los datos enlazados, procesando la plantilla ItemTemplate una vez por elemento de la coleccin DataSource. No procesa nada aparte de los elementos incluidos en las plantillas. Mientras que Repeater es un iterador de propsito general, DataList proporciona algunas funciones adicionales para controlar el diseo de la lista. A diferencia de Repeater, DataList procesa elementos adicionales, como filas y celdas de tablas, y se extiende con atributos de estilo, aparte de la definicin de plantilla para habilitar el formato enriquecido. Por ejemplo, DataList admite las propiedades RepeatColumns y RepeatDirection que especifican si deberan procesarse los datos en mltiples columnas, as como la direccin (vertical u horizontal) en la que se deben procesar los elementos de datos. DataList tambin admite atributos de estilo, tal y como se muestra en el siguiente ejemplo.

<ASP:DataList runat="server" DataSource="<%#MyData%>" RepeatColumns="2" RepeatDirection="Horizontal" ItemStyle-Font-Size="10pt" ItemStyle-Font-Name="Verdana" > ... </ASP:DataList>
Nota: El resto de la seccin se centra en las mltiples funciones del control DataList. Para obtener ms informacin acerca del control Repeater, vea el tema Repeater de la seccin Referencia de controles de formularios Web de este tutorial. En el siguiente ejemplo se muestra el uso del control DataList. Debe observarse que se ha modificado la apariencia de los elementos de datos desde el ejemplo anterior mediante el simple cambio de los contenidos de la propiedad ItemTemplate del control. Las propiedades RepeatDirection y RepeatColumns determinan cmo se distribuyen las plantillas ItemTemplate.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html>

<script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles", MyConnection) DS = New DataSet() MyCommand.Fill(ds, "Titles") MyDataList.DataSource = ds.Tables("Titles").DefaultView MyDataList.DataBind() End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <ASP:DataList id="MyDataList" RepeatColumns="2" RepeatDirection="Horizontal" runat="server"> <ItemTemplate> <div style="padding:15,15,15,15;font-size:10pt;font-family:Verdana"> <div style="font:12pt verdana;color:darkred"> <i><b><%# DataBinder.Eval(Container.DataItem, "title") %></i></b> </div> <br> <b>Id. de ttulo: </b><%# DataBinder.Eval(Container.DataItem, "title_id") %><br> <b>Categora: </b><%# DataBinder.Eval(Container.DataItem, "type") %><br> <b>Id. del editor: </b><%# DataBinder.Eval(Container.DataItem, "pub_id") %><br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %><p> </div> </ItemTemplate> </ASP:DataList> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> </body> </html>

En el siguiente ejemplo se demuestra an ms la infinita flexibilidad de las plantillas cambiando de nuevo la plantilla ItemTemplate. En esta ocasin, uno de los valores de DataItem se ha sustituido por el atributo "src" de una etiqueta <img>. Tambin se ha utilizado el parmetro String de format de DataBinder.Eval para sustituir el valor de DataItem en la cadena de consulta de una direccin URL.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>

<html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles", MyConnection) DS = New DataSet() MyCommand.Fill(ds, "Titles") MyDataList.DataSource = ds.Tables("Titles").DefaultView MyDataList.DataBind() End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <ASP:DataList id="MyDataList" RepeatColumns="2" runat="server"> <ItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td width=1 bgcolor="BD8672"/> <td valign="top"> <img align="top" src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' > </td> <td valign="top"> <b>Ttulo: </b><%# DataBinder.Eval(Container.DataItem, "title") %><br> <b>Categora: </b><%# DataBinder.Eval(Container.DataItem, "type") %><br> <b>Id. del editor: </b><%# DataBinder.Eval(Container.DataItem, "pub_id") %><br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <p> <a href='<%# DataBinder.Eval(Container.DataItem, "title_id", "purchase.aspx?titleid={0}") %>' > <img border="0" src="/quickstart/aspplus/images/purchase_book.gif" > </a> </td> </tr> </table> </ItemTemplate> </ASP:DataList> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" -->

</body> </html>

Controlar devoluciones desde una plantilla


Como en DataGrid, se puede desencadenar un comando desde el interior de una plantilla de DataList que se pasa a un controlador de eventos conectado al mismo control DataList. Por ejemplo, un control LinkButton dentro de ItemTemplate puede desencadenar un comando Select. Al establecer la propiedad OnSelectedIndexChanged de DataList, se puede llamar a un controlador de eventos como respuesta a este comando. En el siguiente ejemplo se muestra este proceso.

<ASP:DataList id="MyDataList" OnSelectedIndexChanged="MyDataList_Select" runat="server"> <ItemTemplate> <asp:linkbutton CommandName="Select" runat="server"> <%# DataBinder.Eval(Container.DataItem, "title") %> </asp:linkbutton> </ItemTemplate> </ASP:DataList>
En el siguiente ejemplo se muestra cmo acta este cdigo. En el controlador de eventos MyDataList_Select, se llenan otros controles de servidor con los detalles acerca del elemento seleccionado concreto.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (Page.IsPostBack) Dim DS As New DataSet Dim MyCommand As New SqlDataAdapter("select * from Titles where type = 'business'", MyConnection) MyCommand.Fill(ds, "Titles") MyDataList.DataSource = ds.Tables("Titles").DefaultView MyDataList.DataBind() End If End Sub Sub MyDataList_Select(Sender As Object, E As EventArgs) Dim Title As String = MyDataList.DataKeys(MyDataList.SelectedItem.ItemIndex) Dim MyCommand As New SqlDataAdapter("select * from Titles where title_id = '" & Title & "'" , MyConnection) Dim DS As New DataSet MyCommand.Fill(DS, "TitleDetails")

Dim RowView As DataRowView = DS.Tables("TitleDetails").DefaultView(0) DetailsImage.Src = "/quickstart/aspplus/images/title-" & RowView("title_id") & ".gif" DetailsPubId.InnerHtml = "<b>Id. del editor: </b>" & RowView("pub_id").ToString() & "<br>" DetailsTitleId.InnerHtml = "<b>Id. de ttulo: </b>" & RowView("title_id").ToString() & "<br>" DetailsType.InnerHtml = "<b>Categora: </b>" & RowView("type").ToString() + "<br>" DetailsPrice.InnerHtml = "<b>Precio: </b> $ " & RowView("price").ToString() + "<p>" PurchaseLink.InnerHtml = "<img border='0' src='/quickstart/aspplus/images/purchase_book.gif' >" PurchaseLink.HRef="purchase.aspx?titleid=" & RowView("title_id").ToString() DetailsTitle.InnerHtml = RowView("title").ToString() DetailsImage.Visible = true End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <table width="100%"> <tr> <td width="50%"> <ASP:DataList id="MyDataList" OnSelectedIndexChanged="MyDataList_Select" DataKeyField="title_id" runat="server"> <ItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td valign="top"> <img align="top" width="25" border=1 src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' runat="server"/> </td> <td valign="top"> <b>Ttulo: </b> <asp:linkbutton Text='<%# DataBinder.Eval(Container.DataItem, "title") %>' CommandName="Select" style="color:darkred" runat="server"/> <br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %><br> </td> </tr> </table> </ItemTemplate> </ASP:DataList> </td> <td valign="top" style="padding-top:15" width="50%"> <table cellpadding="5" width="100%" style="font: 10pt verdana"> <tr> <td> <img id="DetailsImage" visible="false" runat="server"> </td> <td valign="top" width="400"> <div style="font: 12pt verdana;color:darkred">

<i><b><span id="DetailsTitle" runat="server"/></i></b><br> </div> <span id="DetailsTitleId" runat="server"/> <span id="DetailsPubId" runat="server"/> <span id="DetailsType" runat="server"/> <span id="DetailsPrice" runat="server"/> <a id="PurchaseLink" runat="server"/> </td> </tr> </table> </td> </tr> </table> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> </form> </body> </html>

Debe observarse que mientras DataList reconoce unos pocos comandos especiales, como Select y Edit/Update/Cancel, la cadena de comando desencadenada en el interior de la plantilla puede ser cualquier cadena arbitraria. Para todos los comandos, se desencadena OnItemCommand de DataList. Este evento puede conectarse a un controlador de la misma forma que en el ejemplo anterior, tal y como se muestra en el siguiente ejemplo.

<script runat="server"> Protected Sub MyDataList_ItemCommand(Sender As Object, E As DataListCommandEventArgs) Dim Command As String = E.CommandName Select Case Command Case "Discuss" ShowDiscussions(E.Item.DataItem) Case "Ratings" ShowRatings(E.Item.DataItem) End Select End Sub </script> <ASP:DataList id="MyDataList" OnItemCommand="MyDataList_ItemCommand" runat="server"> <ItemTemplate> <asp:linkbutton CommandName="Ratings" runat="server"> View Ratings </asp:linkbutton> | <asp:linkbutton CommandName="Discuss" runat="server"> View Discussions </asp:linkbutton> </ItemTemplate> </ASP:DataList>

Debe observarse que, debido a que ms de un comando puede desencadenar este controlador de eventos, se debe emplear una instruccin switch para determinar el comando concreto que se desencaden. En el siguiente ejemplo se muestra cmo acta este cdigo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") If Not (Page.IsPostBack) Dim DS As New DataSet Dim MyCommand As New SqlDataAdapter("select * from Titles where type = 'business'", MyConnection) MyCommand.Fill(ds, "Titles") MyDataList.DataSource = ds.Tables("Titles").DefaultView MyDataList.DataBind() End If End Sub Sub MyDataList_Select(Sender As Object, E As EventArgs) Dim Title As String = MyDataList.DataKeys(MyDataList.SelectedItem.ItemIndex) Dim MyCommand As New SqlDataAdapter("select * from Titles where title_id = '" & Title & "'" , MyConnection) Dim DS As New DataSet MyCommand.Fill(DS, "TitleDetails") Dim RowView As DataRowView = DS.Tables("TitleDetails").DefaultView(0) DetailsImage.Src = "/quickstart/aspplus/images/title-" & RowView("title_id") & ".gif" DetailsPubId.Text = "<b>Id. del editor: </b>" & RowView("pub_id").ToString() & "<br>" DetailsTitleId.Text = "<b>Id. de ttulo: </b>" & RowView("title_id").ToString() & "<br>" DetailsType.Text = "<b>Categora: </b>" & RowView("type").ToString() + "<br>" DetailsPrice.Text = "<b>Precio: </b> $ " & RowView("price").ToString() + "<p>" PurchaseLink.Text = "<img border='0' src='/quickstart/aspplus/images/purchase_book.gif' >" PurchaseLink.NavigateUrl = "purchase.aspx?titleid=" & RowView("title_id").ToString() DetailsTitle.Text = RowView("title").ToString() DetailsImage.Visible = true End Sub Sub MyDataList_ItemCommand(Sender As Object, E As DataListCommandEventArgs) Dim Title As String = MyDataList.DataKeys(E.Item.ItemIndex) Dim Command As String = E.CommandName Select (Command) Case "Discuss" : ShowDiscussions(Title)

Case "Ratings" : ShowRatings(Title) End Select End Sub Sub ShowRatings(Title As String) Message.InnerHtml = "<h5>Clasificacin para """ & Title & """</h5>" Message.InnerHtml &= "Imprimir clasificacin aqu..." End Sub Sub ShowDiscussions(Title As String) Message.InnerHtml = "<h5>Discusiones sobre """ & Title & """</h5>" Message.InnerHtml &= "Imprimir discusiones aqu..." End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <table width="100%"> <tr> <td width="50%"> <ASP:DataList id="MyDataList" OnSelectedIndexChanged="MyDataList_Select" OnItemCommand="MyDataList_ItemCommand" DataKeyField="title_id" runat="server"> <ItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td valign="top"> <img align="top" width="25" border=1 src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' runat="server"/> </td> <td valign="top"> <b>Ttulo: </b> <asp:linkbutton Text='<%# DataBinder.Eval(Container.DataItem, "title") %>' CommandName="Select" style="color:darkred" runat="server"/> <br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <br> <asp:linkbutton Text="Discusiones" CommandName="Discuss" style="color:darkred;font:8pt tahoma" runat="server"/> | <asp:linkbutton Text="Clasificacin" CommandName="Ratings" style="color:darkred;font:8pt tahoma" runat="server"/> </td> </tr> </table> </ItemTemplate> </ASP:DataList> </td> <td valign="top" style="padding-top:15" width="50%">

<table cellpadding="5" width="100%" style="font: 10pt verdana"> <tr> <td> <img id="DetailsImage" visible="false" runat="server"> </td> <td valign="top" width="400"> <div style="font: 12pt verdana;color:darkred"> <i><b><asp:Label id="DetailsTitle" runat="server"/></i></b><br> </div> <asp:Label id="DetailsTitleId" runat="server"/> <asp:Label id="DetailsPubId" runat="server"/> <asp:Label id="DetailsType" runat="server"/> <asp:Label id="DetailsPrice" runat="server"/> <asp:HyperLink id="PurchaseLink" runat="server"/> </td> </tr> </table> </td> </tr> </table> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> <div id="Message" style="font: 10pt verdana;padding:0,15,15,15" runat="server"/> </form> </body> </html>

Utilizar plantillas de seleccin y de edicin


Adems de controlar el comando Select mediante un controlador de eventos en mbito de pgina, DataList puede responder al evento internamente. Si SelectedItemTemplate se define para DataList, DataList procesa esta plantilla para el elemento que desencaden el comando Select. En el siguiente ejemplo se utiliza SelectedItemTemplate para poner en negrita el ttulo del libro seleccionado.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Dim MyConnection As SqlConnection Sub Page_Load(Sender As Object, E As EventArgs) MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim DS As New DataSet Dim MyCommand As New SqlDataAdapter("select * from Titles where type = 'business'", MyConnection) MyCommand.Fill(DS, "Titles") MyDataList.DataSource = DS.Tables("Titles").DefaultView If Not (Page.IsPostBack) MyDataList.DataBind() End If

End Sub Sub MyDataList_Select(Sender As Object, E As EventArgs) Dim Title As String = MyDataList.DataKeys(MyDataList.SelectedItem.ItemIndex) Dim MyCommand As New SqlDataAdapter("select * from Titles where title_id = '" & Title & "'" , MyConnection) Dim DS As New DataSet MyCommand.Fill(DS, "TitleDetails") Dim RowView As DataRowView = DS.Tables("TitleDetails").DefaultView(0) DetailsImage.Src = "/quickstart/aspplus/images/title-" & RowView("title_id") & ".gif" DetailsPubId.Text = "<b>Id. del editor: </b>" & RowView("pub_id").ToString() & "<br>" DetailsTitleId.Text = "<b>Id. de ttulo: </b>" & RowView("title_id").ToString() & "<br>" DetailsType.Text = "<b>Categora: </b>" & RowView("type").ToString() + "<br>" DetailsPrice.Text = "<b>Precio: </b> $ " & RowView("price").ToString() + "<p>" PurchaseLink.Text = "<img border='0' src='/quickstart/aspplus/images/purchase_book.gif' >" PurchaseLink.NavigateUrl = "purchase.aspx?titleid=" & RowView("title_id").ToString() DetailsTitle.Text = RowView("title").ToString() DetailsImage.Visible = true MyDataList.DataBind() End Sub Sub MyDataList_ItemCommand(Sender As Object, E As DataListCommandEventArgs) Dim Title As String = MyDataList.DataKeys(E.Item.ItemIndex) Dim MyLinkButton As LinkButton = E.CommandSource Select (MyLinkButton.Text) Case "Discussions" : ShowDiscussions(Title) Case "Ratings" : ShowRatings(Title) End Select End Sub Sub ShowRatings(Title As String) Message.InnerHtml = "<h5>Clasificacin para """ & Title & """</h5>" Message.InnerHtml &= "Imprimir clasificacin aqu..." End Sub Sub ShowDiscussions(Title As String) Message.InnerHtml = "<h5>Discusiones sobre """ & Title & """</h5>" Message.InnerHtml &= "Imprimir discusiones aqu..." End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <table width="100%"> <tr>

<td width="50%"> <ASP:DataList id="MyDataList" OnSelectedIndexChanged="MyDataList_Select" OnItemCommand="MyDataList_ItemCommand" DataKeyField="title_id" runat="server"> <ItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td valign="top"> <img align="top" width="25" border=1 src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' runat="server"/> </td> <td valign="top"> <b>Ttulo: </b> <asp:linkbutton Text='<%# DataBinder.Eval(Container.DataItem, "title") %>' CommandName="Select" style="color:darkred" runat="server"/> <br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <br> <asp:linkbutton Text="Discusiones" CommandName="Discuss" style="color:darkred;font:8pt tahoma" runat="server"/> | <asp:linkbutton Text="Clasificacin" CommandName="Ratings" style="color:darkred;font:8pt tahoma" runat="server"/> </td> </tr> </table> </ItemTemplate> <EditItemTemplate> <table cellpadding=10 style="font: 10pt verdana" > <tr> <td valign="top"> <img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title{0}.gif") %>' align="top" width="25" border=1 runat="server"/> </td> <td valign="top"> <b>Title: </b> <asp:linkbutton Font-Bold="true" Text='<%# DataBinder.Eval(Container.DataItem, "title") %>' CommandName="Select" style="color:darkred" runat="server"/> <br> <b>Price: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <br> <asp:linkbutton Text="Discussions" Command="Discuss" style="color:darkred;font:8pt tahoma" runat="server"/> | <asp:linkbutton Text="Ratings" Command="Ratings" style="color:darkred;font:8pt tahoma" runat="server"/> </td> </tr> </table> </EditItemTemplate> </ASP:DataList> </td> <td valign="top" style="padding-top:15" width="50%"> <table cellpadding="5" width="100%" style="font: 10pt verdana">

<tr> <td> <img id="DetailsImage" visible="false" runat="server"> </td> <td valign="top" width="400"> <div style="font: 12pt verdana;color:darkred"> <i><b><asp:Label id="DetailsTitle" runat="server"/></i></b><br> </div> <asp:Label id="DetailsTitleId" runat="server"/> <asp:Label id="DetailsPubId" runat="server"/> <asp:Label id="DetailsType" runat="server"/> <asp:Label id="DetailsPrice" runat="server"/> <asp:HyperLink id="PurchaseLink" runat="server"/> </td> </tr> </table> </td> </tr> </table> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> <div id="Message" style="font: 10pt verdana;padding:0,15,15,15" runat="server"/> </form> </body> </html>

DataList tambin admite EditItemTemplate para procesar un elemento cuyo ndice es igual a la propiedad EditItemIndex de DataList. Para obtener ms detalles sobre cmo editar y actualizar obras, vea el tema Actualizar datos de la seccin Acceso a datos de este tutorial.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub PopulateList() Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type = 'business'", MyConnection) DS = New DataSet() MyCommand.Fill(ds, "Titles") MyDataList.DataSource = ds.Tables("Titles").DefaultView MyDataList.DataBind() End Sub Sub Page_Load(Sender As Object, E As EventArgs) If Not (Page.IsPostBack)

PopulateList() End If End Sub Sub MyDataList_Edit(Sender As Object, E As DataListCommandEventArgs) MyDataList.EditItemIndex = CInt(e.Item.ItemIndex) PopulateList() End Sub Sub MyDataList_Update(Sender As Object, E As DataListCommandEventArgs) ' database update left out for simplicity's sake... Dim EditText As HtmlInputText EditText = E.Item.FindControl("edit_price") Message.InnerHtml = "Precio actualizado: " & EditText.Value MyDataList.EditItemIndex = -1 PopulateList() End Sub Sub MyDataList_Cancel(Sender As Object, E As DataListCommandEventArgs) MyDataList.EditItemIndex = -1 PopulateList() End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <ASP:DataList id="MyDataList" RepeatColumns="2" OnEditCommand="MyDataList_Edit" OnUpdateCommand="MyDataList_Update" OnCancelCommand="MyDataList_Cancel" runat="server"> <ItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td width=1 bgcolor="BD8672"/> <td valign="top"> <img align="top" src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' > </td> <td valign="top"> <b>Ttulo: </b><%# DataBinder.Eval(Container.DataItem, "title") %><br> <b>Categora: </b><%# DataBinder.Eval(Container.DataItem, "type") %><br> <b>Id. del editor: </b><%# DataBinder.Eval(Container.DataItem, "pub_id") %><br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <p> <asp:linkbutton CommandName="Edit" runat="server"> <img border="0" src="/quickstart/aspplus/images/edit_book.gif" > </asp:linkbutton> </td> </tr> </table> </ItemTemplate>

<EditItemTemplate> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td width=1 bgcolor="BD8672"/> <td valign="top"> <img align="top" src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' > </td> <td valign="top"> <b>Ttulo: </b><%# DataBinder.Eval(Container.DataItem, "title") %><br> <b>Categora: </b><%# DataBinder.Eval(Container.DataItem, "type") %><br> <b>Id. del editor: </b><%# DataBinder.Eval(Container.DataItem, "pub_id") %><br> <b>Precio: </b><input id="edit_price" type="text" value='<%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %>' runat="server"/> <p> <asp:linkbutton CommandName="Update" runat="server"><img border="0" src="/quickstart/aspplus/images/update_book.gif" ></asp:linkbutton> <asp:linkbutton CommandName="Cancel" runat="server"><img border="0" src="/quickstart/aspplus/images/cancel_book.gif" ></asp:linkbutton> </td> </tr> </table> </EditItemTemplate> </ASP:DataList> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> </form> <div style="font: 10pt verdana;padding:0,15,15,15" id="Message" runat="server"/> </body> </html>

Buscar un control dentro de una plantilla


En ocasiones, resulta necesario ubicar un control contenido dentro de una plantilla. Si se le da un identificador a un control en una plantilla, dicho control puede recuperarse desde el contenedor (el primer control de la jerarqua primaria que admite INamingContainer). En este caso, el contenedor es el control DataListItem. Debe observarse que aunque haya varios controles con el mismo identificador (en virtud de la repeticin de DataList), cada uno est contenido de forma lgica en el espacio de nombres del control contenedor DataListItem. Se puede atravesar la coleccin Items de DataList para recuperar DataListItem para un ndice dado y, a continuacin, llamar al mtodo FindControl de DataListItem (heredado de la clase base Control) para recuperar un control con un identificador particular.

<script runat="server"> Public Sub Page_Load(sender As Object, E As EventArgs)) ' set datasource and call databind here For I=0 To MyDataList.Items.Count-1 Dim IsChecked As String = MyDataList.Items(i).FindControl("Save").Checked.ToString() If IsChecked = "True" Then ... End If Next End Sub </script>

<ASP:DataList id="MyDataList" runat="server"> <ItemTemplate> <asp:CheckBox id="Save" runat="server"/> <b>Save to Favorites</b> </ItemTemplate> </ASP:DataList>

En el siguiente ejemplo se muestra cmo acta este cdigo.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) If Not (Page.IsPostBack) Dim DS As DataSet Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Titles where type = 'business'", MyConnection) DS = New DataSet() MyCommand.Fill(DS, "Titles") MyDataList.DataSource = DS.Tables("Titles").DefaultView MyDataList.DataBind() End If End Sub Sub Submit_Click(Src As Object, E As EventArgs) Dim I As Long For I=0 To MyDataList.Items.Count -1 Dim CurrentCheckBox As CheckBox CurrentCheckBox = MyDataList.Items(I).FindControl("Save") Message.InnerHtml &= "Elemento(" & i & "): " & CurrentCheckBox.Checked.ToString() & "<br>" Next End Sub </script> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/header.inc" --> <ASP:DataList id="MyDataList" RepeatColumns="2" runat="server"> <ItemTemplate>

<table cellpadding=10 style="font: 10pt verdana"> <tr> <td width=1 bgcolor="BD8672"/> <td valign="top"> <img align="top" src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>' > </td> <td valign="top"> <b>Ttulo: </b><%# DataBinder.Eval(Container.DataItem, "title") %><br> <b>Categora: </b><%# DataBinder.Eval(Container.DataItem, "type") %><br> <b>Id. del editor: </b><%# DataBinder.Eval(Container.DataItem, "pub_id") %><br> <b>Precio: </b><%# DataBinder.Eval(Container.DataItem, "price", "$ {0}") %> <p> <asp:CheckBox id="save" runat="server"/> <b>Guardar en Favoritos</b> </td> </tr> </table> </ItemTemplate> </ASP:DataList> <p> <div style="padding:0,15,0,15"> <input type="submit" Value="Actualizar favoritos" OnServerClick="Submit_Click" runat="server"/> </div> <p> <!-- #include virtual="/quickstart/aspplus/samples/webforms/customize/footer.inc" --> </form> <div style="font: 10pt verdana" EnableViewState="false" id="Message" runat="server"/> </body> </html>

Resumen de la seccin 1. 2. 3. 4. 5. 6. 7.
Los controles DataList y Repeater proporcionan a los programadores un control ajustado sobre el procesamiento de listas enlazadas a datos. El procesamiento de datos enlazados se controla mediante una plantilla, como HeaderTemplate, FooterTemplate o ItemTemplate. El control Repeater es un iterador de propsito general y no inserta nada en el procesamiento que no est contenido en una plantilla. El control DataList ofrece ms control sobre el diseo y el estilo de elementos y extrae su propio cdigo de rendimiento para aplicar formato. DataList admite los eventos Select, Edit/Update/Cancel e Item Command que pueden controlarse en el mbito de pgina conectando los controladores de eventos a los eventos Command de DataList. DataList admite SelectedItemTemplate y EditItemTemplate para controlar el procesamiento de un elemento seleccionado que se puede editar. Los controles se pueden recuperar mediante programacin desde una plantilla con el mtodo Control.FindControl. Debera llamarse en un DataListItem recuperado a partir de la coleccin Items de DataList.

Trabajar con objetos empresariales


Encapsular lgica de programacin en componentes empresariales es una parte esencial de cualquier aplicacin del mundo real, ya sea en tecnologa Web o de otro tipo. En ASP.NET, los objetos empresariales son bloques para construir aplicaciones Web de varios niveles, tales

como aquellas con una capa para acceso de datos o reglas comunes para aplicaciones. Esta seccin muestra cmo escribir algunos componentes sencillos e incluirlos en las pginas de formularios Web de la aplicacin.

El directorio /Bin de la aplicacin


Un problema que se plantea con el uso del modelo COM para componentes de aplicaciones Web es que esos componentes se deben registrar (normalmente con la herramienta regsvr32) antes de poder utilizarlos desde una aplicacin ASP tradicional. La administracin remota de estos tipos de aplicaciones no suele ser posible, ya que la herramienta de registro debe ejecutarse localmente en el servidor. Una dificultad adicional es que estos componentes permanecen bloqueados en disco una vez cargados por la aplicacin, de modo que para poder sustituirlos o eliminarlos se debe detener completamente el servidor Web. ASP.NET intenta resolver estos problemas haciendo que los componentes se puedan colocar en un directorio conocido, de manera que se encuentren automticamente durante la ejecucin. Este directorio conocido se denomina /bin, y se encuentra situado inmediatamente bajo el directorio raz de la aplicacin (un directorio virtual definido por Internet Information Services (IIS)). La ventaja es que no se requiere realizar ningn registro para que la aplicacin ASP.NET Framework pueda utilizar los componentes (stos se pueden distribuir simplemente copindolos en el directorio /bin, o bien realizando una transferencia de archivos mediante FTP). Adems de ofrecer un mtodo sin necesidad de registro para distribuir componentes compilados, ASP.NET no requiere que estos componentes permanezcan bloqueados en el disco durante la ejecucin. Internamente, ASP.NET duplica los ensamblados presentes en /bin y carga estas copias "sombra" en lugar de los originales. Los componentes originales se pueden reemplazar aunque el servidor Web est an en funcionamiento. Los cambios del directorio /bin se detectan automticamente durante la ejecucin. Cuando se detecta un cambio, ASP.NET permite que las solicitudes actualmente en ejecucin se completen, y dirige todas las nuevas solicitudes entrantes a la aplicacin que utiliza el nuevo componente o componentes.

Importar objetos empresariales


En su nivel ms bsico, un componente empresarial es simplemente una clase para la que se puede crear una instancia desde la pgina de formularios Web que la importa. En el siguiente ejemplo, se define una clase sencilla HelloWorld. La clase dispone de un constructor pblico (el cual se ejecuta cuando se crea por primera vez una instancia de la clase), una propiedad nica de tipo String denominada FirstName y un mtodo SayHello que imprime un saludo con el valor de la propiedad FirstName.

Imports System Imports System.Text Namespace HelloWorld Public Class HelloObj Private _name As String Public Sub New MyBase.New() _name = Nothing End Sub Public Property FirstName As String Get Return(_name) End get Set _name = value End Set End Property Public Function SayHello() As String Dim sb As New StringBuilder("Hello ") If (_name <> Nothing) Then sb.Append(_name) Else sb.Append("World") End If sb.Append("!") Return(sb.ToString()) End Function End Class End Namespace

Para compilar esta clase, se ejecuta el compilador de C# (Csc.exe) desde la lnea de comandos. La opcin /t indica al compilador que genere una biblioteca (DLL), mientras que la opcin /out indica dnde colocar el ensamblado resultante. En este caso, el directorio /bin de la aplicacin se encuentra directamente bajo la raz "aspplus" de este tutorial, y se supone que este comando se est ejecutando desde el directorio del ejemplo, es decir, ...\QuickStart\AspPlus\Samples\WebForms\Busobjs.

csc /t:library /out:..\..\..\..\bin\HelloObj.dll HelloObj.cs


Para Visual Basic, el comando de compilacin equivalente es:

vbc /t:library /out:..\..\..\..\bin\HelloObjVB.dll HelloObj.vb


Para JScript, el comando de compilacin equivalente es:

jsc /out:..\..\..\..\bin\HelloObjJS.dll HelloObj.js


El componente est disponible ahora para cualquier pgina de formularios Web de la aplicacin que necesite utilizarlo. El siguiente ejemplo HelloObj.aspx ilustra esta funcionalidad.

<%@ Import Namespace="HelloWorld" %> <html> <style> div { font: 8pt verdana; background-color:cccccc; border-color:black; border-width:1; border-style:solid; padding:10,10,10,10; } </style> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) Dim Comp As HelloObjVB Comp = New HelloObjVB() Message.InnerHtml &= Comp.SayHello() + "<p>" Comp.FirstName = "Microsoft .NET Framework" Message.InnerHtml &= Comp.SayHello() + "<p>" Comp.FirstName = "ASP.NET" Message.InnerHtml &= Comp.SayHello() + "<p>" Comp.FirstName = "Mundo!" Message.InnerHtml &= Comp.SayHello() End Sub </script> <body style="font: 10pt verdana">

<h3>Componente administrado simple</h3> <h5>Resultado del objeto: </h5> <div id="Message" runat="server"/> </body> </html>

Observe la directiva Import, en la parte superior de la pgina, que especifica el espacio de nombres que se va a incluir. Una vez que el espacio de nombres se ha incluido mediante esta directiva, la clase se puede utilizar desde dentro de la pgina de formularios Web. Como el mdulo de ejecucin de ASP.NET carga previamente el ensamblado, slo se requiere una simple importacin del espacio de nombres para hacer que el componente est disponible. El siguiente ejemplo de cdigo ilustra el uso de la directiva Import.

<%@ Import Namespace="HelloWorld" %>


De forma predeterminada, ASP.NET carga todos los ensamblados desde el directorio /bin cuando se inicia la aplicacin. Los ensamblados que se deben cargar se especifican por medio de la configuracin del sistema. Para obtener ms informacin, vea la seccin Descripcin general de la configuracin. Mediante la configuracin, tambin es posible importar ensamblados adicionales en una aplicacin. Por ejemplo:

<configuration> <compilation> <assemblies> <!--The following assemblies are loaded explicitly from the global cache--> <add assembly="System.Data"/> <add assembly="System.Web.Services"/> <add assembly="System.Drawing"/> <!--This tells ASP.NET to load all assemblies from /bin--> <add assembly="*"/> </assemblies> </compilation> </configuration>
Nota: el mbito de cada ensamblado cargado desde /bin se limita a la aplicacin en la que se ejecuta. Esto significa que las aplicaciones del mismo nivel podran utilizar diferentes ensamblados con los mismos nombres de clases o espacios de nombres, sin conflictos.

Pgina de formularios Web sencilla de dos niveles


El uso clsico para un componente externo consiste en realizar acceso a datos. De esta forma, se simplifica el cdigo de la pgina, se mejora la legibilidad y se separa la lgica de la interfaz de usuario de la funcionalidad del sistema. El siguiente ejemplo muestra una pgina de formularios Web sencilla de dos niveles que utiliza un componente de acceso a datos para recuperar informacin de productos.

<%@ Import Namespace="DataLayer" %> <html> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If Not (Page.IsPostBack) Dim Data As DataObjVB Data = New DataObjVB("server=(local)\NetSDK;database=grocertogo;Trusted_Connection=yes") Categories.DataSource = Data.GetCategories() Categories.DataBind() End If End Sub Sub Submit_Click(Sender As Object, E As EventArgs) Dim Data As DataObjVB

Data = New DataObjVB("server=(local)\NetSDK;database=grocertogo;Trusted_Connection=yes") Products.DataSource = Data.GetProductsForCategory(Categories.SelectedItem.Value) Products.DataBind() End Sub </script> <body style="font: 10pt verdana" bgcolor="ffffcc"> <form runat="server"> <h3>Web Forms simples de dos niveles</h3> Seleccionar una categora: <ASP:DropDownList id="Categories" DataValueField="CategoryName" runat="server"/> <input type="Submit" OnServerClick="Submit_Click" Value="Obtener productos" runat="server"/><p> <ASP:DataList id="Products" ShowHeader=false ShowFooter=false RepeatColumns="2" RepeatDirection="horizontal" BorderWidth=0 runat="server"> <ItemTemplate> <table> <tr> <td width="150" style="text-align:center; font-size:8pt; vertical-align:top; height:200"> <ASP:ImageButton borderwidth=6 bordercolor="#ffffcc" command="Select" ImageUrl='<%# DataBinder.Eval(Container.DataItem, "ImagePath") %>' runat="server"/> <p> <%# DataBinder.Eval(Container.DataItem, "ProductName") %> <br> <%# DataBinder.Eval(Container.DataItem, "UnitPrice", "{0:C}").ToString() %> </td> </tr> </table> </ItemTemplate> </ASP:DataList> </form> </body> </html>

El componente de acceso a datos recibe un nico parmetro en su constructor que especifica la cadena de conexin con la base de datos de productos. La pgina de formularios Web llama al mtodo GetCategories del componente para rellenar una lista desplegable y, tambin, llama al mtodo GetProductsForCategory del componente para mostrar los productos correspondientes a la categora seleccionada por el usuario.

Pgina de formularios Web sencilla de tres niveles


Un modelo de aplicacin de tres niveles extiende el caso de dos niveles de modo que incluya reglas empresariales entre la interfaz de usuarios y la lgica de acceso a datos. Este modelo permite a los programadores de interfaces de usuario trabajar con un nivel superior de abstraccin en vez de manipular los datos directamente por medio de las API de componentes de acceso a datos a bajo nivel. Normalmente, el componente empresarial central impone reglas empresariales y garantiza que las relaciones y las restricciones de clave principal de la base de datos se cumplan. El siguiente ejemplo utiliza el componente central para calcular un descuento segn un identificador de proveedor de dos dgitos especificado por el cliente.

<%@ Page ClientTarget="DownLevel"%> <%@ Import Namespace="BusinessLayer" %> <html>

<script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If Not (IsPostBack) Dim Bus As BusObjVB Bus = New BusObjVB() Categories.DataSource = Bus.GetCategories() Categories.DataBind() End If End Sub Sub Submit_Click(Sender As Object, E As EventArgs) If (Page.IsValid) Dim Id As Integer = 0 If Not (CustomerId.Text = "") Id = CInt(CustomerId.Text) End If Dim Bus As BusObjVB Bus = new BusObjVB() Products.DataSource = Bus.GetProductsForCategory(Categories.SelectedItem.Value,Id) End If Products.DataBind() End Sub </script> <body style="font: 10pt verdana" bgcolor="ffffcc"> <form runat="server"> <h3>Web Forms simple de tres niveles</h3> Seleccionar una categora: <ASP:DropDownList id="Categories" DataValueField="CategoryName" runat="server"/> &nbsp; Id. de cliente preferido: <ASP:TextBox id="CustomerId" Width="35" runat="server"/> &nbsp; <input type="Submit" OnServerClick="Submit_Click" Value="Obtener productos" runat="server"/> &nbsp;&nbsp; <asp:RegularExpressionValidator id="RegExValidator" ControlToValidate="CustomerId" ValidationExpression="[0-9]{2}" Display="Dynamic" Font-Name="verdana" Font-Size="10" runat=server> El id. de usuario debe tener dos dgitos numricos </asp:RegularExpressionValidator> <p> <ASP:DataList id="Products" ShowHeader=false ShowFooter=false RepeatColumns="2" RepeatDirection="horizontal" BorderWidth=0 runat="server">

<ItemTemplate> <table> <tr> <td width="150" style="text-align:center; font-size:8pt; vertical-align:top; height:200"> <ASP:ImageButton borderwidth=6 bordercolor="#ffffcc" command="Select" ImageUrl='<%# DataBinder.Eval(Container.DataItem, "ImagePath") %>' runat="server"/> <p> <%# DataBinder.Eval(Container.DataItem, "ProductName") %> <br> <%# DataBinder.Eval(Container.DataItem, "UnitPrice", "{0:C}").ToString() %> </td> </tr> </table> </ItemTemplate> </ASP:DataList> </form> </body> </html>

Resumen de la seccin
1. El mdulo de ejecucin de ASP.NET busca los objetos empresariales (ensamblados locales) en un directorio /bin conocido, directamente bajo la raz de la aplicacin. El directorio /bin ofrece las siguientes ventajas: o No se requiere registro. No se requiere registro para poner un ensamblado a disposicin de las pginas de la aplicacin. Ya est disponible en virtud de su ubicacin en el directorio /bin. El cdigo compilado se puede distribuir simplemente copindolo o transfirindolo mediante FTP a esa ubicacin. o No es necesario reiniciar el servidor. Cuando se cambia cualquier parte de una aplicacin ASP.NET Framework (por ejemplo, al reemplazar una DLL en /bin), las nuevas solicitudes inician inmediatamente la ejecucin con el archivo o archivos modificados. Las solicitudes actualmente en ejecucin pueden terminarse antes de que la antigua aplicacin deje de utilizarse. No es necesario reiniciar el servidor Web cuando cambie la aplicacin, ni siquiera al reemplazar el cdigo compilado. o No se producen conflictos de espacios de nombres. El mbito de cada ensamblado cargado desde /bin se limita a la aplicacin en la que se ejecuta. Esto significa que las aplicaciones del mismo nivel podran utilizar diferentes ensamblados con los mismos nombres de clases o espacios de nombres, sin conflictos.

2.

Las clases de un ensamblado se ponen a disposicin de una pgina de la aplicacin mediante una directiva Import dentro del archivo .aspx. 3. Las aplicaciones en dos niveles simplifican el cdigo de una pgina, mejoran la legibilidad y separan la lgica de la interfaz de usuario de la funcionalidad del sistema. 4. Las aplicaciones de tres niveles extienden el modelo de dos niveles para permitir a los programadores de interfaces de usuario trabajar con un mayor nivel de abstraccin. Normalmente, el componente empresarial central impone reglas empresariales y garantiza que las relaciones y las restricciones de clave principal de la base de datos se cumplan.

Crear controles personalizados


En esta seccin del tutorial se explica a los programadores avanzados la forma de programar controles de servidor ASP.NET que funcionen en el marco de trabajo de pginas ASP.NET. Al programar sus propios controles de servidor ASP.NET personalizados, es posible encapsular una interfaz de usuario personalizada y otras caractersticas de funcionalidad en controles que se pueden reutilizar en pginas ASP.NET. El tutorial proporciona una introduccin sobre la creacin de controles personalizados mediante ejemplos interactivos. Para obtener ms informacin acerca de la creacin de controles, vea Programar controles de servidor ASP.NET en la documentacin del SDK de Microsoft .NET Framework. Nota: los controles descritos en esta seccin podran no funcionar correctamente en un diseador de formularios, como Microsoft Visual Studio .NET, aunque funcionen correctamente en las pginas ASP.NET en tiempo de ejecucin. Para trabajar en un diseador, un control debe aplicar atributos de tiempo de diseo que no se describen aqu. Para obtener informacin detallada acerca de los atributos de tiempo de diseo que se deben aplicar, vea Atributos de tiempo de diseo para componentes en la documentacin del SDK.

Programar un control personalizado simple


Es fcil iniciar la creacin de sus propios controles de servidor ASP.NET. Para crear un control personalizado simple, todo lo que tiene que hacer es definir una clase que se derive de System.Web.UI.Control System.Web.UI.Control Render. El mtodo Render utiliza un argumento de tipo System.Web.UI.HtmlTextWriter. El cdigo HTML que el control enva al cliente se pasa como un argumento de tipo cadena al mtodo Write de HtmlTextWriter.

En el ejemplo siguiente se muestra un control simple que procesa una cadena de mensaje.

<%@ Register TagPrefix="SimpleControlSamples" Namespace="SimpleControlSamples" Assembly="SimpleControlSamplesVB" %> <html> <body> <form method="POST" action="Simple.aspx" runat=server> <SimpleControlSamples:SimpleVB id="MyControl" runat=server/> </form> </body> </html>

Definir propiedades sencillas


Las propiedades son como campos "inteligentes" con mtodos de descriptor de acceso. Hay que exponer propiedades en lugar de campos pblicos de los controles, ya que las propiedades permiten ocultar datos, crear versiones y son compatibles con los diseadores visuales. Las propiedades tienen mtodos get/set de descriptores de acceso que establecen y obtienen valores de propiedades, y que permiten ejecutar lgica de programa adicional si es necesario. En el siguiente ejemplo se muestra la forma de agregar propiedades sencillas que corresponden a tipos de datos primitivos, como nmeros enteros, booleanos o cadenas. En el ejemplo se definen tres propiedades: Message es de tipo cadena, MessageSize es de tipo enumeracin e Iterations es de tipo entero. Hay que tener en cuenta la sintaxis de pgina para establecer propiedades simples o de tipo enumeracin.

<%@ Register TagPrefix="SimpleControlSamples" Namespace="SimpleControlSamples" Assembly="SimpleControlSamplesVB" %> <html> <body> <form method="POST" runat="server"> <SimpleControlSamples:SimplePropertyVB Message="Hola" MessageSize="Large" Iterations=3 runat=server/> </form> </body> </html>

Definir propiedades de clase

Si una clase A tiene una propiedad cuyo tipo es la clase B, las propiedades de B (si existen) sern las subpropiedades de A. En el ejemplo siguiente se define un control SimpleSubProperty personalizado que tiene una propiedad de tipo Format. Format es una clase que tiene dos propiedades primitivas: Color y Size, que a su vez sern subpropiedades de SimpleSubProperty.

<%@ Register TagPrefix="SimpleControlSamples" Namespace="SimpleControlSamples" Assembly="SimpleControlSamplesVB" %> <html> <body> <form method="POST" runat="server"> <SimpleControlSamples:SimpleSubPropertyVB Message="Hola" Format-Color="red" Format-Size="3" runat=server/> </form> </body> </html>

Hay que tener en cuenta que ASP.NET tiene una sintaxis especial para establecer el valor de las subpropiedades. En el siguiente ejemplo de cdigo se muestra la manera de establecer de forma declarativa los valores de las subpropiedades Format.Color y Format.Size en SimpleSubProperty. La sintaxis "-" denota una subpropiedad.

<SimpleControlSamples:SimpleSubProperty Message="Hello There" Format-Color="red" Format-Size="3" runat=server/>

Recuperar el contenido interno


Cada control tiene una propiedad Controls que hereda de System.Web.UI.Control. Se trata de una propiedad de coleccin que denota los controles secundarios (si existen) de un control. Si un control no est marcado con ParseChildrenAttribute o est marcado con ParseChildrenAttribute(ChildrenAsProperties = false), el marco de trabajo de pginas ASP.NET aplica la siguiente lgica de anlisis cuando se usa el control de forma declarativa en una pgina. Si el analizador encuentra controles anidados dentro de las etiquetas del control, crea instancias de los controles y los agrega a la propiedad Controls del control. El texto literal entre etiquetas se agrega como un objeto LiteralControl. Los dems elementos anidados generarn un error de analizador. En el ejemplo siguiente se muestra un control personalizado, SimpleInnerContent, que procesa texto agregado entre etiquetas comprobando si se ha agregado un objeto LiteralControl a su coleccin Controls. Si as fuera, obtiene el valor de la propiedad Text del objeto LiteralControl y lo anexa a la cadena de salida.

<%@ Register TagPrefix="SimpleControlSamples" Namespace="SimpleControlSamples" Assembly="SimpleControlSamplesVB" %> <html> <body> <form method="POST" runat="server"> <SimpleControlSamples:SimpleInnerContentVB id="MyControl" runat=server> Mi mensaje est dentro de la etiqueta de control </SimpleControlSamples:SimpleInnerContentVB>

</form> </body> </html>

Nota: si el control personalizado se deriva de WebControl, no tendr la lgica de anlisis descrita en el ejemplo, ya que WebControl estar marcado con ParseChildrenAttribute(ChildrenAsProperties = true), que resulta de una lgica de anlisis diferente. Para obtener ms informacin acerca de ParseChildrenAttribute, vea la documentacin del SDK.

Crear un control compuesto


Es posible crear controles nuevos combinando controles existentes mediante una mezcla de clases. Los controles compuestos son equivalentes a controles de usuario creados con la sintaxis de pginas ASP.NET. La diferencia principal entre los controles de usuario y los controles compuestos es que los controles de usuario se almacenan como archivos de texto .ascx, mientras que los controles compuestos se compilan y se almacenan en ensamblados. Los pasos clave para desarrollar un control compuesto son:

Reemplazar el mtodo CreateChildControls protegido que se hereda de Control para crear instancias de controles secundarios y agregarlas a la coleccin Controls. Si se van a crear en la pgina instancias nuevas del control compuesto de forma repetida, debe implementarse la interfaz de sistema System.Web.UI.INamingContainer. Se trata de una interfaz de etiquetado que no tiene mtodos. Cuando se implementa mediante un control, el marco de trabajo para pginas ASP.NET crea un nuevo mbito de asignacin de nombres bajo ese control. Esto garantiza que los controles secundarios tendrn identificadores nicos en el rbol jerrquico de controles. No es necesario reemplazar el mtodo Render, ya que los controles secundarios proporcionan lgica de procesamiento. Es posible exponer propiedades que sinteticen propiedades de los controles secundarios. En el siguiente ejemplo se define un control compuesto, Composition1, que combina un objeto System.Web.UI.LiteralControl y un objeto System.Web.UI WebControls.TextBox. El control Composition1 expone una propiedad personalizada, Value, de tipo entero, que se asigna a la propiedad Text de TextBox.

<%@ Register TagPrefix="CompositionSampleControls" Namespace="CompositionSampleControls" Assembly="CompositionSampleControlsVB" %> <html> <script language="VB" runat=server> Private Sub AddBtn_Click(Sender As Object, E As EventArgs) MyControl.Value = MyControl.Value + 1 End Sub Private Sub SubtractBtn_Click(Sender As Object, E As EventArgs) MyControl.Value = MyControl.Value - 1 End Sub </script> <body> <form method="POST" action="Composition1.aspx" runat=server> <CompositionSampleControls:Composition1VB id="MyControl" runat=server/> <br> <asp:button text="Sumar" OnClick="AddBtn_Click" runat=server/> |

<asp:button text="Restar" OnClick="SubtractBtn_Click" runat=server/> </form> </body> </html>

Controlar eventos en un control compuesto


Un control compuesto puede controlar eventos desencadenados por sus controles secundarios. Esto se logra proporcionando mtodos de control de eventos y asociando delegados a eventos desencadenados por los controles secundarios. En el siguiente ejemplo se muestra un control compuesto, Composition2, que agrega dos controles de botn (denominados Add y Subtract) al control compuesto del ejemplo anterior y proporciona mtodos de control de eventos para los eventos Click de los botones. Estos mtodos incrementan y disminuyen el valor de la propiedad Value de Composition2. El mtodo CreateChildControls de Composition2 crea instancias de los controladores de eventos (delegados) que hacen referencia a estos mtodos y asocia los delegados a los eventos Click de las instancias de Button. El resultado final es un control que realiza su propio control de eventos: cuando se hace clic en el botn Add, el valor del cuadro de texto aumenta y cuando se hace clic en el botn Subtract, el valor del cuadro de texto disminuye.

<%@ Register TagPrefix="CompositionSampleControls" Namespace="CompositionSampleControls" Assembly="CompositionSampleControlsVB" %> <html> <body> <form method="POST" action="Composition2.aspx" runat=server> <CompositionSampleControls:Composition2VB id="MyControl" runat=server/> </form> </body> </html>

Provocar eventos personalizados desde un control compuesto


Un control compuesto puede definir eventos personalizados que se provocan en respuesta a eventos provocados por sus controles secundarios. En el ejemplo siguiente se muestra un control compuesto, Composition3, que provoca un evento personalizado, Change, en respuesta al evento TextChanged del control secundario TextBox. Esto se realiza de la manera siguiente:

El evento Change personalizado se define mediante el modelo de evento estndar. Este patrn incluye la definicin de un mtodo OnChange protegido que provoca el evento Change.

Public Event Change(Sender as Object, E as EventArgs) Protected Sub OnChange(e As EventArgs) Change(Me, e) End Sub

Se define un mtodo de control de eventos para el evento TextChanged de TextBox. Este mtodo desencadena el evento Change llamando al mtodo OnChange.

Private Sub TextBox_Change(sender As Object, e As EventArgs) OnChange(EventArgs.Empty) End Sub

El mtodo CreateChildControls crea una instancia de un controlador de eventos que hace referencia al mtodo anterior y asocia el controlador de eventos al evento TextChanged de la instancia de TextBox.

Protected Overrides Sub CreateChildControls() ... Dim box As New TextBox() AddHandler Box.TextChanged, AddressOf TextBox_Change ... End Sub
El evento Change se puede controlar en una pgina que aloje al control, como se muestra en el siguiente ejemplo. En este ejemplo, la pgina proporciona un mtodo de control de eventos para el evento Change que establece el valor de la propiedad Value en cero si el nmero escrito por el usuario es negativo.

<%@ Register TagPrefix="CompositionSampleControls" Namespace="CompositionSampleControls" Assembly="CompositionSampleControlsVB" %> <html> <script language="VB" runat=server> Private Sub Composition2_Change(Sender As Object, E As EventArgs) If MyControl.Value < 0 MyControl.Value = 0 End If End Sub </script> <body> <form method="POST" action="Composition3.aspx" runat=server> <CompositionSampleControls:Composition3VB id="MyControl" OnChange="Composition2_Change" runat=server/> </form> </body> </html>

Mantener el estado
Todo control para formularios Web tiene una propiedad State (heredada de Control) que le permite participar en la administracin de State. El tipo de State es Sytem.Web.UI.StateBag, una estructura de datos equivalente a una tabla hash. Un control puede guardar datos en State en forma de claves con sus valores correspondientes. El marco de trabajo de pginas ASP.NET almacena el valor de State en una variable de cadena; el valor realiza un viaje de ida y vuelta al cliente como una variable oculta. Tras la devolucin automtica al servidor, el marco de

trabajo de pginas analiza la cadena de entrada de la variable oculta y llena la propiedad State de cada control de la jerarqua de controles de una pgina. Un control puede restaurar su estado (establecer los valores de las propiedades y los campos anteriores a la devolucin automtica al servidor) mediante la propiedad State. Los programadores de controles deben saber que hay una sobrecarga de rendimiento por viajes de ida y vuelta al cliente, y deben ser cuidadosos con lo que almacenan en State. En el siguiente fragmento de cdigo se muestra una propiedad que se guarda en State.

Public Property Text As String Get Return CType(State("Text"), String)) End Get Set State("Text") = Value End Set End Property

En el siguiente ejemplo se muestra un control personalizado, Label con dos propiedades, Text y FontSize, que se guardan en State. La pgina ASP.NET que utiliza Label contiene botones que tienen controladores de eventos para aumentar el tamao de fuente del texto del control Label al hacer clic en un botn. Por tanto, el tamao de fuente aumentar cada vez que se haga clic en un botn. Esto slo es posible mediante la administracin de estados: Label tiene que saber cul era el tamao de la fuente antes de la devolucin automtica al servidor con el fin de procesar la prxima fuente grande despus de la devolucin automtica al servidor.

<%@ Register TagPrefix="ViewStateControlSamples" Namespace="ViewStateControlSamples" Assembly="ViewStateControlSamplesVB" %> <html> <script language="VB" runat=server> Private Sub Btn1_Click(Sender As Object, E As EventArgs) MyLabel1.Text = "Se hizo clic en el botn 1" MyLabel1.FontSize = MyLabel1.FontSize + 1 End Sub Private Sub Btn2_Click(Sender As Object, E As EventArgs) MyLabel2.Text = "Se hizo clic en el botn 2" MyLabel2.FontSize = MyLabel2.FontSize + 1 End Sub </script> <body> <form method="POST" action="Label.aspx" runat=server> Mensaje1: <ViewStateControlSamples:LabelVB id="MyLabel1" Text="Label1" FontSize=1 runat=server/> <br> Mensaje2: <ViewStateControlSamples:LabelVB id="MyLabel2" Text="Label2" FontSize=1 runat=server/> <br><br> <asp:button Text="Botn1" OnClick="Btn1_Click" runat=server/> | <asp:button Text="Botn2" OnClick="Btn2_Click" runat=server/> </form>

</body> </html>

En el siguiente ejemplo se muestra un control personalizado, Label con dos propiedades, Text y FontSize, que se guardan en State. La pgina ASP.NET que utiliza Label contiene botones que tienen controladores de eventos para aumentar el tamao de fuente del texto del control Label al hacer clic en un botn. Por tanto, el tamao de fuente aumentar cada vez que se haga clic en un botn. Esto slo es posible mediante la administracin de estados: Label tiene que saber cul era el tamao de la fuente antes de la devolucin automtica al servidor con el fin de procesar la prxima fuente grande despus de la devolucin automtica al servidor.

<%@ Register TagPrefix="NonCompositionSampleControls" Namespace="NonCompositionSampleControls" Assembly="NonCompositionSampleControlsVB" %> <html> <script language="VB" runat=server> Private Sub AddBtn_Click(Sender As Object, E As EventArgs) MyControl.Value = MyControl.Value + 1 End Sub Private Sub SubtractBtn_Click(Sender As Object, E As EventArgs) MyControl.Value = MyControl.Value - 1 End Sub </script> <body> <form method="POST" action="NonComposition1.aspx" runat=server> <NonCompositionSampleControls:NonComposition1VB id="MyControl" runat=server/> <br> <asp:button text="Sumar" OnClick="AddBtn_Click" runat=server/> | <asp:button text="Restar" OnClick="SubtractBtn_Click" runat=server/> </form> </body> </html>

Desarrollar un control personalizado (no compuesto) para controlar datos de devolucin automtica al servidor
Al principio del tutorial, se cre un control personalizado sencillo. En el siguiente ejemplo se muestra un control personalizado que hace algo ms complejo: muestra un cuadro de entrada de datos y lee los datos escritos por el usuario. Los controles que examinan datos de devolucin automtica al servidor (entrada) deben implementar la interfaz System.Web.UI.IPostBackDataHandler. Esto indica al marco de trabajo de pginas ASP.NET que un control debe participar en el control de la devolucin automtica de datos al servidor. El marco de trabajo de pginas transfiere los datos de entrada al mtodo LoadPostData de esta interfaz en forma de claves con sus valores correspondientes. En la implementacin de este mtodo, el control puede examinar los datos de entrada y actualizar sus propiedades de la forma indicada a continuacin.

Private _value As Integer = 0

Public Function LoadPostData(postDataKey As String, values As NameValueCollection) As Boolean _value = Int32.Parse(values(Me.UniqueID)) Return(False) End Function <%@ Register TagPrefix="NonCompositionSampleControls" Namespace="NonCompositionSampleControls" Assembly="NonCompositionSampleControlsVB" %> <html> <body> <form method="POST" action="NonComposition2.aspx" runat=server> <NonCompositionSampleControls:NonComposition2VB id="MyControl" runat=server/> </form> </body> </html>

En el siguiente ejemplo se define un control personalizado, NonComposition1, que implementa IPostBackDataHandler y tiene una propiedad, Value. El control muestra un cuadro HTML de entrada de datos cuyo atributo de texto es la representacin en forma de cadena de Value. Esta propiedad se establece examinando datos de entrada de devolucin automtica al servidor. La pgina que utiliza NonComposition1 tambin tiene dos botones con controladores de eventos con el fin de incrementar y disminuir el valor de la propiedad Value de NonComposition1.

<%@ Register TagPrefix="TemplateControlSamples" Namespace="TemplateControlSamplesVB" Assembly="TemplateControlSamplesVB" %> <script runat=server language=VB> Sub Page_Load() DataBind() End Sub </script> <html> <body> <form method="POST" runat="server"> Versin sin plantillas: <TemplateControlSamples:Template1VB Message="Hello World!" runat=server/> <hr> Versin con plantillas: <TemplateControlSamples:Template1VB Message="Hello World!" runat=server> <MessageTemplate> <b><i><u> <%# Container.Message%> </u></i></b>

</MessageTemplate> </TemplateControlSamples:Template1VB> </form> </body> </html>

Generar cdigo JavaScript de cliente para la devolucin automtica personalizada al servidor


Si un control desea capturar eventos de devolucin automtica al servidor (envos de formularios desde un cliente), debe implementarse la interfaz System.Web.UI.IPostBackEventHandler. Esto indica al marco de trabajo de pginas ASP.NET que un control requiere notificacin de un evento de devolucin automtica de datos al servidor. El control utiliza el mtodo RaisePostBackEvent para controlar el evento y provocar otros eventos. Adems, el marco de trabajo de pginas ASP.NET tiene una arquitectura de eventos personalizada que permite a un control generar cdigo JavaScript de cliente que inicia la devolucin automtica personalizada al servidor. Normalmente, la devolucin automtica al servidor la inician pocos elementos, como un botn Enviar o un botn Imagen. Sin embargo, al emitir cdigo JavaScript de cliente, un control tambin puede iniciar la devolucin automtica al servidor desde otros elementos HTML. En el siguiente ejemplo se define un control personalizado, NonComposition2, a partir del ejemplo anterior, NonComposition1. Adems de la interfaz proporcionada por NonComposition1, muestra dos controles HtmlButton que generan cdigo JavaScript de cliente para provocar la devolucin automtica al servidor cuando se haga clic en ellos. Los atributos de nombre de estos botones son Add y Subtract. El marco de trabajo de pginas pasa el atributo de nombre como un argumento de cadena a RaisePostBackEvent. NonComposition2 implementa RaisePostBackEvent con el fin de incrementar el valor de la propiedad Value si se hace clic en Add y para disminuir su valor si se hace clic en Subtract, como se indica a continuacin.

Public Sub RaisePostBackEvent(eventArgument As String) If eventArgument = "Add" Then Me.Value = Me.Value + 1 Else Me.Value = Me.Value - 1 End If End Sub

La interfaz de usuario que se presenta al cliente es idntica a la del ejemplo anterior; sin embargo, se presenta la interfaz de usuario completa mediante un control personalizado que tambin controla los eventos de devolucin automtica al servidor. El programador de la pgina puede agregar simplemente NonComposition2 a la pgina, sin proporcionar lgica de control de eventos. En el ejemplo siguiente se presenta este cdigo en accin.

<%@ Register TagPrefix="TemplateControlSamples" Namespace="TemplateControlSamplesVB" Assembly="TemplateControlSamplesVB" %> <html> <script language="VB" runat=server> Sub Page_Load(Sender As Object, E As EventArgs) If Not (IsPostBack) Dim Values As New ArrayList Values.Add("1") Values.Add("2") Values.Add("3") Values.Add("4")

MyList.DataSource = Values MyList.DataBind() End If End Sub Private Sub Btn1_Click(Sender As Object, E As EventArgs) ' Do nothing for now. Just demonstrate that values ' where preserved.... End Sub </script> <body> <form method="POST" action="Repeater1.aspx" runat=server> <TemplateControlSamples:Repeater1VB id="MyList" runat=server> <ItemTemplate> Valor: <asp:textbox id="MyValue" Text="<%#Container.DataItem%>" runat=server/> <hr align=left width=200> </ItemTemplate> </TemplateControlSamples:Repeater1VB> <asp:button Text="Actualizar" OnClick="Btn1_Click" runat=server/> </form> </body> </html>

Desarrollar un control a partir de plantillas


El marco de trabajo de pginas ASP.NET permite a los programadores de controles crear controles que separen la interfaz de usuario de la lgica del control mediante el uso de plantillas. Los programadores de pginas pueden personalizar la presentacin del control proporcionando la interfaz de usuario en forma de parmetros entre etiquetas de plantilla. Los controles creados a partir de plantillas tienen una o ms propiedades de tipo System.Web.UI.ITemplate, como se indica en el siguiente ejemplo.

Public Property <TemplateContainer(GetType(Template1VB))> MessageTemplate As ITemplate

El atributo (mostrado arriba entre corchetes) especifica el tipo del control contenedor (control principal). La interfaz ITemplate tiene un mtodo, InstantiateIn, que crea una instancia de control dinmicamente. Se invoca en la propiedad ITemplate del mtodo CreateChildControls, como se muestra en el siguiente ejemplo.

Protected Overrides Sub CreateChildControls() If MessageTemplate <> Null Then MessageTemplate.InstantiateIn(Me) End if

... End Sub

En el siguiente ejemplo se muestra un control sencillo creado a partir de plantillas y una pgina ASP.NET que lo utiliza.

<%@ Register TagPrefix="TemplateControlSamples" Namespace="TemplateControlSamplesVB" Assembly="TemplateControlSamplesVB" %> <html> <script language="VB" runat=server> Public Sub Page_Load(Sender As Object, E As EventArgs) If Not (IsPostBack) Dim Values As New ArrayList Values.Add("1") Values.Add("2") Values.Add("3") Values.Add("4") MyList.DataSource = Values MyList.DataBind() End If End Sub Private Sub Btn1_Click(Sender As Object, E As EventArgs) Dim X As Long For X = 0 To MyList.Items.Count - 1 Dim MyValue As TextBox = MyList.Items(X).FindControl("MyValue") MyValue.Text = (Int32.Parse(MyValue.Text) + 1).ToString() Next End Sub </script> <body> <form method="POST" action="Repeater2.aspx" runat=server> <TemplateControlSamples:Repeater2VB id="MyList" runat=server> <ItemTemplate> Valor: <asp:textbox id="MyValue" Text="<%#Container.DataItem%>" runat=server/> <hr align=left width=200> </ItemTemplate> </TemplateControlSamples:Repeater2VB> <asp:button Text="Actualizar" OnClick="Btn1_Click" runat=server/>

</form> </body> </html>

Desarrollar un control enlazado a datos a partir de plantillas


En el siguiente ejemplo se muestra un uso ms complejo de plantillas para crear un control enlazado a datos. El control Repeater definido en este ejemplo es similar al control System.Web.UI.WebControls.Repeater.

<%@ Register TagPrefix="CustomParsingControlSamples" Namespace="CustomParsingControlSamples" Assembly="CustomParsingControlSamplesVB" %> <html> <body> <form method="POST" runat=server> <CustomParsingControlSamples:CustomParse1VB SelectedIndex="2" runat=server> <CustomParsingControlSamples:ItemVB Message="Uno" runat=server/> <CustomParsingControlSamples:ItemVB Message="Dos" runat=server/> <CustomParsingControlSamples:ItemVB Message="Tres" runat=server/> <CustomParsingControlSamples:ItemVB Message="Cuatro" runat=server/> </CustomParsingControlSamples:CustomParse1VB> </form> </body> </html>

En el siguiente ejemplo se modifica el ejemplo anterior de forma que un usuario de pginas pueda recorrer la coleccin Items durante la devolucin automtica al servidor para obtener valores de la misma.

<%@ Register TagPrefix="CustomParsingControlSamples" Namespace="CustomParsingControlSamples" Assembly="CustomParsingControlSamplesVB" %> <html> <body> <form method="POST" runat=server> <CustomParsingControlSamples:CustomParse2VB SelectedIndex="2" runat=server> <customitem Message="Uno"/> <customitem Message="Dos"/> <customitem Message="Tres"/> <customitem Message="Cuatro"/>

</CustomParsingControlSamples:CustomParse2VB> </form> </body> </html>

Reemplazar el anlisis de controles


Como se ha podido ver en Recuperar el contenido interno, si un control A tiene controles anidados dentro de las etiquetas de control en una pgina, el analizador de la pgina agrega instancias de esos controles a la coleccin Controles A. Para ello hay que invocar al mtodo AddSubParsedObject de A. Cada control hereda este mtodo de Control; la implementacin predeterminada slo inserta un control secundario en el rbol de jerarqua de controles. Un control puede reemplazar la lgica de anlisis predeterminada reemplazando el mtodo AddSubParsedObject. Hay que tener en cuenta que este anlisis est simplificado. En el siguiente ejemplo se proporcionan ms detalles. En el siguiente ejemplo se define un control personalizado, CustomParse1, que reemplaza la lgica de anlisis predeterminada. Cuando se analiza un control secundario de un tipo determinado, se agrega a una coleccin. La lgica de presentacin de CustomParse1 se basa en el nmero de elementos de la coleccin. Tambin se define en el ejemplo un control personalizado sencillo, Item.

<%@ Register TagPrefix="CustomParsingControlSamples" Namespace="CustomParsingControlSamples" Assembly="CustomParsingControlSamplesVB" %> <html> <body> <form method="POST" runat=server> <CustomParsingControlSamples:CustomParse1VB SelectedIndex="2" runat=server> <CustomParsingControlSamples:ItemVB Message="Uno" runat=server/> <CustomParsingControlSamples:ItemVB Message="Dos" runat=server/> <CustomParsingControlSamples:ItemVB Message="Tres" runat=server/> <CustomParsingControlSamples:ItemVB Message="Cuatro" runat=server/> </CustomParsingControlSamples:CustomParse1VB> </form> </body> </html>

Nota: si el control personalizado se deriva de WebControl, no tendr la lgica de anlisis descrita en el ejemplo, ya que WebControl estar marcado con ParseChildrenAttribute(ChildrenAsProperties = true), que resulta de una lgica de anlisis diferente. Para obtener ms informacin acerca de ParseChildrenAttribute, vea la documentacin del SDK. En el tema Recuperar el contenido interno tambin se describe este tema de forma ms detallada.

Definir un generador de controles personalizados


El marco de trabajo de pginas ASP.NET utiliza clases denominadas generadores de controles para procesar las declaraciones escritas entre etiquetas de control en una pgina. Todo control de formularios Web est asociado a una clase de generador de controles predeterminada, System.Web.UI.ControlBuilder. El generador de controles predeterminado agrega un control secundario a la coleccin Controls para cada control anidado que encuentre entre etiquetas de control. Adems, agrega controles Literal para texto entre etiquetas de control anidado. Es posible reemplazar este comportamiento predeterminado asociando una clase de generador de controles personalizados al control. Esto se hace aplicando al control un atributo de generador de controles, como se muestra en el siguiente ejemplo.

Public Class <ControlBuilderAttribute(GetType(CustomParse2ControlBuilderVB))> _ CustomParse2VB : Inherits Control

El elemento entre corchetes anterior es un atributo de Common Language Runtime que asocia la clase CustomParse2ControlBuilder al control CustomParse2. Es posible definir su propio generador de controles personalizado derivando de ControlBuilder y reemplazando sus mtodos. En el siguiente ejemplo se define un generador de controles personalizado que reemplaza el mtodo GetChildControlType heredado de ControlBuilder. Este mtodo devuelve el tipo de control que se va a agregar y se puede utilizar para decidir qu controles se van a agregar. En el ejemplo, el generador de controles slo agregar un control secundario si el nombre de la etiqueta es "customitem". El cdigo del control es muy similar al del ejemplo anterior, con la diferencia de que se agrega el atributo personalizado.

<%@ Register TagPrefix="CustomParsingControlSamples" Namespace="CustomParsingControlSamples" Assembly="CustomParsingControlSamplesVB" %> <html> <body> <form method="POST" runat=server> <CustomParsingControlSamples:CustomParse2VB SelectedIndex="2" runat=server> <customitem Message="Uno"/> <customitem Message="Dos"/> <customitem Message="Tres"/> <customitem Message="Cuatro"/> </CustomParsingControlSamples:CustomParse2VB> </form> </body> </html> Servicios Web de ASP.NET

Escibir un servicio Web sencillo


Es posible escribir un servicio Web de XML sencillo en pocos minutos mediante el uso de cualquier editor de texto. El servicio que se crear en esta seccin, MathService, presenta mtodos para sumar, restar, dividir y multiplicar dos nmeros. En la parte superior de la pgina, la directiva siguiente identifica el archivo como un servicio Web de XML adems de especificar el lenguaje para el servicio (C#, en este caso).

<%@ WebService Language="C#" Class="MathService" %>


En este mismo archivo, se define una clase que encapsula la funcionalidad del servicio. Esta clase debe ser pblica y opcionalmente puede heredar de la clase base WebService. Cada mtodo que se va a exponer del servicio presenta un indicador con un atributo [WebMethod] delante de l. Sin este atributo, no se expondr el mtodo del servicio. A veces, esto resulta til para ocultar los detalles de implementacin llamados por mtodos Web Service pblicos o en el caso en que la clase WebService se utilice tambin en aplicaciones locales (una aplicacin local puede utilizar cualquier clase pblica, pero slo las clases WebMethod se encuentran accesibles de forma remota como servicios Web de XML).

Imports System Imports System.Web.Services Public Class MathService : Inherits WebService

<WebMethod()> Public Function Add(a As Integer, b As Integer) As Integer Return(a + b) End Function End Class

Los archivos de servicios Web de XML se guardan con la extensin de archivo .asmx. Al igual que los archivos .aspx, estos archivos se compilan de forma automtica mediante el motor de tiempo de ejecucin de ASP.NET cuando se realiza una solicitud al servicio (las solicitudes posteriores se atienden mediante un objeto de tipo precompilado almacenado en cach). En el caso de MathService, se ha definido la clase WebService en el propio archivo .asmx. Hay que tener en cuenta que si un explorador solicita un archivo .asmx, el motor de tiempo de ejecucin de ASP.NET devuelve una pgina de ayuda del servicio Web de XML que describe el servicio Web en cuestin.

<%@ WebService Language="VB" Class="MathService" %> Imports System Imports System.Web.Services Public Class MathService : Inherits WebService <WebMethod()> Public Function Add(A As System.Single, B As System.Single) As System.Single Return A + B End Function <WebMethod()> Public Function Subtract(A As System.Single, B As System.Single) As System.Single Return A - B End Function <WebMethod()> Public Function Multiply(A As System.Single, B As System.Single) As System.Single Return A * B End Function <WebMethod()> Public Function Divide(A As System.Single, B As System.Single) As System.Single If B = 0 Return -1 End If Return Convert.ToSingle(A / B) End Function End Class

Servicios Web de XML precompilados


Si se tiene una clase precompilada que se desea exponer como un servicio Web de XML (y esta clase expone mtodos marcados con el atributo [WebMethod]), es posible crear un archivo .asmx con slo la siguiente lnea.

<%@ WebService Class="MyWebApplication.MyWebService" %> MyWebApplication.MyWebService define la clase WebService y est incluido en el subdirectorio \bin de la aplicacin ASP.NET.

Consumir un servicio Web de XML desde una aplicacin cliente


Para utilizar este servicio, hay que hacer uso de la herramienta de lnea de comandos del lenguaje de descripcin de servicios Web (Web Services Description Language), WSDL.exe, incluida en el kit de desarrollo de software (SDK) con el fin de crear una clase proxy que sea similar a la clase definida en el archivo .asmx. (Solamente contendr los mtodos WebMethod). A continuacin, hay que compilar el cdigo con esta clase proxy incluida. WSDL.exe acepta diversas opciones de lnea de comandos; sin embargo, para crear un proxy slo se requiere una opcin: el identificador URI al WSDL. En este ejemplo, se pasan algunas opciones adicionales que especifican el lenguaje preferido, el espacio de nombres y la ubicacin

de salida para el proxy. Tambin es posible compilar con un archivo WSDL guardado anteriormente en lugar del identificador URI al propio servicio:

wsdl.exe /l:CS /n:MathService /out:MathService.cs MathService.wsdl


Una vez que existe la clase proxy, es posible crear objetos basados en ella. Cada llamada de mtodo realizada con el objeto pasa seguidamente al identificador URI del servicio Web de XML (normalmente como una solicitud SOAP).

<%@ Import Namespace="MathServiceVB" %> <html> <script language="VB" runat="server"> Dim Op1 As Single = 0 Dim Op2 As Single = 0 Public Sub Submit_Click(Sender As Object, E As EventArgs) Try Op1 = Single.Parse(Operand1.Text) Op2 = Single.Parse(Operand2.Text) Catch Exp As Exception ' Ignored End Try Dim Service As MathServiceVB.MathService = New MathServiceVB.MathService() Select (CType(sender,Control).ID) Case "Add" : Result.Text = "<b>Resultado</b> = " & Service.Add(Op1, Op2).ToString() Case "Subtract" : Result.Text = "<b>Resultado</b> = " & Service.Subtract(Op1, Op2).ToString() Case "Multiply" : Result.Text = "<b>Resultado</b> = " & Service.Multiply(Op1, Op2).ToString() Case "Divide" : Result.Text = "<b>Resultado</b> = " & Service.Divide(Op1, Op2).ToString() End Select End Sub </script> <body style="font: 10pt verdana"> <h4>Utilizar un servicio matemtico simple </h4> <form runat="server"> <div style="padding:15,15,15,15;background-color:beige;width:330;border-color:black;border-width:1;borderstyle:solid"> Operando 1: <br><asp:TextBox id="Operand1" Text="15" runat="server"/><br> Operando 2: <br><asp:TextBox id="Operand2" Text="5" runat="server"/><p> <input type="submit" id="Add" value="Agregar" OnServerClick="Submit_Click" runat="server"> <input type="submit" id="Subtract" value="Restar" OnServerClick="Submit_Click" runat="server"> <input type="submit" id="Multiply" value="Multiplicar" OnServerClick="Submit_Click" runat="server"> <input type="submit" id="Divide" value="Dividir" OnServerClick="Submit_Click" runat="server">

<p> <asp:Label id="Result" runat="server"/> </div> </form> </body> </html>

Clculo de referencias de servicios Web de XML


En esta seccin se muestra que se pueden pasar varios tipos de datos a mtodos de servicios Web y devolverlos desde los mismos. Dado que la implementacin de servicios Web de XML se genera en la parte superior de la arquitectura de serializacin de XML, admite un importante nmero de tipos de datos. En la siguiente tabla se enumeran los tipos de datos admitidos para mtodos de servicios Web

cuando se utiliza el protocolo SOAP (por ejemplo, al utilizar el proxy generado por la herramienta del Lenguaje de descripcin de servicios Web, WSDL.exe).

Tipo Tipos primitivos

Descripcin Tipos primitivos estndar. En la lista completa de tipos primitivos admitidos se encuentran String, Char, Byte, Boolean, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, Double, Guid, Decimal, DateTime (como timeInstant de XML), DateTime (como fecha de XML), DateTime (como hora de XML) y XmlQualifiedName (como QName de XML). Tipos de enumeracin, como por ejemplo, "public enum color { red=1, blue=2 }" Matrices de los tipos primitivos anteriores, como string[] e int[] Tipos de clases y estructuras con campos o propiedades pblicas. Se pueden serializar los campos y propiedades pblicos. Matrices de los tipos anteriores. Tipos de DataSet de ADO.NET (vea la siguiente seccin para obtener un ejemplo). Tambin pueden aparecer DataSet como campos en estructuras y clases. Nota: Microsoft Visual Studio.NET y la utilidad del SDK XSD.EXE son compatibles para "establecer tipos inflexiblemente" en DataSet. Estas herramientas generan una clase que se hereda de DataSet para producir DataSet1 al agregar varios mtodos, propiedades, etc. que son especficos para un esquema XML concreto. Si se pasa DataSet, los servicios Web de XML siempre transmiten el esquema junto con los datos (de forma que sabe qu tablas y columnas se estn pasando) y los tipos correspondientes (por ejemplo, int, string). Si se pasa una subclase de DataSet (por ejemplo, DataSet1), los servicios Web de XML suponen que se agregan tablas o columnas al constructor, as como que esas tablas o columnas representan el esquema.

Tipos Enum Matrices de primitivos, Enums Clases y estructuras Matrices de clases (estructuras) DataSet

Matrices de DataSet XmlNode

Matrices del tipo anterior. XmlNode consiste en una representacin en memoria de un fragmento de XML (como un modelo ligero de objeto de documento de XML). Por ejemplo, "<comment>This is<b>pretty</b> neat</comment>" podra almacenarse en un tipo XmlNode. Se pueden pasar tipos XmlNode como parmetros y se agregan al resto de XML que se est pasando al servicio Web de XML (los otros parmetros) de forma compatible con SOAP. Lo mismo sirve para los valores devueltos. Esto permite pasar o devolver XML cuya estructura cambia de llamada en llamada o donde no se pueden conocer todos los tipos que se estn pasando. Tambin pueden aparecer tipos XmlNode como campos en estructuras y clases. Matrices del tipo anterior.

Matrices de XmlNode Valores devueltos:

Tanto si se llama a un servicio Web de XML mediante SOAP o HTTP GET/POST, todos los tipos anteriores son compatibles con los valores devueltos. Parmetros: Tanto los parmetros por valor, como por referencia (in/out) son compatibles si se utiliza el protocolo SOAP. Los parmetros por referencia pueden enviar el valor en dos direcciones: hasta el servidor y de vuelta al cliente. Cuando se analizan parmetros de entrada a un servicio

Web de XML mediante HTTP GET/POST, slo se admite un conjunto limitado de tipos de datos que deben ser parmetros por valor. A continuacin se enumeran los tipos compatibles con los parmetros GET/POST de HTTP: Tipo Tipos primitivos (limitados) Descripcin La mayora de los tipos primitivos estndar. La lista completa de tipos primitivos admitidos comprende los tipos Int32, String, Int16, Int64, Boolean, Single, Double, Decimal, DateTime, UInt16, UInt32, UInt64 y Currency. Desde el punto de vista del cliente, todos estos tipos se transforman en cadenas. Tipos de enumeracin, como por ejemplo, "public enum color { red=1, blue=2 }". Desde el punto de vista del cliente, los tipos enum se convierten en clases con una cadena const esttica para cada valor. Matrices de los tipos primitivos anteriores, como string[] e int[]

Tipos Enum

Matrices de primitivos, Enums

En el siguiente ejemplo se muestra el uso de los tipos que se acaban de enumerar, mediante un proxy SOAP generado desde WSDL.exe. Debe tenerse en cuenta que, como hay ms de una clase pblica definida en el archivo .asmx file, se debe especificar cul se tratar como clase WebService mediante el atributo "Class" de la directiva WebService:

<%@ WebService Language="C#" Class="DataTypes" %> <%@ WebService Language="VB" Class="DataTypes" %> Imports System Imports System.Web.Services Namespace DataTypesVB.Enumerations Public Enum Mode EOn = 1 EOff = 2 End Enum Public Class Order Public OrderID As Integer Public Price As Double End Class End Namespace Public Class DataTypes : Inherits WebService <WebMethod()> Public Function SayHello() As String Return "Hola a todos" End Function <WebMethod()> Public Function SayHelloName(Name As String) As String Return "Hola" & Name End Function <WebMethod()> Public Function GetIntArray() As Integer() Dim I As Integer Dim A(4) As Integer For I = 0 to 4 A(I) = I*10 Next Return A End Function <WebMethod()> Public Function GetMode() As DataTypesVB.Enumerations.Mode

Return DataTypesVB.Enumerations.Mode.EOff End Function <WebMethod()> Public Function GetOrder() As DataTypesVB.Enumerations.Order Dim MyOrder As New DataTypesVB.Enumerations.Order MyOrder.Price=34.5 MyOrder.OrderID = 323232 Return MyOrder End Function <WebMethod()> Public Function GetOrders() As DataTypesVB.Enumerations.Order() Dim MyOrder(2) As DataTypesVB.Enumerations.Order MyOrder(0) = New DataTypesVB.Enumerations.Order() MyOrder(0).Price=34.5 MyOrder(0).OrderID = 323232 MyOrder(1) = New DataTypesVB.Enumerations.Order() MyOrder(1).Price=99.4 MyOrder(1).OrderID = 645645 Return MyOrder End Function End Class

El mtodo SayHello muestra cmo devolver una cadena desde un servicio. El mtodo SayHelloName devuelve una cadena y tambin toma una cadena como parmetro. El mtodo GetIntArray muestra cmo devolver una matriz de enteros. El mtodo GetMode devuelve un valor enum. El mtodo GetOrder devuelve una clase (que, en este caso, es casi lo mismo que una estructura). El mtodo GetOrders devuelve una matriz de objetos Order.

Mediante la herramienta de generacin del proxy de la lnea de comandos WSDL.exe, el clculo de referencias de estos tipos de datos resulta transparente para la aplicacin del cliente consumidor. A continuacin, se incluye una aplicacin del cliente de muestra para el anterior servicio Web de XML:

<%@ Import Namespace="DataTypesVB" %> <html> <style> div { font: 8pt verdana; background-color:cccccc; border-color:black; border-width:1; border-style:solid; padding:10,10,10,10; } </style> <script language="VB" runat="server">

Public Sub Page_Load(Sender As Object, E As EventArgs) Dim D As DataTypesVB.DataTypes = New DataTypesVB.DataTypes() Message1.InnerHtml = D.SayHello() Message1.InnerHtml = Message1.InnerHtml & D.SayHelloName("Bob") Message3.InnerHtml = Message3.InnerHtml & D.GetMode() Dim MyIntArray As Integer() = D.GetIntArray() Dim MyString As String = "Contenido de la matriz:<BR>" Dim I As Integer For I = 0 To MyIntArray.Length - 1 MyString = MyString & MyIntArray(I) & "<BR>" Next Message2.InnerHtml = Message2.InnerHtml & MyString Dim MyOrder As Order = D.GetOrder() Message4.InnerHtml = Message4.InnerHtml & "<BR>Id. de pedido: " & MyOrder.OrderID Message4.InnerHtml = Message4.InnerHtml & "<BR>Precio: " & MyOrder.Price Dim MyOrders As Order() = D.GetOrders() For I = 0 To myOrders.Length - 1 If i > 0 Then Message5.InnerHtml &= "<BR>" Message5.InnerHtml &= "<BR>N de pedido: " & i Message5.InnerHtml &= "<BR>Id. de pedido: " & myOrders(0).OrderID Message5.InnerHtml &= "<BR>Precio: " & myOrders(0).Price Next End Sub </script> <body style="font: 10pt verdana"> <H4>Utilizar tipos de datos con servicios Web</H4> <h5>Mtodos que devuelven tipos primitivos (cadena): </h5> <div id="Message1" runat="server"/> <h5>Mtodos que devuelven una matriz de tipos primitivos (enteros): </h5> <div id="Message2" runat="server"/> <h5>Mtodo que devuelve una enumeracin: </h5> <div id="Message3" runat="server"/> <h5>Mtodo que devuelve una clase o estructura: </h5> <div id="Message4" runat="server"/> <h5>Mtodo que devuelve una matriz de clases o estructuras: </h5> <div id="Message5" runat="server"/> </body> </html>

Utilizar datos en servicios Web de XML


En este ejemplo se muestra la forma de devolver conjuntos de datos (objetos DataSet), que representan una nueva y eficaz manera de representar datos desconectados basada en XML, desde un mtodo de servicio Web. Esto constituye un uso muy eficaz de los servicios Web de XML, ya que los objetos DataSet pueden almacenar informacin y relaciones complejas en una estructura inteligente. Al exponer conjuntos de datos a travs de un servicio, es posible limitar las conexiones de base de datos que se establecen con el servidor de datos.

El mtodo GetTitleAuthors establece una conexin con una base de datos y emite dos instrucciones SQL: una que devuelve una lista de autores y otra que devuelve una lista de ttulos de libros. Coloca los dos conjuntos de resultados en un nico conjunto de datos denominado ds y despus devuelve el objeto DataSet en cuestin.

que utiliza un conjunto de datos como parmetro y devuelve un nmero entero que representa el nmero de filas recibidas en la tabla "Authors" del conjunto de datos. Aunque la implementacin de este mtodo es un poco simplista, tambin se podran combinar de forma inteligente los datos transferidos con el servidor de la base de datos.
El mtodo PutTitleAuthors ilustra un mtodo de servicio Web

<%@ WebService Language="VB" Class="DataService" %> Imports System Imports System.Data Imports System.Data.SqlClient Imports System.Web.Services Public Class DataService : Inherits WebService <WebMethod()> Public Function GetTitleAuthors() As DataSet Dim MyConnection As SqlConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") Dim MyCommand1 As SqlDataAdapter = New SqlDataAdapter("select * from Authors", MyConnection) Dim MyCommand2 As SqlDataAdapter = New SqlDataAdapter("select * from Titles", MyConnection) Dim DS As New DataSet MyCommand1.Fill(DS, "Authors") MyCommand2.Fill(ds, "Titles") Return DS End Function <WebMethod()> Public Function PutTitleAuthors(DS As DataSet) As Integer Return DS.Tables(0).Rows.Count End Function End Class
La aplicacin cliente para este servicio Web de XML llama a GetTitleAuthors y enlaza la tabla Authors con un control DataGrid, de la manera ilustrada en los ejemplos anteriores. Para ilustrar el mtodo PutTitleAuthors, el cliente quita tres filas de datos del conjunto de datos antes de llamar a este mtodo y muestra el nmero de filas recibidas por el servicio.

<%@ Import Namespace="DataServiceVB" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Protected Sub Page_Load(Src As Object, E As EventArgs) Dim D As DataServiceVB.DataService = New DataServiceVB.DataService() Dim MyData As DataSet = D.GetTitleAuthors() Authors_DataGrid.DataSource=MyData.Tables("Authors").DefaultView Authors_DataGrid.DataBind() Message.InnerHtml = "Nmero de filas: " & MyData.Tables("Authors").Rows.Count.ToString()

End Sub Protected Sub Submit_DataSet(Src As Object, E As EventArgs) Dim D As DataServiceVB.DataService = New DataServiceVB.DataService() Dim MyData As DataSet = D.GetTitleAuthors() 'Remove three rows from the Authors table MyData.Tables("Authors").Rows.RemoveAt(0) MyData.Tables("Authors").Rows.RemoveAt(1) MyData.Tables("Authors").Rows.RemoveAt(2) Dim RowCount As Integer = D.PutTitleAuthors(MyData) Authors_DataGrid.DataSource=MyData.Tables("Authors").DefaultView Authors_DataGrid.DataBind() Message.InnerHtml = "Nmero modificado de filas: " & RowCount.ToString() End Sub </script> <body style="font: 10pt verdana"> <h4>Utilizar acceso a datos con servicios Web</h4> <form runat="server"> <input type="submit" OnServerclick="Submit_DataSet" value="Quitar tres filas del conjunto de datos" runat="server"/> <p> <span id="Message" runat="server"/> <p> <ASP:DataGrid id="Authors_DataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" EnableViewState="false" /> </form> </body> </html>

Utilizar objetos y elementos intrnsecos


En este ejemplo se ilustra la forma de tener acceso a los elementos intrnsecos de ASP.NET, como Session y Application. Tambin se muestra la forma de desactivar el objeto Session mediante WebMethod. El primer mtodo del archivo .asmx de ejemplo, UpdateHitCounter, tiene acceso al objeto Session y agrega e incrementa en una unidad el valor de "HitCounter". Despus devuelve este valor en forma de cadena. El segundo mtodo, UpdateAppCounter, hace lo mismo, pero con el objeto Application. Hay que tener en cuenta lo siguiente:

<WebMethod(EnableSession:=true)>

El estado de sesin de los servicios Web de XML est deshabilitado de forma predeterminada y hay que utilizar una propiedad de atributo especial para habilitar objetos Session. Sin embargo, este objeto no necesita objetos Session, ya que slo utiliza el objeto Application.

<%@ WebService Language="VB" Class="SessionService1" %> Imports System Imports System.Web.Services Public Class SessionService1 : Inherits WebService <WebMethod(EnableSession:=true)> Public Function UpdateHitCounter() As String If Session("HitCounter") Is Nothing Session("HitCounter") = 1 Else Session("HitCounter") = Cint(Session("HitCounter")) + 1 End If Return "Ha tenido acceso a este servicio " & Session("HitCounter").ToString() & " veces." End Function <WebMethod(EnableSession:=false)> Public Function UpdateAppCounter() As String If Application("HitCounter") Is Nothing Application("HitCounter") = 1 Else Application("HitCounter") = CInt(Application("HitCounter")) + 1 End If Return "Se obtuvo acceso al servicio " & Application("HitCounter").ToString() & " veces." End Function End Class

Cuando se tiene acceso al cliente proxy, ste contiene una coleccin de cookies. Esta coleccin se utiliza para aceptar y devolver la cookie APSESSIONID que utiliza ASP.NET para hacer un seguimiento de las sesiones. Esto es lo que permite al cliente recibir distintas respuestas al mtodo Hit de Session.

<%@ Import Namespace="System.Net" %> <%@ Import Namespace="SessionService1VB" %> <html> <style> div { font: 8pt verdana; background-color:cccccc; border-color:black; border-width:1; border-style:solid; padding:10,10,10,10; }

</style> <script language="VB" runat="server"> Public Sub Page_Load(Sender As Object, E As EventArgs) Dim S As SessionService1VB.SessionService1 = New SessionService1VB.SessionService1() S.CookieContainer = new CookieContainer() Message1.InnerHtml = S.UpdateHitCounter() & "<BR>" & S.UpdateHitCounter() & "<BR>" + S.UpdateHitCounter() Message2.InnerHtml = S.UpdateAppCounter() & "<BR>" & S.UpdateAppCounter() & "<BR>" + S.UpdateAppCounter() End Sub </script> <body style="font: 10pt verdana"> <H4>Utilizar intrnsecos con servicios Web</H4> <h5>Resultados de UpdateHitCounter: </h5> <div id="Message1" runat="server"/> <h5>Resultados de UpdateAppCounter: </h5> <div id="Message2" runat="server"/> </body> </html>

Comportamiento WebService
Microsoft lanz recientemente un comportamiento DHTML con habilitacin SOAP nuevo para Microsoft Internet Explorer 5.0 y versiones posteriores. El nuevo comportamiento WebService permite a la secuencia de comandos en el cliente invocar mtodos remotos expuestos por servicios Web .NET XML de Microsoft u otros servidores Web que admiten el protocolo SOAP (Simple Object Access Protocol). El comportamiento WebService se implementa con un archivo HTML Components (HTC) como un comportamiento asociado, por lo que puede utilizarse en Internet Explorer. La finalidad del comportamiento WebService es proporcionar una manera sencilla de utilizar y aplicar SOAP, sin requerir un conocimiento profundo de su implementacin. El comportamiento WebService admite el uso de una amplia variedad de tipos de datos, incluidos tipos de datos SOAP intrnsecos, matrices y datos XML (Lenguaje de marcado extensible, Extensible Markup Language). Este componente flexible permite a Internet Explorer recuperar informacin de servicios Web de XML y actualizar una pgina de forma dinmica mediante el uso de DHTML y secuencias de comandos, sin requerir el desplazamiento ni una actualizacin de pgina completa. La siguiente generacin de la infraestructura y las herramientas de programacin .NET, incluido Visual Studio.NET, .NET Framework y servidores .NET Enterprise, est diseada para la programacin de aplicaciones segn el modelo de servicios Web de XML. El comportamiento WebService es especialmente significativo ya que permite a Internet Explorer utilizar estos servicios Web de XML de prxima generacin. El sitio de Microsoft Developer Network (MSDN) proporciona la documentacin siguiente. Informacin general del comportamiento WebService http://msdn.microsoft.com/workshop/author/webservice/overview.asp Uso del comportamiento WebService http://msdn.microsoft.com/workshop/author/webservice/using.asp Comportamiento WebService http://msdn.microsoft.com/workshop/author/webservice/webservice.asp

Hacer coincidir modelos de texto HTML


Este ejemplo muestra cmo crear un proxy cliente para cualquier URL que proporcione texto. En vez de crear el archivo .asmx, se puede crear un archivo WSDL que describa la pgina HTML (o XML o cualquier otro formato no binario) actual. El archivo WSDL puede utilizarse para generar un proxy cliente mediante la herramienta de lnea de comandos WSDL.exe que utilizar RegEx para analizar la pgina HTML especificada y extraer los valores.

Esto se puede realizar agregando etiquetas <Match> a la seccin Response del archivo WSDL. Estas etiquetas utilizan un atributo denominado pattern, que es la expresin regular que se corresponde con la parte de texto de la pgina que constituye el valor de la propiedad. (Nota: la propiedad de la clase proxy es de slo lectura). El cdigo consumidor puede entonces crear el objeto, obtener acceso al objeto Matches devuelto por el nombre convertido en funcin que aparece en el archivo WSDL y conseguir acceso a cualquier parte del cdigo HTML como una propiedad. No es necesario ningn conocimiento de WSDL, expresiones regulares, ni HTML para poder utilizar la clase proxy. sta se comporta como cualquier otra clase de .NET Framework.

<?xml version="1.0"?> <definitions xmlns:s="http://www.w3.org/1999/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <s:schema targetNamespace="http://tempuri.org/" attributeFormDefault="qualified" elementFormDefault="qualified"> <s:element name="TestHeaders"> <s:complexType derivedBy="restriction"/> </s:element> <s:element name="TestHeadersResult"> <s:complexType derivedBy="restriction"> <s:all> <s:element name="result" type="s:string" nullable="true"/> </s:all> </s:complexType> </s:element> <s:element name="string" type="s:string" nullable="true"/> </s:schema> </types> <message name="TestHeadersHttpGetIn"/> <message name="TestHeadersHttpGetOut"> <part name="Body" element="s0:string"/> </message> <portType name="TestItHttpGet"> <operation name="TestHeaders"> <input message="s0:TestHeadersHttpGetIn"/> <output message="s0:TestHeadersHttpGetOut"/> </operation> </portType> <binding name="TestItHttpGet" type="s0:TestItHttpGet"> <http:binding verb="GET"/> <operation name="TestHeaders"> <http:operation location="/QuickStart/aspplus/samples/services/TextMatching/VB/MatchServer.html"/> <input> <http:urlEncoded/> </input> <output> <text xmlns="http://microsoft.com/wsdl/mime/textMatching/"> <match name='Title' pattern='TITLE&gt;(.*?)&lt;'/> <match name='H1' pattern='H1&gt;(.*?)&lt;'/> </text> </output> </operation> </binding> <service name="TestIt"> <port name="TestItHttpGet" binding="s0:TestItHttpGet"> <http:address location="http://localhost" /> </port> </service>

</definitions>

Informacin general de una aplicacin


En qu consiste una aplicacin ASP.NET?
ASP.NET define una aplicacin como el conjunto de todos los archivos, pginas, controladores, mdulos y cdigo ejecutable que se pueden invocar o ejecutar dentro del mbito de un determinado directorio virtual (y sus subdirectorios) en un servidor de aplicaciones Web. Por ejemplo, una aplicacin de "pedido" podra publicarse dentro del directorio virtual "/pedido" de un servidor Web. Para IIS, el directorio virtual se puede configurar en el Administrador de servicios de Internet y contiene todos los subdirectorios, a menos que los propios subdirectorios sean directorios virtuales. Cada aplicacin ASP.NET Framework de un servidor Web se ejecuta dentro de un dominio nico de aplicaciones ejecutables de .NET Framework, lo que garantiza el aislamiento de clases (no se producen conflictos de nombres o versiones), el uso seguro de recursos (se impide el acceso a determinados equipos o recursos de red) y el aislamiento de variables estticas. ASP.NET mantiene una agrupacin de instancias HttpApplication durante el perodo de duracin de una aplicacin Web. ASP.NET asigna automticamente una de estas instancias para procesar cada solicitud HTTP entrante recibida por la aplicacin. La instancia HttpApplication asignada en particular es responsable del proceso de la solicitud a lo largo de todo su perodo de duracin y slo se puede volver a utilizar despus de que la solicitud se haya completado. Esto significa que el cdigo de usuario incluido en la instancia HttpApplication no necesita ser reentrante.

Crear una aplicacin


Para crear una aplicacin ASP.NET Framework, se puede utilizar un directorio virtual existente o crear uno nuevo. Por ejemplo, si Windows 2000 Server se instal con IIS, probablemente existir un directorio C:\\InetPub\\WWWRoot. IIS se puede configurar mediante el Administrador de servicios de Internet, que se encuentra en Inicio -> Programas -> Herramientas administrativas. Haga clic con el botn secundario del mouse (ratn) en un directorio existente y elija Nuevo (para crear un nuevo directorio virtual) o Propiedades (para convertir un directorio normal existente). Cuando se coloca una simple pgina .aspx, como la siguiente, en el directorio virtual, y se obtiene acceso a ella con el explorador, se desencadena el proceso de creacin de la aplicacin ASP.NET.

<%@Page Language="VB"%> <html> <body> <h1>hello world, <% Response.Write(DateTime.Now.ToString()) %></h1> </body> </html>

Ahora, ya se puede agregar el cdigo apropiado para utilizar el objeto Application (por ejemplo, para almacenar objetos con mbito de aplicacin). Mediante la creacin un archivo global.asax, tambin se pueden definir diversos controladores de eventos (por ejemplo, para el evento Application_Start).

Duracin de una aplicacin


Una aplicacin ASP.NET Framework se crea la primera vez que se realiza una solicitud al servidor; antes de ello, no se ejecuta ningn cdigo ASP.NET. Cuando se realiza la primera solicitud, se crea una agrupacin de instancias HttpApplication y se provoca el evento Application_Start. Las instancias HttpApplication procesan esta solicitud y las siguientes hasta que la ltima instancia termina y se provoca el evento Application_End. Observe que los mtodos Init y Dispose de HttpApplication se invocan por cada instancia y, de este modo, pueden utilizarse varias veces entre Application_Start y Application_End. Slo se comparten estos eventos entre todas las instancias de HttpApplication en una aplicacin ASP.NET.

Nota sobre subprocesos mltiples


Si se utilizan objetos con mbito de aplicacin, se debera tener en cuenta que ASP.NET procesa las solicitudes de forma concurrente y que pueden ser varios los subprocesos que obtengan acceso al objeto Application. Por lo tanto, el siguiente cdigo es peligroso y podra no producir el resultado esperado si diferentes clientes solicitan la pgina reiteradamente al mismo tiempo.

<% Application("counter") = CType(Application("counter") + 1, Int32) %>

Para conseguir que este cdigo sea seguro durante la ejecucin de subprocesos, hay que serializar el acceso al objeto Application mediante los mtodos Lock y UnLock. Sin embargo, al hacerlo se produce una efecto de merma considerable en el rendimiento:

<% Application.Lock() Application("counter") = CType(Application("counter") + 1, Int32) Application.UnLock() %>

Otra solucin consiste en hacer que el objeto almacenado con un mbito de aplicacin sea seguro para la ejecucin de subprocesos. Por ejemplo, observe que las clases de coleccin del espacio de nombres System.Collections no son seguras para la ejecucin de subprocesos por razones de rendimiento.

Resumen de la seccin
1. Las aplicaciones ASP.NET Framework se componen de todo aquello que se encuentra bajo un directorio virtual del servidor Web. 2. Una aplicacin ASP.NET Framework se crea agregando archivos a un directorio virtual del servidor Web.

3.

La duracin de una aplicacin ASP.NET Framework viene marcada por los eventos Application_Start y Application_End. 4. El acceso a los objetos con mbito de aplicacin debe ser seguro para el acceso a mltiples subprocesos.

Utilizar el archivo Global.asax


Archivo Global.asax
Adems de escribir cdigo para interfaces de usuario, los programadores tambin pueden agregar lgica del nivel de aplicacin y cdigo de control de eventos a sus aplicaciones Web. Este cdigo no se encarga de generar interfaces de usuario y no se invoca normalmente en respuesta a solicitudes de pginas individuales. En vez de ello, se encarga de procesar eventos de la aplicacin de nivel superior, tales como Application_Start, Application_End, Session_Start, Session_End, etc. Los programadores crean esta lgica mediante un archivo Global.asax ubicado en la raz del rbol de directorios virtuales de una aplicacin Web. ASP.NET analiza y compila automticamente este archivo para producir una clase dinmica de .NET Framework, la cual extiende la clase base HttpApplication (la primera vez que se activa o se solicita cualquier recurso o URL dentro del espacio de nombres de la aplicacin). ASP.NET analiza y compila dinmicamente el archivo Global.asax para producir una clase de .NET Framework la primera vez que se activa o se solicita cualquier recurso o URL dentro del espacio de nombres de la aplicacin. El archivo Global.asax est configurado para rechazar automticamente cualquier solicitud de URL directa de modo que los usuarios externos no puedan descargar o ver el cdigo interno.

Eventos cuyo mbito es una sesin o una aplicacin


Los programadores pueden definir controladores para eventos de la clase base HttpApplication creando mtodos en el archivo Global.asax que se ajusten al modelo de nomenclatura "NombreDeEventoDeLaAplicacin(FirmaDeArgumentosDelEvento)". Por ejemplo:

<script language="VB" runat="server"> Sub Application_Start(Sender As Object, E As EventArgs) ' Application startup code goes here End Sub </script>

Si el cdigo de control de eventos necesita importar espacios de nombres adicionales, se puede utilizar la directiva @ import en una pgina .aspx, como se indica a continuacin:

<%@ Import Namespace="System.Text" %>


El siguiente ejemplo ilustra el perodo de vida de Application, Session y Request.

<script language="VB" runat="server"> Sub Application_Start(Sender As Object, E As EventArgs) ' Do application startup code here End Sub Sub Application_End(Sender As Object, E As EventArgs) ' Clean up application resources here End Sub Sub Session_Start(Sender As Object, E As EventArgs) Response.Write("La sesin se est iniciando...<br>") End Sub Sub Session_End(Sender As Object, E As EventArgs) ' Clean up session resources here End Sub Sub Application_BeginRequest(Sender As Object, E As EventArgs) Response.Write("<h3><font face='Verdana'>Usar el archivo Global.asax</font></h3>") Response.Write("La solicitud se est iniciando...<br>") End Sub Sub Application_EndRequest(Sender As Object, E As EventArgs) Response.Write("La solicitud est terminando...<br>") End Sub Sub Application_Error(Sender As Object, E As EventArgs) Context.ClearError() Response.Redirect("errorpage.htm") End Sub </script>

La primera vez que se abre la pgina, se provoca el evento Start para la aplicacin y la sesin:

Sub Application_Start(Sender As Object, E As EventArgs) ' Application startup code goes here End Sub Sub Session_Start(Sender As Object, E As EventArgs) Response.Write("Session is Starting...<br>") Session.Timeout = 1 End Sub

Los eventos BeginRequest y EndRequest se provocan en cada solicitud. Cuando la pgina se actualiza, slo aparecen mensajes de BeginRequest, EndRequest y el mtodo Page_Load. Observe que, al abandonar la sesin actual (hacer clic en el botn "Finalizar esta sesin"), se crea una nueva sesin y se provoca de nuevo el evento Session_Start.

Objetos cuyo mbito es una sesin o una aplicacin


Los objetos estticos, las clases de .NET Framework y los componentes COM se pueden definir en el archivo Global.asax mediante la etiqueta object. El mbito puede ser appinstance, session o application. El mbito appinstance denota que el objeto es especfico para una instancia de HttpApplication y no est compartido.

<object id="id" runat="server" class=".NET Framework class Name" scope="appinstance"/> <object id="id" runat="server" progid="COM ProgID" scope="session"/> <object id="id" runat="server" classid="COM ClassID" scope="application"/>

Resumen de la seccin
1. En las aplicaciones ASP.NET Framework se pueden definir controladores de eventos cuyo mbito sea toda la aplicacin o toda la sesin, en el archivo Global.asax. 2. En las aplicaciones ASP.NET Framework se pueden definir objetos cuyo mbito sea toda la aplicacin o toda la sesin, en el archivo Global.asax.

Administrar el estado de las aplicaciones


Utilizar el estado de las aplicaciones
En este ejemplo se ilustra el uso del estado de una aplicacin para leer un conjunto de datos en Application_Start.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.IO" %> <script language="VB" runat="server"> Sub Application_Start(Sender As Object, E As EventArgs) Dim DS As New DataSet Dim FS As FileStream FS = New FileStream(Server.MapPath("schemadata.xml"),FileMode.Open,FileAccess.Read) Dim Reader As StreamReader Reader = New StreamReader(FS) DS.ReadXml(Reader) FS.Close() Dim View As DataView View = New DataView(ds.Tables(0)) Application("Source") = View End Sub </script>

Ya que distintos subprocesos pueden tener acceso a una aplicacin y a todos los objetos que contiene dicha aplicacin de forma simultnea, es mejor almacenar con mbito de aplicacin nicamente los datos que se modifican con poca frecuencia. Idealmente, los objetos se inicializan en el evento Application_Start y los accesos posteriores son de slo lectura. En el siguiente ejemplo se lee un archivo en Application_Start (definido en el archivo Global.asax) y el contenido se almacena en un objeto DataView en el estado de la aplicacin.

Sub Application_Start() Dim ds As New DataSet() Dim fs As New FileStream(Server.MapPath("schemadata.xml"),FileMode.Open,FileAccess.Read) Dim reader As New StreamReader(fs) ds.ReadXml(reader) fs.Close() Dim view As New DataView (ds.Tables(0)) Application("Source") = view

End Sub

En el mtodo Page_Load se recupera el objeto DataView y despus se utiliza para llenar un objeto DataGrid:

Sub Page_Load(sender As Object, e As EventArgs) Dim Source As New DataView = CType(Application("Source"), DataView) ... MyDataGrid.DataSource = Source ... End Sub

La ventaja de esta solucin es que el precio de obtener los datos slo lo paga la primera solicitud. Las siguientes solicitudes utilizarn el objeto DataView existente. Como los datos no se modifican nunca despus de la inicializacin, no es necesaria la serializacin del acceso.

Utilizar el estado de las sesiones


En el ejemplo siguiente se ilustra el uso del estado de una sesin para almacenar preferencias de usuario voltiles.

<script language="VB" runat="server"> Sub Session_Start(Sender As Object, E As EventArgs) Session("BackColor") = "beige" Session("ForeColor") = "black" Session("LinkColor") = "blue" Session("FontSize") = "8pt" Session("FontName") = "verdana" End Sub </script>

Es posible almacenar los datos con mbito de sesin a fin de proporcionar datos individuales a un usuario durante una sesin. En el ejemplo siguiente se inicializan los valores de preferencias de usuario en el evento Session_Start del archivo Global.asax.

Sub Session_Start() Session("BackColor") = "beige" ... End Sub

En la siguiente pgina de personalizacin, se modifican los valores de las preferencias de usuario en el controlador de eventos Submit_Click con la informacin aportada por el usuario.

Protected Sub Submit_Click(sender As Object, e As EventArgs) Session("BackColor") = BackColor.Value ... Response.Redirect(State("Referer").ToString()) End Sub

Los valores individuales se obtienen mediante el mtodo GetStyle:

Protected GetStyle(key As String) As String Return(Session(key).ToString()) End Sub

El mtodo GetStyle se utiliza para crear estilos especficos de una sesin:

<style> body { font: <%=GetStyle("FontSize")%> <%=GetStyle("FontName")%>; background-color: <%=GetStyle("BackColor")%>; } a { color: <%=GetStyle("LinkColor")%> } </style>
Para comprobar que los valores se almacenan realmente con mbito de sesin, hay que abrir dos veces la pgina del ejemplo, cambiar un valor en la primera ventana del explorador y actualizarlo en la segunda. La segunda ventana reflejar los cambios, ya que las dos instancias de explorador comparten un objeto Session comn. Configurar el estado de una sesin: es posible configurar las caractersticas del estado de una sesin en la seccin <sessionState> de un archivo web.config. Para doblar el tiempo de espera predeterminado de 20 minutos, se puede agregar el cdigo siguiente al archivo web.config de una aplicacin:

De forma predeterminada, ASP.NET almacenar el estado de la sesin en el mismo proceso que atiende la solicitud, de la misma manera que ASP. Si no hay cookies disponibles, se puede hacer un seguimiento de una sesin agregando un identificador de sesin a la direccin URL. Se puede habilitar de la manera siguiente:

De forma predeterminada, ASP.NET almacenar el estado de la sesin en el mismo proceso que atiende la solicitud, de la misma manera que ASP. Adems, ASP.NET puede almacenar datos de sesin en un proceso externo, que podra residir en otro equipo. Para habilitar esta funcin:

Inicie el servicio de estado de ASP.NET mediante el complemento Servicios o ejecutando la instruccin "net start aspnet_state" desde la lnea de comandos. De manera predeterminada, el servicio de estado escuchar en el puerto 42424. Para cambiar el puerto, modifique la clave del Registro para el servicio: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\Port Establezca el atributo mode de la seccin <sessionState> en "StateServer".

Configure el atributo stateConnectionString con los valores del equipo en que se inici aspnet_state.

En el siguiente ejemplo se da por hecho que el servicio de estado se ejecuta en el mismo equipo que el servidor Web ("localhost") y utiliza el puerto predeterminado (42424):

<sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424" />


Hay que tener en cuenta que si se prueba el ejemplo anterior con este valor, es posible restablecer el servidor Web (escriba iisreset en la lnea de comandos) y as se conservar el valor de estado de la sesin.

Utilizar las cookies del cliente


En el ejemplo siguiente se ilustra el uso del estado de las cookies del cliente para preferencias de usuario voltiles. almacenar

<html>

<script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If Request.Cookies("preferences1") Is Nothing Dim Cookie As HttpCookie Cookie = New HttpCookie("preferences1") Cookie.Values.Add("ForeColor","black") Cookie.Values.Add("BackColor","beige") Cookie.Values.Add("LinkColor","blue") Cookie.Values.Add("FontSize","8pt") Cookie.Values.Add("FontName","Verdana") Response.AppendCookie(Cookie) End If End Sub Protected Function GetStyle(Key As String) As String Dim Cookie As HttpCookie Cookie = Request.Cookies("preferences1") If Not Cookie Is Nothing Select (Key) Case "ForeColor" : Return Cookie.Values("ForeColor") Case "BackColor" : Return Cookie.Values("BackColor") Case "LinkColor" : Return Cookie.Values("LinkColor") Case "FontSize" : Return Cookie.Values("FontSize") Case "FontName" : Return Cookie.Values("FontName") End Select End If Return "" End Function </script> <style> body { font: <%=GetStyle("FontSize")%> <%=GetStyle("FontName")%>; background-color: <%=GetStyle("BackColor")%>; } a { color: <%=GetStyle("LinkColor")%> } </style> <body style="color:<%=GetStyle("ForeColor")%>">

<h3><font face="Verdana">Almacenar datos voltiles con las cookies del cliente</font></h3> <b><a href="customize.aspx">Personalizar la pgina</a></b><p> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> </body> </html>

Almacenar cookies en el cliente es uno de los mtodos que utiliza el estado de las sesiones de ASP.NET para asociar solicitudes a sesiones. Tambin se pueden utilizar cookies directamente para conservar datos entre solicitudes, pero despus se almacenan los datos en el cliente y se envan al servidor con cada solicitud. Los exploradores limitan el tamao de las cookies; por tanto, slo se garantiza la aceptacin de un nmero mximo de 4096. Cuando se almacenan los datos en el cliente, el mtodo Page_Load del archivo cookies1.aspx comprueba si el cliente ha enviado una cookie. Si no se ha enviado ninguna, se crea una cookie nueva y despus se inicializa y almacena en el cliente:

Protected Sub Page_Load(sender As Object, e As EventArgs) If Request.Cookies("preferences1") = Null Then Dim cookie As New HttpCookie("preferences1") cookie.Values.Add("ForeColor", "black") ... Response.AppendCookie(cookie) End If End Sub

En la misma pgina, se utiliza de nuevo un mtodo GetStyle con el fin de proporcionar los valores individuales almacenados en la cookie:

Protected Function GetStyle(key As String) As String Dim cookie As HttpCookie = Request.Cookies("preferences1") If cookie <> Null Then Select Case key Case "ForeColor" Return(cookie.Values("ForeColor")) Case ... End Select End If Return("") End Function

Compruebe que el ejemplo funciona correctamente; para ello, abra la pgina cookies1.aspx y modifique las preferencias. Abra la pgina en otra ventana; esta ventana debera reflejar las nuevas preferencias. Cierre todas las ventanas del explorador y abra de nuevo la pgina cookies1.aspx. Esto debera eliminar la cookie temporal y restaurar los valores de preferencias predeterminados.

<html> <script language="VB" runat="server">

Sub Page_Load(Sender As Object, E As EventArgs) If Request.Cookies("preferences2") Is Nothing Dim Cookie As HttpCookie Cookie = New HttpCookie("preferences2") Cookie.Values.Add("ForeColor","black") Cookie.Values.Add("BackColor","beige") Cookie.Values.Add("LinkColor","blue") Cookie.Values.Add("FontSize","8pt") Cookie.Values.Add("FontName","Verdana") Response.AppendCookie(Cookie) End If End Sub Protected Function GetStyle(Key As String) As String Dim Cookie As HttpCookie Cookie = Request.Cookies("preferences2") If Not Cookie Is Nothing Select (Key) Case "ForeColor" : Return Cookie.Values("ForeColor") Case "BackColor" : Return Cookie.Values("BackColor") Case "LinkColor" : Return Cookie.Values("LinkColor") Case "FontSize" : Return Cookie.Values("FontSize") Case "FontName" : Return Cookie.Values("FontName") End Select End If Return "" End Function </script> <style> body { font: <%=GetStyle("FontSize")%> <%=GetStyle("FontName")%>; background-color: <%=GetStyle("BackColor")%>; } a { color: <%=GetStyle("LinkColor")%> } </style> <body style="color:<%=GetStyle("ForeColor")%>"> <h3><font face="Verdana">Almacenar datos permanentes con las cookies del cliente</font></h3> <b><a href="customize.aspx">Personalizar la pgina</a></b><p>

Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> Imagine algo de contenido aqu ...<br> </body> </html>

Para conservar una cookie entre sesiones es necesario establecer el valor de la propiedad Expires de la clase HttpCookie en una fecha futura. El siguiente fragmento de cdigo de la pgina customization.aspx es idntico al ejemplo anterior, con la excepcin de la asignacin a Cookie.Expires:

Protected Sub Submit_Click(sender As Object, e As EventArgs) Dim cookie As New HttpCookie("preferences2") cookie.Values.Add("ForeColor",ForeColor.Value) ... cookie.Expires = DateTime.MaxValue ' Never Expires Response.AppendCookie(cookie) Response.Redirect(State("Referer").ToString()) End Sub

Compruebe que el ejemplo funciona; para ello, modifique un valor, cierre todas las ventanas del explorador y abra de nuevo el archivo cookies2.aspx. La ventana debera mostrar an el valor personalizado.

Utilizar ViewState
En este ejemplo se ilustra el uso de la propiedad ViewState para almacenar valores especficos de una solicitud.

<%@ Register TagPrefix="Acme" TagName="Address" Src="address.ascx" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) If Not (IsPostBack) ViewState("PanelIndex") = 0 End If End Sub Sub Next_Click(Src As Object, E As EventArgs) Dim PrevPanelId As String = "Panel" & ViewState("PanelIndex").ToString() ViewState("PanelIndex") = CInt(ViewState("PanelIndex")) + 1 Dim PanelId As String = "Panel" & ViewState("PanelIndex").ToString() Dim P As Panel

P = FindControl(PanelId) P.Visible=true P = FindControl(PrevPanelId) P.Visible=false End Sub Sub Prev_Click(Src As Object, E As EventArgs) Dim PanelId As String = "Panel" & ViewState("PanelIndex").ToString() ViewState("PanelIndex") = CInt(ViewState("PanelIndex")) - 1 Dim PrevPanelId As String = "Panel" & ViewState("PanelIndex").ToString() Dim P As Panel P = FindControl(PanelId) P.Visible=false P = FindControl(PrevPanelId) P.Visible=true End Sub Sub Finish_Click(Src As Object, E As EventArgs) Dim P As Panel Dim PanelId As String = "Panel" & ViewState("PanelIndex").ToString() P = FindControl(PanelId) P.Visible=false MyLabel.Text &= "<b>Gracias, hemos recibido la siguiente informacin: </b><p>" MyLabel.Text &= "Nombre: " & FirstName.Value & "<br>" MyLabel.Text &= "Apellido: " & LastName.Value & "<br>" MyLabel.Text &= "Direccin: " & Address.Address & "<br>" MyLabel.Text &= "Ciudad: " & Address.City & "<br>" MyLabel.Text &= "Estado: " & Address.StateName & "<br>" MyLabel.Text &= "Cdigo postal: " & Address.Zip & "<br>" MyLabel.Text &= "Nmero de tarjeta: " & CardNum.Value & "<br>" MyLabel.Text &= "Tipo de tarjeta: " & CardType.SelectedItem.Value & "<br>" MyLabel.Text &= "Caduca: " & Expires.Value & "<br>" End Sub </script> <body style="font: 10pt verdana"> <h3><font face="Verdana">Utilizar PageState</font></h3> <form runat="server"> <ASP:Panel id="Panel0" Visible="true" runat="server"> <table width="500" height="200" style="font:10pt verdana;background-color:cccccc;border-width:1;borderstyle:solid;border-color:black"> <tr> <td style="padding:10,10,10,10" valign="top"> <table height="100%" style="font:10pt verdana;"> <tr> <td colspan="2"><b>Completar los siguientes campos y, a continuacin, seleccionar Siguiente para continuar:</b></td> </tr> <tr height="20"/> <tr> <td>Nombre:</td> <td><input id="FirstName" type="text" size="45" runat="server"></td> </tr>

<tr> <td>Apellido:</td> <td><input id="LastName" type="text" size="45" runat="server"></td> </tr> <tr> <td colspan="2" align="right" height="100%" valign="bottom"> <input type="submit" Value=" Siguiente >> " OnServerClick="Next_Click" runat="server"> </td> </tr> </table> </td> </tr> </table> </ASP:Panel> <ASP:Panel id="Panel1" Visible="false" runat="server"> <table width="500" height="200" style="font:10pt verdana;background-color:cccccc;border-width:1;borderstyle:solid;border-color:black"> <tr> <td style="padding:10,10,10,10" valign="top"> <table height="100%" style="font:10pt verdana;"> <tr> <td colspan="2"><b>Completar los siguientes campos y, a continuacin, seleccionar Siguiente para continuar:</b></td> </tr> <tr height="20"/> <tr> <td colspan="2"> <Acme:Address id="Address" ShowCaption="false" runat="server"/> </td> </tr> <tr> <td colspan="2" align="right" valign="bottom" height="100%"> <input type="submit" Value=" << Atrs " OnServerClick="Prev_Click" runat="server"> <input type="submit" Value=" Siguiente >> " OnServerClick="Next_Click" runat="server"> </td> </tr> </table> </td> </tr> </table> </ASP:Panel> <ASP:Panel id="Panel2" Visible="false" runat="server"> <table width="500" height="200" style="font:10pt verdana;background-color:cccccc;border-width:1;borderstyle:solid;border-color:black"> <tr> <td style="padding:10,10,10,10" valign="top"> <table height="100%" style="font:10pt verdana;"> <tr> <td colspan="2"><b>Completar los siguientes campos y, a continuacin, seleccionar Siguiente para continuar:</b></td> </tr> <tr height="20"/> <tr> <td>Nmero de tarjeta: </td> <td><input id="CardNum" size="45" type="text" runat="server"/></td> </tr> <tr> <td>Tipo de tarjeta: </td> <td> <asp:DropDownList id="CardType" runat="server"> <asp:ListItem>Visa</asp:ListItem>

<asp:ListItem>Mastercard</asp:ListItem> <asp:ListItem>Discover</asp:ListItem> </asp:DropDownList> </td> </tr> <tr> <td>Caduca: </td> <td><input id="Expires" type="text" runat="server"/></td> </tr> <tr> <td colspan="2" align="right" valign="bottom" height="100%"> <input type="submit" Value=" << Atrs " OnServerClick="Prev_Click" runat="server"> <input type="submit" Value=" Finalizar " OnServerClick="Finish_Click" runat="server"> </td> </tr> </table> </td> </tr> </table> </ASP:Panel> </form> <asp:Label id="MyLabel" EnableViewState="false" runat="server"/> </body> </html>

ASP.NET proporciona la nocin de estado de la presentacin de cada control en el servidor. Un control puede guardar su estado interno entre solicitudes mediante la propiedad ViewState de una instancia de la clase StateBag. La clase StateBag proporciona una interfaz de tipo diccionario para almacenar objetos asociados a una clave de tipo cadena. El archivo pagestate1.aspx muestra un panel visible y almacena el ndice del panel en el estado de la presentacin de la pgina con la clave PanelIndex:

Protected Sub Next_Click(sender As Object, e As EventArgs) Dim PrevPanelId As String = "Panel" + ViewState("PanelIndex").ToString() ViewState("PanelIndex") = CType(ViewState("PanelIndex") + 1, Integer) Dim PanelId As String = "Panel" + ViewState("PanelIndex").ToString() ... End Sub

Hay que tener en cuenta que si se abre la pgina en varias ventanas del explorador, cada ventana del explorador mostrar inicialmente el panel del nombre. Todas las ventanas permiten el desplazamiento entre paneles de forma independiente.

Resumen de la seccin
1. Utilice variables de estado de la aplicacin para almacenar datos que se modifican con poca frecuencia pero que se utilizan a menudo. 2. Utilice variables de estado de la sesin para almacenar datos especficos de una sesin o de un usuario. Los datos se almacenan completamente en el servidor. Hay que utilizar estas variables para datos de poca duracin, datos importantes o grandes cantidades de datos. 3. Almacene pequeas cantidades de datos voltiles en una cookie no persistente. Los datos se almacenan en el cliente, se envan al servidor en cada solicitud y caducan cuando finalice la ejecucin en el cliente. 4. Almacene pequeas cantidades de datos no voltiles en una cookie persistente. Los datos se almacenarn en el cliente hasta que caduquen y se enviarn al servidor en cada solicitud. 5. Almacene en el estado de la presentacin pequeas cantidades de datos especficos de una solicitud. Los datos se envan desde el servidor al cliente y viceversa.

Generadores y controladores HTTP

Informacin general
ASP.NET proporciona una API de bajo nivel para solicitudes y respuestas que permite a los programadores utilizar clases de .NET Framework para ocuparse de las solicitudes HTTP entrantes. Para ello, los programadores crean clases que admiten la interfaz System.Web.IHTTPHandler e implementan el mtodo ProcessRequest(). Los controladores suelen ser tiles cuando los servicios suministrados por la abstraccin del marco de trabajo de pgina de alto nivel no son necesarios para procesar la solicitud HTTP. Entre los usos habituales de los controladores, se incluyen los filtros y las aplicaciones al estilo CGI, especialmente aqullas que devuelven datos binarios. Cada solicitud HTTP recibida por ASP.NET se procesa en ltimo trmino mediante una instancia especfica de una clase que implementa IHTTPHandler. IHttpHandlerFactory proporciona la infraestructura que controla la resolucin real de las solicitudes URL en instancias IHttpHandler. Adems de las clases IHttpHandlerFactory predeterminadas suministradas por ASP.NET, los programadores pueden opcionalmente crear y registrar generadores que admitan escenarios complejos de activacin y resolucin de solicitudes.

Configurar generadores y controladores HTTP


Los generadores y controladores HTTP se declaran en la configuracin de ASP.NET como parte de un archivo web.config. ASP.NET define una seccin de configuracin <httphandlers> en la que se pueden agregar y quitar controladores y generadores. Los valores de configuracin para HttpHandlerFactory y HttpHandler son heredados por los subdirectorios. Por ejemplo, ASP.NET asigna todas las solicitudes de archivos .aspx a la clase PageHandlerFactory del archivo global machine.config:

<httphandlers> ... <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory,System.Web" /> ... </httphandlers>

Crear un controlador HTTP personalizado


El siguiente ejemplo crea un controlador HttpHandler personalizado que controla todas las solicitudes que se realizan a "SimpleHandler.aspx".

Imports System.Web Namespace Acme Public Class SimpleHandlerVB : Implements IHttpHandler Public Sub ProcessRequest(Context As HttpContext) Implements IHttpHandler.ProcessRequest Context.Response.Write("Hola a todos") End Sub Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable Get Return true End Get End Property End Class End Namespace

Un controlador HTTP personalizado se puede crear implementando la interfaz IHttpHandler, la cual contiene slo dos mtodos. Mediante una llamada a IsReusable, un generador HTTP puede consultar a un controlador para determinar si se puede utilizar la misma instancia con el f in de atender a varias solicitudes. El mtodo ProcessRequest toma una instancia HttpContext como parmetro y le proporciona acceso a los intrnsecos Request y Response. En el siguiente ejemplo, los datos de solicitud no se tienen en cuenta y se enva una constante de tipo cadena como respuesta al cliente.

Public Class SimpleHandler : Inherits IHttpHandler Public Sub ProcessRequest(context As HttpContext) context.Response.Write("Hello World!")

End Sub Public Function IsReusable() As Boolean Return(True) End Function End Class

Despus de incluir el ensamblado del controlador compilado en el directorio \bin de la aplicacin, la clase del controlador se puede especificar como objetivo de las solicitudes. En este caso, todas las solicitudes dirigidas a "SimpleHandler.aspx" se desvan a una instancia de la clase SimpleHandler, la cual reside en el espacio de nombres Acme.SimpleHandler.

Resumen de la seccin
1. Los controladores y generadores HTTP constituyen el eje del marco de trabajo de las pginas ASP.NET. 2. Los generadores asignan cada solicitud a un controlador, que se encarga de procesarlas. 3. Los generadores y controladores se definen en el archivo web.config. Los subdirectorios heredan la configuracin de los generadores..

4.

Para crear un controlador personalizado, hay que implementar IHttpHandler y agregar la clase a la seccin <httphandlers> del archivo web.config del directorio.

Servicios de cach

Informacin general sobre el almacenamiento en cach


El almacenamiento en cach es una tcnica ampliamente utilizada en informtica para aumentar el rendimiento, que consiste en mantener datos de acceso frecuente o costoso en una memoria ms rpida. En el contexto de una aplicacin Web, el almacenamiento en cach se utiliza para retener pginas o datos durante las solicitudes HTTP y reutilizarlos sin tener que crearlos de nuevo. ASP.NET dispone de tres clases de cach que se pueden utilizar en las aplicaciones Web:

Cach de resultados, que almacena en cach la respuesta dinmica generada por una solicitud. Cach de fragmentos, que almacena en cach partes de una respuesta generada por una solicitud.

Cach de datos, que almacena en cach objetos arbitrarios mediante programacin. Para ello, ASP.NET proporciona un motor de cach muy completo que permite a los programadores retener fcilmente datos entre solicitudes. La cach de resultados es til cuando el contenido de toda una pgina se puede almacenar en memoria cach. En un sitio con muchos accesos, mantener en cach las pginas con accesos ms frecuentes durante incluso un minuto cada vez puede producir incrementos significativos del rendimiento. Mientras una pgina permanece en la cach de resultados, las solicitudes subsiguientes de esa pgina se atienden desde la pgina de resultados, sin ejecutar el cdigo que la cre. A veces, no resulta prctico mantener en cach una pgina entera (quiz es mejor crear o personalizar partes de la pgina para cada solicitud). En este caso, suele ser preferible identificar aquellos objetos o datos cuya construccin sea ms costosa como candidatos al almacenamiento en cach. Tras identificar a esos elementos, se pueden crear una sola vez y almacenarse en cach durante algn tiempo. Adems, se puede utilizar la cach de fragmentos para mantener en cach partes del resultado de una pgina. La eleccin del momento en el que se puede almacenar en cach un elemento puede constituir una decisin interesante. Para algunos elementos, los datos podran actualizarse a intervalos regulares o ser vlidos durante un cierto perodo de tiempo. En ese caso, los elementos en cach pueden estar sometidos a unas reglas de caducidad que determinen el tiempo que pueden estar almacenados en la cach. El cdigo que obtiene acceso al elemento en cach simplemente comprueba la ausencia del elemento y vuelve a crearlo si es necesario. La cach de ASP.NET admite dependencias de clave y de archivos, lo que permite a los programadores hacer que un elemento en cach dependa de un archivo externo o de otro elemento almacenado en cach. Esta tcnica se puede utilizar para invalidar elementos cuando su origen de datos subyacente cambia.

Almacenar en cach resultados de pgina


El almacenamiento en cach de resultados es una tcnica eficaz que aumenta el rendimiento de procesos solicitud/respuesta almacenando en cach el contenido generado en pginas dinmicas. El almacenamiento de resultados en cach est habilitado de forma predeterminada, pero los resultados de una respuesta no se almacenarn en cach a menos que se realice una accin explcita para que se pueda almacenar en cach la respuesta. Para permitir que una respuesta sea vlida con el fin de almacenar resultados en cach, hay que tener una directiva de vencimiento o validacin vigente y de visibilidad en cach pblica. Esto se puede hacer mediante la API de bajo nivel OutputCache o la directiva de alto nivel @ OutputCache. Cuando se habilita el almacenamiento de resultados en cach se crea una entrada en la primera solicitud GET enviada a la pgina. Las solicitudes GET o HEAD siguientes se atendern desde la entrada de la cach de resultados hasta que caduque la solicitud almacenada en cach. El almacenamiento en cach de resultados tambin admite variaciones de pares nombre/valor GET o POST almacenados en cach. Tambin respeta las directivas de vencimiento y validacin de las pginas. Si una pgina est almacenada en la cach de resultados, marcada con una directiva de vencimiento que indica que la pgina caduca a los 60 minutos del momento en que se almacena en cach, se quitar de la cach de resultados cuando hayan transcurrido 60 minutos. Si se recibe otra solicitud despus de ese momento, se ejecuta el cdigo de la pgina y se puede volver a almacenar en cach dicha pgina. Este tipo de directiva de vencimiento se denomina vencimiento absoluto: una pgina es vlida hasta una hora determinada. En el ejemplo siguiente se muestra una forma sencilla de almacenar las respuestas en la cach de resultados mediante la directiva @ OutputCache. El ejemplo slo muestra la hora a la que se gener la respuesta. Para ver el funcionamiento del almacenamiento en cach de resultados, llame a la pgina y vea la hora a la que se gener la respuesta. A continuacin, actualice la pgina y observe que la hora no cambi, lo que indica que la segunda respuesta se enva desde la cach de resultados.

<%@ OutputCache Duration="60" VaryByParam="none" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) TimeMsg.Text = DateTime.Now.ToString("G") End Sub </script> <body> <h3><font face="Verdana">Utilizar la cach de resultados</font></h3> <p><i>Generado por ltima vez el:</i> <asp:label id="TimeMsg" runat="server"/> </body> </html>
La siguiente directiva activa el almacenamiento en cach de los resultados de la respuesta:

<%@ OutputCache Duration="60" VaryByParam="none"%>


Esta directiva indica simplemente que la pgina debe almacenarse en cach durante 60 segundos y que la pgina no vara en funcin de ningn parmetro GET o POST. Las solicitudes recibidas mientras la pgina permanezca almacenada se satisfarn desde la cach. Cuando hayan transcurrido 60 segundos, se quita la pgina de la cach; la siguiente solicitud se controla explcitamente y vuelve a almacenar en cach la pgina. Como es lgico, en el ejemplo anterior se guarda poco trabajo mediante el almacenamiento en cach de los resultados. En el siguiente ejemplo se muestra la misma tcnica para el almacenamiento en cach de los resultados, pero en este caso se consulta una base de datos y se muestran los resultados en una cuadrcula.

<%@ OutputCache Duration="60" VaryByParam="none" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %>

<html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter Dim ds As DataSet MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) ds = New DataSet() MyCommand.Fill(ds, "Authors") MyDataGrid.DataSource=new DataView(ds.Tables(0)) MyDataGrid.DataBind() TimeMsg.Text = DateTime.Now.ToString("G") End Sub </script> <body> <h3><font face="Verdana">Utilizar la cach de resultados</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding="3" CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" /> <p> <i>Generado por ltima vez el:</i> <asp:label id="TimeMsg" runat="server" /> </body> </html>
En el ltimo ejemplo, se modifica ligeramente la aplicacin para permitir al usuario consultar informacin de autores de varios estados de forma selectiva. En este ejemplo se muestran solicitudes de almacenamiento en cach que se diferencian en los pares nombre/valor de la cadena de consulta mediante el atributo VaryByParam de la directiva @ OutputCache.

<%@ OutputCache Duration="60" VaryByParam="state" %>


Para cada estado del conjunto de datos hay un vnculo que pasa el estado deseado como parte de la cadena de consulta. A continuacin la aplicacin crea la consulta de base de datos apropiada y muestra slo los autores que pertenecen al estado seleccionado. Tenga en cuenta que la primera vez que haga clic en el vnculo para un estado determinado se generar una nueva marca de la hora en la parte inferior de la pgina. Despus, siempre que se vuelva a enviar una solicitud para ese estado en el plazo de un minuto se obtendr la marca de la hora original, lo que indica que la solicitud se almacen en cach.

<%@ OutputCache Duration="60" VaryByParam="state" %>

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter Dim ds As DataSet Dim queryState As String Dim selectCmd As String queryState = Request.QueryString("state") If queryState = Nothing selectCmd = "select * from Authors" Else selectCmd = "select * from Authors where state = '" + queryState + "'" End If MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter(selectCmd, MyConnection) ds = New DataSet() MyCommand.Fill(ds, "Authors") MyDataGrid.DataSource=new DataView(ds.Tables(0)) MyDataGrid.DataBind() ' capture the time of the current request ' subsequent requests while we're still cached ' will show the original time TimeMsg.Text = DateTime.Now.ToString("G") End Sub </script> <body> <h3><font face="Verdana">Utilizar la cach de resultados</font></h3> <b>Autores por estado:</b> <table cellspacing="0" cellpadding="3" rules="all" style="background-color:#AAAADD;border-color:black;bordercolor:black;width:700px;border-collapse:collapse;"> <tr> <td><a href="outputcache3.aspx?state=CA">CA</a></td> <td><a href="outputcache3.aspx?state=IN">IN</a></td> <td><a href="outputcache3.aspx?state=KS">KS</a></td> <td><a href="outputcache3.aspx?state=MD">MD</a></td> <td><a href="outputcache3.aspx?state=MI">MI</a></td> <td><a href="outputcache3.aspx?state=OR">OR</a></td> <td><a href="outputcache3.aspx?state=TN">TN</a></td> <td><a href="outputcache3.aspx?state=UT">UT</a></td> </tr> </table> <p> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700" BackColor="#ccccff" BorderColor="black"

ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" /> <p> <i>Generado por ltima vez el:</i> <asp:label id="TimeMsg" runat="server"/> </body> </html>

Aquellas aplicaciones que se desee que ejerzan ms control sobre los encabezados HTTP relacionados con el almacenamiento en cach pueden utilizar la funcionalidad proporcionada por la clase System.Web.HttpCachePolicy. En el siguiente ejemplo se muestra el cdigo equivalente a las directivas de pgina utilizadas en los ejemplos anteriores.

Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)) Response.Cache.SetCacheability(HttpCacheability.Public)
Para convertir esto en una directiva de vencimiento variable, en la que se restablece el tiempo de vencimiento cada vez que se solicita la pgina, establezca el valor de la propiedad SlidingExpiration de la manera mostrada en el cdigo siguiente.

Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)) Response.Cache.SetCacheability(HttpCacheability.Public) Response.Cache.SetSlidingExpiration(True)

Nota: cuando la fecha de vencimiento variable est habilitada (SetSlidingExpiration(true)), una solicitud enviada al servidor de origen siempre origina una respuesta. El vencimiento variable es til en escenarios en los que hay cachs indirectas, que pueden satisfacer solicitudes de clientes (si el contenido an no ha caducado) sin solicitar el contenido al servidor de origen. Puede que algunas aplicaciones que se estn adaptando desde la tecnologa ASP ya establezcan directivas de almacenamiento en cach con las propiedades de ASP; por ejemplo:

Response.CacheControl = "Public" Response.Expires = 60


ASP.NET es compatible con estas propiedades, que surten el mismo efecto que los otros ejemplos mostrados.

Resumen de la seccin
1. El almacenamiento en cach de resultados permite almacenar en cach el contenido generado por las pginas ASP.NET. 2. Las pginas no se colocan en la cach de resultados a menos que tengan una fecha de vencimiento o una directiva de validacin vlidas, as como visibilidad pblica de cach.

Cach de fragmentos de pgina


Adems de insertar en la cach una pgina completa, ASP.NET proporciona un medio sencillo para utilizar la cach slo con ciertas reas del contenido de la pgina; esta caracterstica se denomina cach de fragmentos. Las reas de la pgina se definen mediante un control de usuario y se marcan para insertarlas en la cach mediante la directiva @ OutputCache presentada en la seccin anterior. Esta directiva especifica el tiempo (en segundos) que el contenido resultante del control de usuario debera permanecer en la cach del servidor, as como cualquier condicin opcional por la cual debera modificarse. Por ejemplo, la siguiente directiva indica a ASP.NET que coloque en la cach el control de usuario durante 120 segundos y que modifique la cach mediante los parmetros de envo del formulario o cadenas de consulta "CategoryID" y "SelectedID".

<%@ OutputCache Duration="120" VaryByParam="CategoryID;SelectedID"%>


El atributo VaryByParam permite a los creadores de controles de usuario indicar a ASP.NET que coloque en la cach o almacene mltiples instancias de un rea en el servidor. Por ejemplo, las siguientes URL que apuntan a la pgina host de la cach del control de usuario anterior separan instancias del contenido del control de usuario. http://localhost/mypage.aspx?categoryid=foo&selectedid=0 http://localhost/mypage.aspx?categoryid=foo&selectedid=1 La lgica interna de un control de usuario puede entonces generar dinmicamente contenido distinto (el cual se coloca en la cach por separado) segn los argumentos suministrados. Adems de utilizar el atributo VaryByParam, la cach de fragmentos tambin admite el atributo VaryByControl. Mientras que el atributo VaryByParam modifica los resultados en cach segn pares nombre/valor enviados mediante POST o GET, el atributo VaryByControl modifica el fragmento en cach mediante controles internos del control de usuario. Por ejemplo:

<%@ OutputCache Duration="120" VaryByParam="none" VaryByControl="Category" %>


Observe que, de modo similar a las pginas colocadas en la cach de salida, es necesario incluir VaryByParam aunque no se utilice. Si el control de usuario contiene un control de cuadro de seleccin desplegable denominado Categora, el resultado del control de usuario variar segn el valor seleccionado en ese control. Al igual que es posible anidar controles de usuario recursivamente dentro de una pgina (es decir, un control de usuario declarado dentro de otro control del servidor), tambin es posible anidar controles de usuario en la cach de salida de forma recursiva. Esto proporciona un modelo de composicin que permite a las reas que utilizan la cach estar compuestas de otras reas que tambin vayan a utilizarla. El siguiente cdigo de ejemplo muestra cmo hacer que dos secciones de men de una pgina utilicen la cach mediante un control de usuario declarativo.

<%@ Register TagPrefix="Acme" TagName="Menu" Src="Menu.ascx" %> <html> <body> <table> <tr> <td> <Acme:Menu Category="LeftMenu" runat=server/> </td> <td> <h1>Hi, the time is now: <%=Now%> </h1> </td> <td> <Acme:Menu Category="RightMenu" runat=server/> </td> <tr> </table> </body> </html>

El siguiente cdigo de ejemplo muestra la implementacin del control de usuario "Acme:Menu" con utilizacin de la cach.

<%@ OutputCache Duration="120" VaryByParam="none" %> <script language="VB" runat=server> Public Category As String; Sub Page_Load(sender As Object, e As EventArgs) Dim conn As AdoConnection = New AdoConnection("MyDSN")

MyMenu.DataSource = conn.Execute("select * from menu where category=" & Category) MyMenu.DataBind() End Sub </script> <asp:datagrid id="MyMenu" runat=server/>

Observe que, en este ejemplo, la respuesta de cada control de usuario utiliza la cach durante un perodo de 120 segundos. Toda la lgica necesaria para volver a crear cada control de usuario del men, en el caso de que no se encuentre en la cach (ya sea por haber finalizado el perodo de 120 segundos o porque la memoria del servidor no sea suficiente), se encapsula limpiamente dentro del control de usuario. El siguiente ejemplo muestra un caso sencillo de cach de fragmentos. En este ejemplo, el resultado de un control que recupera datos de una base de datos SQL Server utiliza la cach, a la vez que se conservan las propiedades dinmicas de la pgina principal. Se puede ver que la pgina es dinmica porque el tiempo se modifica con cada actualizacin, mientras que el control slo se actualiza cada 60 segundos.

<%@ Register TagPrefix="Acme" TagName="DataControl" Src="datactrl.ascx" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) TimeMsg.Text = DateTime.Now.ToString("G") End Sub </script> <body> <h3><font face="Verdana">Almacenamiento en cach de fragmentos</font></h3> <Acme:DataControl runat="server"/> <br> <i>Pgina generada por ltima vez:</i> <asp:label id="TimeMsg" runat="server" /> </body> </html>

Advertencias
Nota: los intentos de manipular mediante programacin un control que utiliza la cach, desde su pgina contenedora, hacen que se produzca un error. Por ejemplo, los intentos de utilizar una expresin declarativa de enlace de datos en la etiqueta del control de usuario hacen que se generen errores de anlisis, como se muestra en el siguiente cdigo.

<!-- Las siguientes etiquetas generan errores de anlisis. --> <Acme:Menu Category='<%# Container.DataItem("Category")' runat="server"/>
La razn de ello es simple. En los casos en que se utiliza la cach para el contenido de un control de usuario, se crea una instancia del control slo en la primera solicitud; de este modo, una vez en la cach, el control deja de estar disponible. En vez de ello, se debera encapsular toda la lgica necesaria para crear el contenido de un control de usuario dentro del propio control; esto se hace normalmente dentro del evento Page_Load o Page_PreRender del control de usuario.

Se pueden declarar y utilizar otros parmetros de propiedades declarativas para personalizar el control. Por ejemplo, el control de usuario anterior se puede personalizar del siguiente modo:

<Acme:Menu Category="LeftMenu" runat=server/> <Acme:Menu Category="RightMenu" runat=server/>


Estas declaraciones hacen que el compilador de pginas genere y ejecute el cdigo apropiado en caso de que se cree el control como resultado de una falta de datos en la cach. Los programadores de controles de usuario pueden tener acceso a estas opciones de configuracin de igual forma que en el caso de controles de usuario que no utilizan la cach.

Resumen de la seccin
1. Adems de insertar en la cach una pgina completa, ASP.NET proporciona un medio sencillo para utilizar la cach slo con ciertas reas del contenido de la pgina; esta caracterstica se denomina cach de fragmentos.

2.

Las reas de la pgina se definen mediante un control de usuario y se marcan para que utilicen la cach, mediante la directiva @ OutputCache presentada en la seccin anterior. 3. Al igual que es posible anidar controles de usuario recursivamente dentro de una pgina (es decir, un control de usuario declarado dentro de otro control del servidor), tambin es posible anidar controles de usuario en la cach de salida de forma recursiva.

4.

Los intentos de manipular mediante programacin un control que utiliza la cach, desde su pgina contenedora, hacen que se produzca un error. En vez de ello, se debera encapsular toda la lgica necesaria para crear el contenido de un control de usuario directamente dentro del propio control, normalmente dentro del evento Page_Load o Page_PreRender del control de usuario. 5. Se pueden declarar y utilizar otros parmetros de propiedades declarativas para personalizar el control.

Cach de datos de pgina


Introduccin a la cach de datos
ASP.NET proporciona un motor de cach con mltiples caractersticas que pueden utilizar las pginas con el fin de almacenar y recuperar objetos arbitrarios mediante las solicitudes HTTP. La cach de ASP.NET es privada para cada aplicacin y almacena los objetos en memoria. El perodo de vida de la cach equivale al de la aplicacin; es decir, cuando la aplicacin se reinicia, la cach se crea de nuevo. La cach proporciona una interfaz de diccionario sencilla que permite a los programadores colocar objetos dentro y recuperarlos posteriormente con facilidad. En el caso ms simple, colocar un elemento en la cach es como agregar un elemento a un diccionario:

Cache("mykey") = myValue

Recuperar los datos es igual de sencillo:

myValue = Cache("mykey") If myValue <> Null Then DisplayData(myValue) End If

Para aplicaciones que necesitan una funcionalidad ms sofisticada, la cach de ASP.NET ofrece eliminacin de datos innecesarios, caducidad y dependencias de clave y archivo.

La eliminacin de datos es el proceso por el que la cach intenta quitar elementos no importantes o utilizados con poca frecuencia en caso de que la memoria sea escasa. Los programadores que deseen controlar la eliminacin de datos pueden proporcionar sugerencias al eliminador al insertar los elementos en la cach, lo que indica el costo relativo de creacin del elemento y la rapidez relativa con la que se debe obtener acceso al elemento de manera que resulte til. La caducidad permite a los programadores asignar perodos de vida a los elementos en cach; pudiendo los perodos ser explcitos (por ejemplo, caduca a las 6:00) o bien relativos al ltimo uso de un elemento (por ejemplo, caduca 20 minutos despus de haber utilizado el elemento por ltima vez). Cuando un elemento ha caducado, se elimina de la cach y, entonces, cualquier intento para recuperarlo hace que se devuelva el valor null, a menos que el elemento se inserte de nuevo en la cach. Las dependencias de clave y archivo permiten basar la validez de un elemento de la cach en un archivo externo o en otro elemento de la cach. Si una dependencia cambia, el elemento ya no es vlido y, entonces, se quita de la cach. Un ejemplo de

cmo se podra utilizar esta funcionalidad lo constituye el siguiente escenario: una aplicacin lee informacin financiera de un archivo XML que se actualiza peridicamente. La aplicacin procesa los datos del archivo y crea un grafico de objetos que representa los datos en un formato ms significativo. La aplicacin almacena los datos en la cach e inserta una dependencia en el archivo desde el que se leyeron los datos. Cuando el archivo se actualiza, los datos se eliminan de la cach y la aplicacin puede volver a leerlos e insertar la copia actualizada de los datos.

Utilizar la cach de datos


El siguiente ejemplo muestra una utilizacin sencilla de la cach. Ejecuta una consulta de base de datos, guarda el resultado en la cach y sigue utilizndolo durante el perodo de vida de la aplicacin. Cuando ejecute el ejemplo, observe el mensaje que aparece en la parte inferior de la pgina. Cuando se realiza una solicitud por primera vez, el mensaje indica que los datos se recuperaron explcitamente del servidor de la base de datos. Tras actualizar la pgina, sta advierte que se utiliz la copia almacenada en cach.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim Source As DataView ' try to retrieve item from cache ' if it's not there, add it Source = Cache("MyDataSet") If Source Is Nothing Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection("server=(local)\NetSDK;database=pubs;Trusted_Connection=yes") MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) Dim ds As New DataSet myCommand.Fill(ds, "Authors") Source = New DataView(ds.Tables("Authors")) Cache("MyDataSet") = Source CacheMsg.Text = "Conjunto de datos creado explcitamente" Else cacheMsg.Text = "Conjunto de datos recuperado de la cach" End If MyDataGrid.DataSource=Source MyDataGrid.DataBind() End Sub </script> <body> <form method="GET" runat="server"> <h3><font face="Verdana">Almacenar datos en cach</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="700"

BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaad" /> <p> <i><asp:label id="CacheMsg" runat="server"/></i> </form> </body> </html>

El siguiente ejemplo muestra un elemento de la cach que depende de un archivo XML. Es similar al primer ejemplo, aunque en este caso los datos se recuperan de un origen de datos XML en vez de un servidor de base de datos. Cuando los datos se insertan en la cach, el archivo XML se agrega como una dependencia. Cuando se agrega un nuevo registro mediante el formulario de la parte inferior de la pgina, el archivo XML se actualiza y, entonces, el elemento almacenado en la cach debe crearse de nuevo.

<%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) If Not IsPostBack LoadData() End If End Sub Sub NewAuthorBtn_Click(Src As Object, E As EventArgs) If Not Page.IsValid AuthorMsg.Text = "Faltan algunos campos requeridos" Else Dim fs As FileStream Dim reader As StreamReader Dim ds As DataSet Dim newAuthor As DataRow Dim writer As TextWriter ' open the file and read the current authors ds = New DataSet fs = New FileStream(Server.MapPath("authors.xml"), FileMode.Open, FileAccess.Read, FileShare.ReadWrite) reader = New StreamReader(fs) ds.ReadXml(reader) fs.Close() ' append a row Try newAuthor = ds.Tables(0).NewRow() newAuthor("au_id") = AuthorId.Text

newAuthor("au_lname") = LastName.Text newAuthor("au_fname") = FirstName.Text newAuthor("phone") = Phone.Text newAuthor("address") = Address.Text newAuthor("city") = City.Text newAuthor("state") = AddressState.Text newAuthor("zip") = PostalCode.Text newAuthor("contract") = Contract.Checked ds.Tables(0).Rows.Add(newAuthor) Catch Exc As Exception CacheMsg.Text = "No se pudo crear el autor con id. = (" & AuthorId.Text & ")<br>" & "El autor ya existe." Return End Try ' rewrite the data file fs = New FileStream(Server.MapPath("authors.xml"), FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite) writer = New StreamWriter(fs) writer = TextWriter.Synchronized(writer) ds.WriteXml(writer) writer.Close() Cache.Remove("MyData") LoadData() End If End Sub Sub RefreshBtn_Click(Src As Object, E As EventArgs) LoadData() End Sub Sub LoadData Dim Source As DataView Source = Cache("MyData") If Source Is Nothing Dim ds As DataSet Dim fs As FileStream Dim reader As StreamReader ' read the data from the XML source ds = New DataSet() fs = New FileStream(Server.MapPath("authors.xml"), FileMode.Open,FileAccess.Read) reader = New StreamReader(fs) ds.ReadXml(reader) fs.Close() Source = New DataView(ds.Tables(0)) ' cache it for future use Cache.Insert("MyData", Source, New CacheDependency(Server.MapPath("authors.xml"))) ' we created the data explicitly, so advertise that fact CacheMsg.Text = "Conjunto de datos creado explcitamente" Else CacheMsg.Text = "Conjunto de datos recuperado de la cach" End If MyDataGrid.DataSource = Source MyDataGrid.DataBind() End Sub </script>

<body> <form runat="server"> <h3><font face="Verdana">Dependencias del archivo</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="900" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" /> <hr> <h3><font face="Verdana">Agregar nuevo autor</font></h3> <asp:Label ID="AuthorMsg" Text="Rellenar los campos requeridos a continuacin para agregar un nuevo autor" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /> <p> <table> <tr> <td>Id. del autor:</td> <td><ASP:TextBox id=AuthorId Text="111-11-1111" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="AuthorId" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>Apellido:</td> <td><ASP:TextBox id=LastName Text="Doe" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="LastName" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>Nombre:</td> <td><ASP:TextBox id=FirstName Text="John" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="FirstName" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>Telfono:</td> <td><ASP:TextBox id=Phone Text="555 555-5050" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="Phone" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>Direccin:</td> <td><ASP:TextBox id=Address Text="One Microsoft Way" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="Address" ErrorMessage="*" Display="Static" runat=server/></td> </tr> <tr> <td>Ciudad:</td> <td><ASP:TextBox id=City Text="Redmond" runat=server/></td>

<td><ASP:RequiredFieldValidator ControlToValidate="City" ErrorMessage="*" Display="Static" runat=server/></td> </tr> <tr> <td>Estado:</td> <td><ASP:TextBox id=AddressState Text="WA" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="AddressState" ErrorMessage="*" Display="Static" runat=server/></td> </tr> <tr> <td>Cdigo postal:</td> <td><ASP:TextBox id=PostalCode Text="98052" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="PostalCode" ErrorMessage="*" Display="Static" runat=server/></td> </tr> <tr> <td>Contrato:</td> <td><ASP:CheckBox id=Contract Checked runat="server"/></td> <td></td> </tr> </table> <asp:button Text="Agregar nuevo autor" OnClick="NewAuthorBtn_Click" runat=server/> <asp:button Text="Actualizar lista" OnClick="RefreshBtn_Click" runat=server/> <p> <hr> <p> <i><asp:label id="CacheMsg" runat="server"/></i></p> </form> </body> </html>

Observe que se agrega una dependencia de archivo utilizando Cache.Insert y suministrando un objeto CacheDependency que hace referencia al archivo XML.

Cache.Insert("MyData", Source, _ New CacheDependency(Server.MapPath("authors.xml")))

Un elemento de la cach puede depender de uno o varios archivos o claves. Como ya se mencion anteriormente, una aplicacin puede definir reglas de caducidad sobre un elemento de la cach. El siguiente cdigo establece un tiempo de caducidad absoluto.

Cache.Insert("MyData", Source, null, _ DateTime.Now.AddHours(1), TimeSpan.Zero)

El parmetro relevante es la llamada a DateTime.Now.AddHours(1), que indica que el tiempo finaliza 1 hora despus del momento en que se insert. El argumento final, TimeSpan.Zero, indica que no existe ninguna regla de caducidad relativa para este elemento. El siguiente cdigo muestra cmo establecer una regla de caducidad relativa. Inserta un elemento que caduca 20 minutos despus de su ltimo acceso. Observe el uso de DateTime.MaxValue, que indica que no existe ninguna regla de caducidad absoluta para este elemento.

Cache.Insert("MyData", Source, null, DateTime.MaxValue, _ TimeSpan.FromMinutes(20))

Resumen de la seccin
1. 2. 3. Es posible almacenar objetos arbitrarios en la cach de datos mediante programacin. La cach de ASP.NET admite caducidad y dependencias. La cach se asigna a una aplicacin y su perodo de vida coincide con el de la aplicacin.

Configuracin

Informacin general sobre la configuracin


Un requisito fundamental de cualquier servidor de aplicaciones Web consiste en la existencia de un sistema de configuracin rico y flexible que permita a los programadores asociar fcilmente valores de configuracin con una aplicacin instalable (sin tener que incluir los valores dentro del cdigo), y a los administradores poder personalizar con facilidad estos valores despus de la distribucin. El sistema de configuracin de ASP.NET se ha diseado para satisfacer las necesidades de ambos colectivos, proporcionando una infraestructura de configuracin jerrquica que permite definir datos de configuracin extensibles y utilizarlos a lo largo de una aplicacin, un sitio o un equipo. Ofrece las siguientes cualidades que le convierten en un producto especialmente apropiado para la creacin y el mantenimiento de aplicaciones Web:

ASP.NET permite almacenar valores de configuracin junto con contenido esttico, pginas dinmicas y objetos empresariales dentro de una nica jerarqua de directorios de la aplicacin. Los usuarios o administradores slo necesitan copiar un nico rbol de directorios para instalar una aplicacin ASP.NET Framework en un equipo. Los datos de configuracin se almacenan en archivos de texto sin formato donde los usuarios pueden leer y escribir perfectamente. Los administradores y los programadores pueden utilizar cualquier editor de textos estndar, analizador XML o lenguaje de secuencias de comandos para interpretar y actualizar los valores de configuracin. ASP.NET proporciona una infraestructura de configuracin extensible que permite a programadores terceros almacenar sus propios valores de configuracin, definir el formato de persistencia de esos valores, participar de forma inteligente en su procesamiento y controlar el modelo de objetos resultante a travs del cual esos valores se exponen en ltima instancia. El sistema detecta automticamente los cambios en los archivos de configuracin de ASP.NET y los aplica sin intervencin del usuario (no es necesario que un administrador reinicie el servidor Web o el equipo para que surtan efecto). Las secciones de configuracin se pueden bloquear mediante la etiqueta <location> y el atributo allowOverride. Para aprender ms sobre el sistema de configuracin de ASP.NET y sobre su funcionamiento, vea Formato de archivos de configuracin y Recuperar configuracin.

Formato del archivo de configuracin


Los archivos de configuracin de ASP.NET son archivos de texto basados en XML (cada uno con el nombre web.config) que pueden aparecer en cualquier directorio de un servidor de aplicaciones ASP.NET. Cada archivo web.config aplica valores de configuracin al directorio en el que se encuentra ubicado y a todos sus subdirectorios virtuales. Los valores de los subdirectorios pueden reemplazar o modificar opcionalmente los valores especificados en sus directorios principales. El archivo de configuracin raz-WinNT\Microsoft.NET\Framework\<version>\machine.config--proporciona valores de configuracin predeterminados para todo el equipo. ASP.NET configura IIS para impedir el acceso directo desde un explorador a los archivos web.config, y as garantizar que sus valores no se hacen pblicos (los intentos de acceso hacen que ASP.NET devuelva el cdigo 403: Acceso prohibido). Durante la ejecucin, ASP.NET utiliza estos archivos de configuracin web.config para calcular jerrquicamente una coleccin exclusiva de valores para cada solicitud de destino URL entrante (estos valores se calculan slo una vez y despus se guardan en cach a lo largo de las solicitudes subsiguientes; ASP.NET vigila automticamente si se producen cambios e invalida la cach si cualquiera de los archivos de configuracin cambia). Por ejemplo, los valores de configuracin para la URL http://myserver/myapplication/mydir/page.aspx se calcularan aplicando los valores del archivo web.config en el siguiente orden:

Configuracin base del equipo. C:\WinNT\Microsoft.NET\Framework\v.1.00\machine.config Sobrescrita por la configuracin del sitio (o la aplicacin de la raz). C:\inetpub\wwwroot\web.config Sobrescrita por la configuracin de la aplicacin. D:\MyApplication\web.config

Sobrescrita por la configuracin del subdirectorio. D:\MyApplication\MyDir\web.config


Si existe un archivo web.config en el directorio raz de un sitio, por ejemplo, "Inetpub\\wwwroot", sus valores de configuracin se utilizarn para todas las aplicaciones de ese sitio. Observe que la presencia de un archivo web.config dentro de un determinado directorio o de la raz de la aplicacin es totalmente opcional. Si no existe un archivo web.config, todos los valores de configuracin para el directorio se heredan automticamente del directorio principal.

Secciones y controladores de secciones de configuracin


Un archivo web.config es un archivo de texto XML que puede contener elementos de documentos XML estndar, incluidos comentarios, texto, etiquetas bien formadas, prrafos cdata, etc. El archivo puede ser ANSI, UTF-8 o Unicode; el sistema detecta automticamente la codificacin. El elemento raz de un archivo web.config es siempre una etiqueta <configuration>. Los valores de ASP.NET y del usuario final se encapsulan entonces dentro de la etiqueta, como se indica a continuacin:

<configuration> <!- Configuration settings would go here. --> </configuration>


La etiqueta <configuration> contiene normalmente tres tipos diferentes de elementos: 1) declaraciones de controladores de secciones de configuracin, 2) grupos de secciones de configuracin y 3) valores de secciones de configuracin.

Controladores de secciones de configuracin - La infraestructura de configuracin de ASP.NET no realiza ninguna suposicin acerca del formato de archivos o de los valores admitidos dentro de un archivo web.config. En vez de ello, delega el procesamiento de los datos de web.config en controladores de secciones de configuracin, que son clases de .NET Framework que implementan la interfaz IConfigurationSectionHandler. Slo es necesario realizar una declaracin individual de IConfigurationSectionHandler normalmente en el archivo machine.config. Los archivos web.config de subdirectorios heredan automticamente esta declaracin. Los controladores de secciones de configuracin se declaran dentro de un archivo web.config mediante directivas de etiquetas de seccin anidadas dentro de una etiqueta <configSections> . Las etiquetas de seccin pueden calificarse con ms detalle mediante etiquetas de grupo que permiten organizarlas en grupos lgicos (vase ms abajo). Cada etiqueta de seccin identifica un nombre de etiqueta que denota una seccin especfica de datos de configuracin y una clase IConfigurationSectionHandler asociada que se encarga de procesarla. Grupos de secciones de configuracin - La configuracin de ASP.NET permite el agrupamiento jerrquico de secciones a efectos de organizacin. Una etiqueta <sectionGroup> puede aparecer dentro de una etiqueta <configSections> o dentro de otras etiquetas <sectionGroup>. Por ejemplo, todos los controladores de secciones de ASP.NET aparecen dentro del grupo de secciones <system.web>. Secciones de configuracin - Los valores de configuracin de ASP.NET se representan dentro de secciones de etiquetas de configuracin, tambin anidadas dentro de una etiqueta <configuration> (y etiquetas de grupos de secciones opcionales). Para cada seccin de configuracin, se debe definir un controlador de seccin apropiado en la jerarqua de configuraciones. En el ejemplo siguiente, la etiqueta <httpModules> es la seccin de configuracin que define los datos de configuracin de mdulos HTTP. La clase System.Configuration.HttpModulesConfigurationHandler es la responsable de interpretar en tiempo de ejecucin el contenido existente dentro de la etiqueta <httpModules>. Observe que tanto la seccin como la definicin del controlador de seccin deben tener el mismo calificador de grupo de secciones (en este caso, <system.web>). Asimismo, tenga en cuenta que en los nombres de etiqueta se distingue entre maysculas y minsculas y, por tanto, deben escribirse exactamente como aparecen. Otros atributos y valores para ASP.NET tambin realizan esa distincin, de modo que, si no se escriben correctamente, el mdulo de ejecucin de configuraciones no los examinar.

<configuration> <configSections> <sectionGroup name="system.web"> <section name="httpModules" type="System.Web.Configuration.HttpModulesConfigurationHandler,System.Web" /> </sectionGroup> </configSections> <system.web> <httpModules> <add name="CookielessSession" type="System.Web.SessionState.CookielessSessionModule,System.Web" /> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule,System.Web" /> <add name="Session" type="System.Web.SessionState.SessionStateModule,System.Web" />

<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule,System.Web" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule,System.Web" /> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule,System.Web" /> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule,System.Web" /> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule,System.Web" /> </httpModules> </system.web> </configuration>

Utilizar Location y Path


De forma predeterminada, todos los valores de configuracin definidos dentro de la etiqueta <configuration> de nivel superior se aplican a la ubicacin del directorio actual que contiene el archivo web.config y a todos sus subdirectorios. Opcionalmente, se pueden aplicar valores de configuracin a subdirectorios especficos por debajo del archivo de configuracin actual mediante la etiqueta <location> y un atributo restrictivo path apropiado. Si el archivo de configuracin es el archivo principal machine.config, se pueden aplicar valores a aplicaciones o directorios virtuales especficos. Si el archivo de configuracin es un archivo web.config, se pueden aplicar valores a un archivo, subdirectorio, directorio virtual o aplicacin especficos.

<configuration> <location path="EnglishPages"> <system.web> <globalization requestEncoding="iso-8859-1" responseEncoding="iso-8859-1" /> </system.web> </location> <location path="EnglishPages\OneJapanesePage.aspx"> <system.web> <globalization requestEncoding="Shift-JIS" responseEncoding="Shift-JIS" /> </system.web> </location> </configuration>

Bloquear valores de configuracin


Adems de especificar la informacin de la ruta de acceso mediante la etiqueta <location> tambin se pueden establecer medidas de seguridad para que los valores no sean reemplazados por otro archivo de configuracin situado ms abajo en la jerarqua de configuraciones. Para bloquear un grupo de valores, se puede especificar un atributo allowOverride con el valor false, en la etiqueta <location> que los engloba. El siguiente cdigo bloquea valores de suplantacin de identidad para dos aplicaciones diferentes.

<configuration> <location path="app1" allowOverride="false"> <system.web> <identity impersonate="false" userName="app1" password="app1pw" />

</system.web> </location> <location path="app2" allowOverride="false"> <system.web> <identity impersonate="false" userName="app2" password="app2pw" /> </system.web> </location> </configuration>
Observe que si un usuario intenta reemplazar estos valores en otro archivo de configuracin, el sistema de configuracin indicar un error:

<configuration> <system.web> <identity userName="developer" password="loginpw" /> </system.web> </configuration>

Seccin de configuracin ASP.NET estndar


ASP.NET se suministra con una serie de controladores estndar de secciones de configuracin para procesar los valores de configuracin de los archivos web.config. La siguiente tabla proporciona una breve descripcin de las secciones junto con referencias para obtener ms informacin. Nombre de seccin Descripcin <httpModules> Se encarga de configurar mdulos HTTP dentro de una aplicacin. Los mdulos HTTP participan en el procesamiento de todas las solicitudes en una aplicacin. Entre los usos ms habituales, se incluyen la seguridad y el inicio de sesin. Se encarga de asignar direcciones URL de entrada a clases IHttpHandler. Los subdirectorios no heredan estos valores. Tambin es responsable de asignar direcciones URL de entrada a clases IHttpHandlerFactory. Los datos representados en secciones <httpHandlers> son heredados jerrquicamente por subdirectorios. Para obtener ms informacin, vea la seccin Factoras y controladores Http de este tutorial. Se encarga de configurar el mdulo HTTP de estado de sesin. Para obtener ms informacin, vea la seccin Administrar el estado de la aplicacin de este tutorial. Se encarga de configurar los valores de globalizacin de una aplicacin. Para obtener ms informacin, vea la seccin Localizacin de este tutorial. Es responsable de todos los valores de compilacin utilizados por ASP.NET. Para obtener ms informacin, vea las secciones Objetos empresariales y Depuracin de este tutorial. Se encarga de configurar el servicio de seguimiento de ASP.NET. Para obtener ms informacin, vea la seccin Seguimiento de este tutorial. Se encarga de configurar los valores del modelo de proceso de ASP.NET en sistemas de servidores Web de IIS. Es responsable del control de los valores del componente de funcionalidad de explorador. Para obtener ms informacin, vea la seccin Recuperar configuracin de este tutorial.

<httpHandlers>

<sessionState> <globalization> <compilation>

<trace> <processModel> <browserCaps>

Recuperar configuracin
ASP.NET permite a los programadores obtener acceso a los valores de configuracin desde una aplicacin, ya sea exponiendo los valores de configuracin directamente (como propiedades con un fuerte control de tipos) o mediante determinadas API de configuracin generales. El siguiente ejemplo muestra una pgina que proporciona acceso a la seccin de configuracin <browserCaps> mediante la propiedad Browser de la clase System.Web.HttpRequest. Se trata de una tabla hash de atributos que refleja las capacidades del explorador que est actualmente obteniendo acceso a la pgina. Los datos reales de la seccin <browserCaps> se incluyen en el archivo machine.config.

<%@ Page Language="VB" %>

<html> <body style="font: 10pt verdana"> <h3>Recuperar funciones del explorador</h3> Boolean ActiveXControls = <%=Request.Browser.ActiveXControls.ToString()%><br> Boolean AOL = <%=Request.Browser.AOL.ToString()%><br> Boolean BackgroundSounds = <%=Request.Browser.BackgroundSounds.ToString()%><br> Boolean Beta = <%=Request.Browser.Beta.ToString()%><br> String Browser = <%=Request.Browser.Browser%><br> Boolean CDF = <%=Request.Browser.CDF.ToString()%><br> Boolean Cookies = <%=Request.Browser.Cookies.ToString()%><br> Boolean Crawler = <%=Request.Browser.Crawler.ToString()%><br> Boolean Frames = <%=Request.Browser.Frames.ToString()%><br> Boolean JavaApplets = <%=Request.Browser.JavaApplets.ToString()%><br> Boolean JavaScript = <%=Request.Browser.JavaScript.ToString()%><br> Int32 MajorVersion = <%=Request.Browser.MajorVersion.ToString()%><br> Double MinorVersion = <%=Request.Browser.MinorVersion.ToString()%><br> String Platform = <%=Request.Browser.Platform%><br> Boolean Tables = <%=Request.Browser.Tables.ToString()%><br> String Type = <%=Request.Browser.Type%><br> Boolean VBScript = <%=Request.Browser.VBScript.ToString()%><br> String Version = <%=Request.Browser.Version%><br> Boolean Win16 = <%=Request.Browser.Win16.ToString()%><br> Boolean Win32 = <%=Request.Browser.Win32.ToString()%><br> </body> </html>

Adems de obtener acceso a los valores de configuracin, los programadores tambin pueden utilizar la clase System.Configuration.ConfigurationSettings para recuperar los datos de cualquier seccin de configuracin. Observe que el objeto particular devuelto por ConfigurationSettings depende del controlador asociado a la seccin de configuracin (vea IConfigurationSectionHandler.Create). El siguiente cdigo muestra cmo se puede obtener acceso a los datos de configuracin expuestos para una seccin <customconfig>. En este ejemplo, se supone que el controlador de la seccin de configuracin devuelve un objeto de tipo CustomConfigSettings con la propiedad Enabled.

Dim config As CustomConfigSettings = CType(ConfigurationSettings("customconfig"), CustomConfigSettings) If config.Enabled = True Then ' Do something here. End If

Utilizar valores de aplicaciones


Los archivos de configuracin son perfectamente apropiados para almacenar valores de aplicaciones personalizados, tales como cadenas de conexin con bases de datos, rutas de acceso a archivos o direcciones URL de servicios Web de XML remotos. Entre las secciones de configuracin predeterminadas (definidas en el archivo machine.config), se incluye una seccin <appSettings> que se puede utilizar para almacenar estos valores como pares nombre/valor. En el siguiente ejemplo, se muestra una seccin de configuracin <appSettings> que define cadenas de conexin con bases de datos para una aplicacin.

<configuration> <appSettings> <add key="pubs" value="server=(local)\NetSDK;database=pubs;Trusted_Connection=yes" /> <add key="northwind" value="server=(local)\NetSDK;database=northwind;Trusted_Connection=yes" /> </appSettings> </configuration>
El objeto ConfigurationSettings expone una propiedad AppSettings especial que se puede utilizar para recuperar esos valores:

Dim dsn As String = ConfigurationSettings.AppSettings("pubs")

El siguiente ejemplo ilustra esta tcnica.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ Import Namespace="System.Configuration" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim dsn As String = ConfigurationSettings.AppSettings("pubs") Dim MyConnection As SqlConnection Dim MyCommand As SqlDataAdapter MyConnection = New SqlConnection(DSN) MyCommand = New SqlDataAdapter("select * from Authors", MyConnection) Dim DS As New DataSet MyCommand.Fill(DS, "Authors") MyDataGrid.DataSource= New DataView(DS.Tables(0)) MyDataGrid.DataBind() End Sub </script> <body> <h3><font face="Verdana">Recuperar datos sobre la configuracin</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd" /> </body> </html>

Implementacin

Distribuir aplicaciones ASP.NET Diseo del sistema de archivos de las aplicaciones ASP.NET

Se puede utilizar ASP.NET para albergar mltiples aplicaciones Web, cada una identificada mediante un prefijo URL nico dentro de un sitio Web (un sitio Web se representa en un servidor Web como una combinacin NombreDeHost/Puerto). Por ejemplo, un nico servidor Web de Microsoft Internet Information Services (IIS) con dos direcciones IP (una con alias "www.msn.com" y otra "intranet") y tres sitios lgicos (http://intranet, http://www.msn.com, http://www.msn.com port 81) podra exponer las siguientes seis aplicaciones ASP.NET. URL de la aplicacin http://intranet http://www.msn.com http://www.msn.com:81 http://intranet/training http://intranet/hr http://intranet/hr/compensation/ Descripcin Aplicacin "Root" del sitio de la intranet. Aplicacin "Root" en el sitio www.msn.com. Aplicacin "Root" en el sitio www.msn.com, puerto 81. Aplicacin "training" del sitio de la intranet. Aplicacin "HR" del sitio de la intranet. Aplicacin "Compensation" del sitio de la intranet.

Nota: la URL de la aplicacin "compensation" mencionada en la tabla est arraigada dentro del espacio de nombres de la URL de la aplicacin HR. No obstante, esta notacin jerrquica de URL no implica que la aplicacin "compensation" se encuentre incluida o anidada dentro de la aplicacin HR. Cada aplicacin ASP.NET Framework expuesta en un espacio de nombres de URL est respaldada por un directorio del sistema de archivos ubicado en un recurso compartido local o remoto. Los directorios de aplicaciones no necesitan estar ubicados centralmente en una parte contigua del sistema de archivos; pueden estar esparcidos por todo un disco. Por ejemplo, las aplicaciones ASP.NET mencionadas anteriormente podran estar ubicadas en los diferentes directorios que aparecen en la tabla siguiente. URL de la aplicacin http://intranet http://www.msn.com http://www.msn.com:81 http://intranet/training http://intranet/hr http://intranet/hr/compensation/ Ruta de acceso fsica c:\inetpub\wwwroot c:\inetpub\msnroot d:\msnroot81 d:\serverapps\trainingapp \\hrweb\sillystuff\reviews c:\inetpub\wwwroot\compensation

Resolver referencias de clases en ensamblados


Los ensamblados constituyen la unidad de implementacin de clases en Common Language Runtime. Los programadores que escriben clases de .NET Framework utilizando la versin 7.0 de Visual Studio .NET producen un nuevo ensamblado con cada proyecto de Visual Studio que compilan. Aunque es posible hacer que un ensamblado ocupe varios archivos ejecutables portables (PE) (varias DLL de mdulos), Visual Studio .NET compilar, de forma predeterminada, todo el cdigo del ensamblado en una nica DLL (1 proyecto de Visual Studio .NET = 1 ensamblado de .NET Framework = 1 DLL fsica). Para utilizar un ensamblado en un equipo, se debe implementar en una cach de ensamblado. La cach de ensamblado puede ser global para un equipo o local para una aplicacin determinada. En la cach de ensamblado global del sistema, slo debera colocarse el cdigo que se va a compartir entre varias aplicaciones. El cdigo especfico para una aplicacin particular, como la lgica de la mayora de las aplicaciones Web, se debera implementar en la cach de ensamblado local de la aplicacin. Una de las ventajas de distribuir un ensamblado en la cach de ensamblado local de una aplicacin es que slo el cdigo interno de esa aplicacin puede tener acceso a l. (Se trata de una caracterstica muy apreciada para escenarios en los que intervienen proveedores de servicios de Internet). Tambin facilita la creacin conjunta de versiones de la misma aplicacin, ya que las clases son privadas para cada instancia de versin de la aplicacin. Un ensamblado se puede distribuir en la cach de ensamblado local de una aplicacin simplemente copiando (o utilizando XCOPY o FTP) los archivos apropiados en un directorio marcado como "ubicacin para la cach de ensamblado" de esa determinada aplicacin. No es necesario ejecutar ninguna herramienta de registro adicional una vez copiados los archivos apropiados y tampoco es necesario reiniciar el equipo. Esto elimina algunas de las dificultades actualmente asociadas a la distribucin de componentes COM dentro de aplicaciones ASP (actualmente, un administrador debe iniciar sesin localmente en el servidor Web y ejecutar Regsvr32.exe). De forma predeterminada, una aplicacin ASP.NET Framework se configura automticamente para utilizar el subdirectorio \\bin, ubicado inmediatamente bajo la raz de la aplicacin, como su cach de ensamblado local. El directorio \\bin tambin est configurado para denegar cualquier acceso de un explorador Web, de modo que un cliente remoto no pueda descargar el cdigo y apropiarse del mismo. El siguiente ejemplo muestra una posible distribucin de directorios para una aplicacin de ASP.NET, donde el directorio \bin se encuentra justo debajo de la raz de la aplicacin.

C:\inetpub\wwwroot Web.cfg Default.aspx \bin <= Application assembly cache directory MyPages.dll

MyBizLogic.dll \order SubmitOrder.aspx OrderFailed.aspx \img HappyFace.gif

Inicio de aplicaciones ASP.NET Framework y resolucin de clases


Las aplicaciones ASP.NET Framework se construyen lentamente la primera vez que un cliente solicita un recurso URL de ellas. Cada aplicacin ASP.NET Framework se lanza dentro de un dominio de aplicacin exclusivo (AppDomain), que consiste en una nueva construccin de Common Language Runtime que permite a los hosts de procesos ofrecer cdigo extensivo, seguridad y aislamiento de configuraciones durante la ejecucin. ASP.NET se encarga de crear manualmente un dominio de aplicaciones cuando se inicia una nueva aplicacin. Como parte de este proceso, ASP.NET proporciona valores de configuracin para que Common Language Runtime los utilice. Entre estos valores de configuracin, se incluyen:

Las rutas de acceso a directorios que componen la cach de ensamblado local. (Nota: es la arquitectura de aislamiento de dominios para aplicaciones de .NET Framework la que permite a cada aplicacin mantener su propia cach de ensamblado local). Las restricciones de seguridad de la aplicacin (donde puede tener acceso la aplicacin en el sistema). Como ASP.NET no tiene conocimiento, en tiempo de compilacin, de las aplicaciones que se escriben por encima de l, no puede utilizar referencias estticas para resolver y hacer referencia al cdigo de las aplicaciones. En vez de ello, ASP.NET debe utilizar un enfoque de resolucin dinmico de clases y ensamblados para realizar la transicin del mdulo de ejecucin de ASP.NET al cdigo de aplicacin. Los archivos de activacin de pgina y configuracin de ASP.NET permiten hacer referencia dinmicamente a una clase de .NET Framework compilada para un objetivo especificando una combinacin de nombre de clase y ensamblado. El formato de cadena para esta unin sigue el modelo classname, assemblyname . Llegados a este punto, Common Language Runtime puede utilizar esta referencia simple de cadena para resolver y cargar la clase apropiada.

Sustitucin de cdigo
Los ensamblados de .NET Framework normalmente se compilan y distribuyen en un formato PE basado en DLL de Windows. Cuando el cargador de Common Language Runtime resuelve una clase implementada con este tipo de ensamblado, llama a la rutina LoadLibrary de Windows en el archivo (la cual bloquea su acceso en disco) y, a continuacin, asigna los datos de cdigo en memoria apropiados para la ejecucin. Una vez cargado, el archivo DLL permanece bloqueado en disco hasta que el dominio de aplicacin que hace referencia a l se destruye o se recicla manualmente. Aunque ASP.NET no puede impedir que Common Language Runtime bloquee una DLL de ensamblado en disco, s puede garantizar que el mdulo de ejecucin no cargue nunca realmente las DLL fsicas en la cach de ensamblado privada de una aplicacin Web. En vez de ello, se realizan copias en servidores de copia de seguridad de las DLL de ensamblados inmediatamente antes de su uso. El mdulo de ejecucin bloquea y carga entonces estos ensamblados del servidor de copia de seguridad (no los archivos originales). Como los archivos de ensamblado originales siempre permanecen desbloqueados, existe la libertad de eliminarlos, reemplazarlos o cambiar su nombre sin activar el servidor Web o tener que usar una utilidad de registro. FTP y los mtodos similares funcionan sin problemas. ASP.NET mantiene una lista activa de todos los ensamblados cargados dentro del dominio de una aplicacin particular y utiliza cdigo de supervisin de cambio de archivos para detectar cualquier actualizacin en los archivos originales.

Resumen de la seccin
1. Las aplicaciones ASP.NET Framework se identifican mediante una URL nica y residen en el sistema de archivos del servidor Web. 2. ASP.NET puede utilizar ensamblados compartidos, los cuales residen en la cach global, y ensamblados especficos de la aplicacin, que residen en el directorio \bin de la raz virtual de la aplicacin. 3. Las aplicaciones ASP.NET Framework se ejecutan en el contexto de dominios de aplicaciones (AppDomains), los cuales proporcionan aislamiento e imponen restricciones de seguridad. 4. Se puede hacer referencia a las clases dinmicamente especificando "nombre de clase, nombre de ensamblado". 5. ASP.NET utiliza copias de servidor de copia de seguridad de archivos de ensamblado para evitar bloqueos y supervisa los archivos para que los cambios se detecten inmediatamente.

Utilizar el modelo de procesos

Uno de los requisitos ms importantes de las aplicaciones ASP.NET Framework es la fiabilidad. La arquitectura de las aplicaciones que se ejecutan dentro del proceso de servidor (en IIS, Inetinfo.exe) no ofrece una base slida para crear aplicaciones fiables que puedan ejecutarse sin problemas durante perodos prolongados de tiempo. Se comparten demasiados recursos en el nivel de procesos y es muy fcil que un error interrumpa todo el proceso de servidor. Para solucionar este problema, ASP.NET proporciona un modelo de ejecucin fuera de proceso, que protege al proceso de servidor del cdigo de usuario. Tambin permite aplicar tcnicas heursticas a la duracin del proceso para mejorar la disponibilidad de las aplicaciones Web. El uso de comunicaciones asincrnicas entre procesos permite proporcionar el mejor equilibrio entre rendimiento, escalabilidad y fiabilidad.

Configuracin del modelo de procesos


La configuracin del modelo de procesos se expone en el archivo de configuracin raz del equipo, Machine.config. La seccin de configuracin se denomina <processModel> y se muestra en el ejemplo siguiente. El modelo de procesos est habilitado de forma predeterminada (enable="true").

<processModel enable="true" timeout="infinite" idleTimeout="infinite" shutdownTimeout="0:00:05" requestLimit="infinite" requestQueueLimit="5000" memoryLimit="80" webGarden="false" cpuMask="0xffffffff" userName="" password="" logLevel="errors" clientConnectedCheck="0:00:05" />
La mayora de los valores de configuracin controlan el inicio de un nuevo proceso de trabajo para atender solicitudes (reemplazando discretamente un proceso de trabajo antiguo). El modelo de procesos admite dos tipos de reciclaje: reactivo y proactivo.

Reciclaje reactivo de procesos


El reciclaje reactivo de procesos se produce cuando un proceso funciona incorrectamente o no puede atender solicitudes. El proceso suele mostrar sntomas que se pueden detectar, como bloqueos, infracciones de acceso, fugas de memoria, etc., para desencadenar su reciclaje. Es posible controlar las condiciones que desencadena el reinicio de un proceso mediante los valores de configuracin descritos en la tabla siguiente. Valor requestQueueLimit Descripcin Controla las condiciones de bloqueo. El valor DWORD se establece en el nmero mximo permitido de solicitudes en cola que, una vez superado, hace que se considere que el proceso de trabajo funciona incorrectamente. Cuando se supera este nmero, se inicia un proceso nuevo y se reasignan las solicitudes. El valor predeterminado es de 5.000 solicitudes. Controla las condiciones de prdida de memoria. El valor DWORD se establece en el porcentaje de memoria fsica que puede consumir el proceso de trabajo antes de que se considere que funciona incorrectamente. Cuando se supera este porcentaje, se inicia un proceso nuevo y se reasignan las solicitudes. El valor predeterminado es el 80%. Especifica el intervalo de tiempo del que dispone el proceso de trabajo para cerrarse discretamente (valor de tipo cadena, con el formato hr:min:seg). Cuando se agote el tiempo de espera, la API de servicios de Internet de ASP.NET cerrar el proceso de trabajo. El valor predeterminado es "00:00:05".

memoryLimit

shutdownTimeout

Reciclaje proactivo de procesos


El reciclaje proactivo de procesos reinicia peridicamente el proceso de trabajo, aunque ste funcione correctamente. Esto puede ser una forma til de evitar la denegacin de servicio a causa de condiciones que no puede detectar el modelo de procesos. Es posible reiniciar un proceso despus de un nmero determinado de solicitudes o cuando haya transcurrido un tiempo de espera. Valor timeout Descripcin Valor de tipo cadena, con el formato hr:min:seg, que configura el lmite de tiempo que, una vez transcurrido, hace que se inicie un nuevo proceso de trabajo para reemplazar al actual. El valor

predeterminado es infinite, una palabra clave que indica que no se debe reiniciar el proceso. idleTimeout Valor de tipo cadena, con el formato hr:min:seg, que configura el tiempo de inactividad que, una vez transcurrido, hace que se cierre automticamente el proceso de trabajo. El valor predeterminado es infinite, una palabra clave que indica que no se debe reiniciar el proceso. El valor DWORD se establece en el nmero de solicitudes que pueden producirse antes de que se inicie un nuevo proceso de trabajo para reemplazar al actual. El valor predeterminado es infinite, una palabra clave que indica que no se debe reiniciar el proceso.

requestLimit

Registrar eventos del modelo de procesos


El modelo de procesos puede escribir eventos en el registro de eventos de Windows cuando se realice el cambio de proceso. Esto se controla mediante el atributo logLevel en la seccin de configuracin <processModel>. Valor logLevel Descripcin Controla el registro de eventos de cambio de proceso en el registro de eventos. El valor puede ser:

Todos: se registran todos los eventos de cambio de proceso. Ninguno: no se registra ningn evento. Errores: slo se registran los eventos inesperados.

Cuando se produce un evento de cambio, si el registro est habilitado para el evento, se escriben los siguientes eventos en el registro de eventos de la aplicacin. Tipo de registro de eventos Error Error Informacin Informacin Informacin Error

Razn del cierre Inesperado requestQueueLimit RequestLimit Timeout IdleTimeout MemoryLimitExceeded

Descripcin El proceso de trabajo de ASP.NET se cerr de forma inesperada . Se reinici el proceso de trabajo de ASP.NET porque se super el lmite de la cola de solicitudes. Se reinici el proceso de trabajo de ASP.NET porque se super el lmite de solicitudes. Se reinici el proceso de trabajo de ASP.NET porque se super el intervalo de tiempo de espera. Se cerr el proceso de trabajo de ASP.NET porque se super el intervalo de tiempo de espera de inactividad. Se reinici el proceso de trabajo de ASP.NET porque se super el lmite de memoria del proceso.

Habilitar unidades Web


El modelo de procesos permite habilitar la escalabilidad en equipos con varios procesadores mediante la distribucin del trabajo entre varios procesos, uno por cada CPU, con la afinidad de procesador establecida en la CPU correspondiente. Esto elimina la contencin de bloqueos entre procesadores, por lo que es ideal para grandes sistemas de multiprocesamiento simtrico (SMP). Esta tcnica se conoce como uso de unidades Web. Los valores de configuracin necesarios para habilitar unidades Web se muestran en la tabla siguiente. Tenga en cuenta que esta configuracin slo surtir efecto despus de reiniciar el servidor. Es necesario reciclar IIS para que el cambio surta efecto. Valor webGarden cpuMask Descripcin Controla la afinidad CPU. True indica que es necesario asignar a los procesos la afinidad correspondiente a la CPU. El valor predeterminado es False. Controla el nmero de procesos y el funcionamiento de la unidad Web. Se inicia un proceso para cada CPU en la que el bit correspondiente de la mscara est establecido en 1. Cuando se establece el valor de UseCPUAffinity en 0, el valor de cpuMask slo controla el nmero de procesos de trabajo (nmero de bits establecidos en 1). El nmero mximo permitido de procesos de trabajo es el nmero de CPU. De forma predeterminada, todas las CPU estn habilitadas y se iniciarn tantos procesos de trabajo como CPU haya en el equipo. El valor predeterminado es 0xffffffff.

El uso de unidades Web produce algunos efectos secundarios que hay que tener en cuenta:

Si la aplicacin utiliza el estado de sesin, debe elegir un proveedor fuera de proceso (servicio de Windows NT o SQL). Para cada proceso se miden tanto el estado de la aplicacin como las estadsticas de la aplicacin y no para cada equipo. El almacenamiento en cach se realiza para cada proceso, no para cada equipo.

Resumen de la seccin
1. ASP.NET proporciona un modelo de ejecucin fuera de proceso, que protege al proceso de servidor del cdigo de usuario. Tambin permite aplicar tcnicas heursticas a la duracin del proceso para mejorar la disponibilidad global de las aplicaciones Web.

2.

La configuracin de <processModel> se expone en el archivo raz de configuracin del equipo, Machine.config. El modelo de procesos est habilitado de forma predeterminada. 3. El modelo de procesos admite dos tipos de reciclaje: reactivo y proactivo. El reciclaje reactivo de procesos se produce cuando un proceso funciona incorrectamente o no puede atender solicitudes. El reciclaje proactivo de procesos reinicia peridicamente el proceso de trabajo, aunque ste funcione correctamente.

4.

El modelo de procesos puede escribir eventos en el registro de eventos de Windows cuando se realice el cambio de proceso. Esto se controla mediante el atributo de registro en la seccin de configuracin <processModel>. 5. El modelo de procesos permite habilitar la escalabilidad en equipos con varios procesadores mediante la distribucin del trabajo entre varios procesos, uno por cada CPU, con la afinidad de procesador establecida en la CPU correspondiente. Esta tcnica se conoce como uso de unidades Web.

Controlar errores

Cuando se produce un error en una pgina, ASP.NET enva informacin sobre el error al cliente. Los errores se dividen en cuatro categoras:

Errores de configuracin: se producen cuando la sintaxis o la estructura de un archivo Web.config de la jerarqua de configuracin es incorrecta. Errores del analizador: se producen cuando la sintaxis ASP.NET de una pgina no est bien formada. Errores de compilacin: se producen cuando las instrucciones del lenguaje de destino de una pgina son incorrectas. Errores de tiempo de ejecucin: se producen durante la ejecucin de una pgina, incluso aunque los errores no se detectaran en tiempo de compilacin. De forma predeterminada, la informacin mostrada para un error de tiempo de ejecucin consiste en la pila de llamadas (las cadenas de llamadas a procedimientos que condujeron hasta la excepcin). Si el modo de depuracin se encuentra habilitado, ASP.NET muestra el nmero de lnea del cdigo fuente donde se origin el error en tiempo de ejecucin. El modo de depuracin es una herramienta muy valiosa para depurar la aplicacin. Es posible habilitar el modo de depuracin a nivel de pgina, mediante la siguiente directiva:

<%@ Page Debug="true" %>


Tambin se puede habilitar el modo de depuracin en el mbito de la aplicacin, mediante el archivo Web.config del directorio raz de la aplicacin, como se indica en el siguiente ejemplo. Nota: activar el modo de depuracin implica una penalizacin del rendimiento. Asegrese de desactivarlo antes de implementar la aplicacin final. El siguiente ejemplo muestra el uso del modo de depuracin para obtener los nmeros de lnea de una excepcin en tiempo de ejecucin.

<%@ Debug="true"%> <html> <script language="VB" runat="server"> ' Setting Debug to true causes lines numbers to be printed for runtime errors ' Enable this at the Page or Application level while developing ' Be sure to disable before deploying to a production site Sub Error_500(sender As Object, e As EventArgs) Dim foo As String = Nothing Response.Write(foo.ToString()) End Sub </script>

<body> <form runat="server"> <h4><font face="verdana">Produce un error...</font></h4> <asp:button text="500 Error del servidor" OnClick="Error_500" width="150" runat="server"/><p> </form> </body> </html>
Nota: slo los archivos asignados con la extensin aspnet_isapi.dll en IIS generan estos errores. ASP.NET no procesa los archivos no atendidos por medio de aspnet_isapi.dll, estos archivos generan errores de IIS. Vea la documentacin de IIS para obtener informacin sobre cmo configurar errores personalizados de IIS. La tabla siguiente describe los atributos de configuracin y los valores para la etiqueta <customerrors>. Atributo Modo DefaultRedirect Descripcin Indica si los errores personalizados estn habilitados, deshabilitados o slo se muestran a equipos remotos. Valores: On, Off, RemoteOnly (predeterminado). Indica la URL predeterminada a la que se debe desviar a un explorador Web si se produce un error. Este atributo es opcional.

El atributo Mode determina si los errores se van a mostrar a clientes locales, remotos o a ambos. Los efectos de cada opcin se describen en la siguiente tabla. Modo On Off RemoteOnly Solicitud de host local Pgina de errores personalizada. Pgina de errores de ASP.NET. Pgina de errores de ASP.NET. Solicitud de host remoto Pgina de errores personalizada. Pgina de errores de ASP.NET. Pgina de errores personalizada.

El siguiente ejemplo muestra cmo se utiliza la seccin de configuracin <customerrors>.

<html> <script language="VB" runat="server"> Sub Error_500(sender As Object, e As EventArgs) Dim foo As String = Nothing Response.Write(foo.ToString()) End Sub </script> <body> <form runat="server"> <h4><font face="verdana">Produce un error...</font></h4> <asp:button text="500 Error del servidor" OnClick="Error_500" width="150" runat="server"/><p> </form> </body> </html>
Adems de desviar a una pgina comn cuando se produce cualquier error, tambin se pueden asignar pginas de error especficas a cdigos de estado de error especficos. La seccin de configuracin <customerrors> admite una etiqueta <error> interna que asocia cdigos de estado HTTP con pginas de error personalizadas. Por ejemplo:

<configuration> <system.web> <customErrors mode="RemoteOnly" defaultRedirect="/genericerror.htm"> <error statusCode="500" redirect="/error/callsupport.htm"/> <error statusCode="404" redirect="/error/notfound.aspx"/> <error statusCode="403" redirect="/error/noaccess.aspx"/>

</customErrors> </system.web> </configuration>

La tabla siguiente describe los atributos y valores de la etiqueta <error>. Atributo StatusCode Redirect Descripcin Cdigo de estado HTTP de los errores para los cuales se debera utilizar la pgina de errores personalizada. Ejemplos: 403 Prohibido, 404 No encontrado o 500 Error interno del servidor. URL a la que se debe desviar a un explorador cliente si se produce un error.

El ejemplo siguiente muestra cmo utilizar la etiqueta <error>. Observe que el ejemplo especifica una pgina .aspx para errores de "Archivo no encontrado" con el fin de que la URL de la pgina que falta y que se pasa por medio de QueryString se pueda imprimir.

<html> <script language="VB" runat="server"> Sub Error_404(sender As Object, e As EventArgs) Response.Redirect("nowhere.aspx") End Sub Sub Error_500(sender As Object, e As EventArgs) Dim foo As String = Nothing Response.Write(foo.ToString()) End Sub </script> <body> <form runat="server"> <h4><font face="verdana">Produce un error...</font></h4> <asp:button text="404 No encontrado" OnClick="Error_404" width="150" runat="server"/><p> <asp:button text="500 Error del servidor" OnClick="Error_500" width="150" runat="server"/><p> </form> </body> </html>

Controlar errores mediante programacin

Los errores tambin se pueden tratar en el cdigo, ya sea en el mbito de la pgina o de la aplicacin. La clase base Page expone un mtodo Page_Error que se puede reemplazar en las pginas. Se invoca al mtodo siempre que una excepcin no capturada se lanza en tiempo de ejecucin.

<script language="C#" runat="server"> Sub Page_Error(Source As Object, E As EventArgs) Dim message As String = "<font face=verdana color=red>" _ & "<h4>" & Request.Url.ToString() & "</h4>" _ & "<pre><font color='red'>" & Server.GetLastError().ToString() & "</pre>" _ & "</font>" Response.Write(message) End Sub </script>
El siguiente ejemplo muestra el mtodo Page_Error.

<html> <script language="VB" runat="server"> Sub Error_500(sender As Object, e As EventArgs) Dim foo As String = Nothing Response.Write(foo.ToString()) End Sub Sub Page_Error(sender As Object, e As EventArgs) Dim message As String = "<font face=verdana color=red>" _ & "<h4>" & Request.Url.ToString() & "</h4>" _ & "<pre><font color='red'>" & Server.GetLastError().ToString() & "</pre>" _ & "</font>" Response.Write(message) Server.ClearError() End Sub </script> <body> <form runat="server"> <h4><font face="verdana">Produce un error...</font></h4> <asp:button text="500 Error del servidor" OnClick="Error_500" width="150" runat="server"/><p> </form> </body> </html>
En el mtodo se puede hacer algo til, como enviar un mensaje al administrador del sitio avisndole de que la pgina no se ejecut correctamente. ASP.NET proporciona un conjunto de clases en el espacio de nombres System.Web.Mail precisamente para este propsito. Para importar este espacio de nombres, utilice una directiva @Import en la parte superior de la pgina, como se indica a continuacin:

<%@ Import Namespace="System.Web.Mail" %>

Se pueden utilizar entonces los objetos MailMessage y SmtpMail para enviar mensajes de correo electrnico mediante programa.

Dim mail As New MailMessage mail.From = "automated@contoso.com" mail.To = "administrator@contoso.com" mail.Subject = "Site Error" mail.Body = message mail.BodyFormat = MailFormat.Html SmtpMail.Send(mail)
El siguiente ejemplo muestra cmo enviar un mensaje de correo en respuesta a un error de pgina.

Nota: este ejemplo no enva correo realmente a menos que haya configurado el servicio de correo SMTP en la mquina. Para obtener ms informacin acerca del servicio de correo SMTP, consulte la documentacin IIS.

<%@ Import Namespace="System.Web.Mail" %> <html> <script language="VB" runat="server"> Sub Error_500(sender As Object, e As EventArgs) Dim foo As String = Nothing Response.Write(foo.ToString())

End Sub Sub Page_Error(Sender As Object, E As EventArgs) Dim message As String = "<font face=verdana color=red>" _ & "<h4>" & Request.Url.ToString() & "</h4>" _ & "<pre><font color=red>" & Server.GetLastError().ToString() & "</pre>" _ & "</font>" Response.Write(message) Response.Write("Error en el servidor, se notific al administrador del sitio.") Dim mail As New MailMessage mail.From = "automated@contoso.com" mail.To = "administrator@contoso.com" mail.Subject = "Error del sitio" mail.Body = message mail.BodyFormat = MailFormat.Html SmtpMail.Send(mail) Server.ClearError() End Sub </script> <body> <form runat="server"> <h4><font face="verdana">Produce un error...</font></h4> <asp:button text="500 Error del servidor" OnClick="Error_500" width="150" runat="server"/><p> </form> </body> </html>
Adems de tratar los errores en el mbito de la pgina, se pueden tratar tambin en el mbito de la aplicacin. Para ello, utilice el evento Application_Error de Global.asax. Este evento tiene lugar para cualquier excepcin sin tratamiento que se produce dentro de la aplicacin.

Sub Application_Error(sender As Object, e As EventArgs) '...Do something here End Sub

Escribir en el Registro de eventos

El espacio de nombres System.Diagnostics proporciona clases para escribir en el Registro de eventos de Windows. Para utilizar este espacio de nombres en las pginas, primero hay que importar el espacio de nombres como se indica a continuacin:

<%@ Import Namespace="System.Diagnostics"%>


La clase EventLog encapsula el propio Registro. Proporciona mtodos estticos para detectar o crear registros y puede crearse una instancia para escribir entradas de registro desde el cdigo. El siguiente ejemplo muestra esta funcionalidad dentro del mtodo Application_Error de Global.asax. Siempre que se produce una excepcin sin tratamiento en la aplicacin, se crea una entrada con el mensaje de error y el estado de la pila en el registro de la aplicacin.

Sub Application_Error(sender As Object, e As EventArgs) Dim Message As String = "\n\nURL:\n http://localhost/" & Request.Path _ & "\n\nMESSAGE:\n " & Server.GetLastError().Message _ & "\n\nSTACK TRACE:\n" & Server.GetLastError().StackTrace ' Create event log if it does not exist

Dim LogName As String = "Application" If (Not EventLog.SourceExists(LogName)) EventLog.CreateEventSource(LogName, LogName) End If ' Insert into event log Dim Log As New EventLog Log.Source = LogName Log.WriteEntry(Message, EventLogEntryType.Error) End Sub
El cdigo fuente completo para el ejemplo anterior aparece a continuacin. Observe que este cdigo est deshabilitado para que no se pueda ejecutar y evitar as entradas en el Registro de eventos de Windows. Si quiere ver cmo se ejecuta este cdigo, cree una raz virtual IIS que apunte al directorio que contiene este archivo.

<%@ Import Namespace="System.Diagnostics" %> <script language="VB" runat="server"> Sub Application_Error(sender As Object, e As EventArgs) Dim Message As String = "\n\nURL:\n http://localhost/" & Request.Path _ & "\n\nMESSAGE:\n " & Server.GetLastError().Message _ & "\n\nSTACK TRACE:\n" & Server.GetLastError().StackTrace ' Create Event Log if it does not exist Dim LogName As String = "Application" If (Not EventLog.SourceExists(LogName)) EventLog.CreateEventSource(LogName, LogName) End If ' Insert into Event Log Dim Log As New EventLog Log.Source = LogName Log.WriteEntry(Message, EventLogEntryType.Error) End Sub </script>

Resumen de la seccin
1. Los errores se dividen en cuatro categoras: errores de configuracin, de anlisis, de compilacin y de ejecucin. 2. De forma predeterminada, la informacin mostrada para un error de tiempo de ejecucin consiste en la pila de llamadas (la cadena de llamadas a procedimientos que condujo hasta la excepcin). Si el modo de depuracin se encuentra habilitado, ASP.NET muestra el nmero de lnea del cdigo fuente donde se origin el error en tiempo de ejecucin. 3. ASP.NET permite especificar si los errores se van a mostrar a clientes locales, remotos o a ambos. De forma predeterminada, los errores slo se muestran a clientes locales (los que se encuentran en el mismo equipo que el servidor). Tambin se puede especificar una pgina de errores personalizada a la que enviar a los clientes si se produce un error.

4. 5. 6. 7. 8.

Adems de desviar a una pgina comn cuando se produce cualquier error, tambin se pueden asignar pginas de error especficas a cdigos de estado de error especficos. La seccin de configuracin <customerrors> admite una etiqueta <error> interna que asocia cdigos de estado HTTP con pginas de errores personalizadas. Los errores tambin se pueden controlar en el cdigo, ya sea en el mbito de la pgina o de la aplicacin. La clase base Page expone un mtodo HandleError que se puede reemplazar en las pginas. Se invocar al mtodo siempre que una excepcin no capturada se lance en tiempo de ejecucin. El espacio de nombres System.Web.Mail expone clases para enviar correo electrnico mediante programa. Esto resulta til para avisar a un administrador cuando se produce un error. Adems de controlar errores en el mbito de la pgina, se puede utilizar el evento Application_Error de Global.asax para controlarlos en el mbito de la aplicacin. Este evento tiene lugar para cualquier excepcin sin tratamiento que se produce dentro de la aplicacin. El espacio de nombres System.Diagnostics proporciona clases para escribir en el Registro de eventos de Windows.

Personalizar pginas de error


Segn las circunstancias, los errores de una aplicacin se pueden tratar de distintos modos. Por ejemplo, durante el desarrollo probablemente desee ver las pginas de error detalladas suministradas por ASP.NET para ayudar a identificar y resolver problemas. Sin embargo, una vez que la aplicacin se est utilizando en un entorno de produccin, no es aconsejable mostrar errores detallados a los usuarios. Puede utilizar ASP.NET para especificar si los errores se van a mostrar a clientes locales, remotos o a ambos. De forma predeterminada, los errores slo se muestran a clientes locales (los que se encuentran en el mismo equipo que el servidor). Tambin se puede especificar una pgina de errores personalizada a la que enviar a los clientes si se produce un error. Los errores personalizados se habilitan en el archivo Web.config para una aplicacin. Por ejemplo:

<configuration> <system.web> <customErrors defaultRedirect="genericerror.htm" mode="remoteonly" /> </system.web> </configuration>


Esta configuracin permite a los clientes locales ver las pginas de error predeterminadas de ASP.NET detalladas pero desva a los clientes remotos hacia una pgina personalizada, genericerror.htm. ASP.NET pasa la ruta de acceso de la pgina en la que se produjo el error a la pgina de errores como un argumento QueryString. Observe que, si la ejecucin de la pgina de errores genera un error, se enva una pgina en blanco al cliente remoto.

<%@ Page Language="VB" Description="Error page"%> <html> <head> <title>Error page</title> </head> <body> <h1>Error page</h1> Error originated on: <%=Request.QueryString("ErrorPage") %> </body> </html>

Seguridad Informacin general sobre seguridad


Una parte importante de muchas aplicaciones Web radica en la capacidad de identificar usuarios y controlar el acceso a los recursos. Se conoce como autenticacin al acto de determinar la identidad de la entidad solicitante. Por lo general, el usuario deber presentar sus credenciales, como el par nombre de usuario y contrasea, para ser autenticado. Cuando se encuentre disponible una identidad autenticada, deber determinarse si esa identidad puede tener acceso a un recurso especfico. Este proceso se conoce como autorizacin. ASP.NET e IIS colaboran para proporcionar servicios de autenticacin y autorizacin a las aplicaciones. Una caracterstica importante de los objetos COM es la capacidad de controlar la identidad con la que se ejecuta el cdigo de objeto COM. Se conoce como representacin al hecho de que un objeto COM ejecute cdigo con la identidad de la entidad solicitante. Opcionalmente, las aplicaciones ASP.NET Framework pueden representar solicitudes. Es posible que algunas aplicaciones tambin personalicen dinmicamente el contenido en funcin de la identidad del solicitante o de un conjunto de funciones al que pertenece la identidad del solicitante. Las aplicaciones ASP.NET Framework pueden comprobar dinmicamente si la entidad solicitante actual participa en una funcin concreta. Por ejemplo, es posible que una aplicacin intente comprobar si el usuario actual pertenece a la funcin del administrador a fin de generar condicionalmente contenido para los administradores

Autenticacin y autorizacin
ASP.NET funciona, junto con IIS, para permitir la autenticacin de tipo bsica, implcita y Windows. ASP.NET es compatible con el servicio de autenticacin de pasaporte de Microsoft, el cual proporciona servicios simples de firma y servicios de perfiles de usuario. ASP.NET tambin proporciona un robusto servicio para aplicaciones que necesitan utilizar autenticacin basada en formularios. La autenticacin basada en formularios utiliza "cookies" para autenticar a los usuarios, y permite a la aplicacin realizar su propia verificacin de credenciales. Es importante darse cuenta de que los servicios de autenticacin de ASP.NET dependen de los servicios de autenticacin suministrados por IIS. Por ejemplo, para poder utilizar una autenticacin bsica en una aplicacin IIS, se debe configurar el uso de la autenticacin bsica para la aplicacin mediante el Administrador de servicios Internet. ASP.NET proporciona dos tipos de servicios de autorizacin:

Comprobaciones de ACLs o permisos sobre un recurso para determinar si la cuenta de usuario autenticada puede obtener acceso a los recursos Autorizacin de URL, la cual autoriza una identidad para partes del espacio Web Para ilustrar la diferencia, considere un escenario en el que una aplicacin est configurada para permitir acceso annimo mediante la cuenta IUSR_MYMACHINE. Cuando una solicitud de una pgina ASP.NET (como "/default.aspx") recibe autorizacin, se realiza una comprobacin de los ACL de ese archivo (por ejemplo, "c:\\inetpub\\wwwroot\\default.aspx") para ver si la cuenta IUSR_MYMACHINE tiene permiso para leer el archivo. Si lo tiene, entonces se autoriza el acceso. La autorizacin de archivo se realiza automticamente. Para autorizacin de URL, se comprueba el usuario annimo con los datos de configuracin obtenidos para la aplicacin ASP.NET. Si se permite el acceso a la direccin URL solicitada, la solicitud se autoriza. En este caso, ASP.NET comprueba si el usuario annimo dispone de acceso a /Default.aspx (es decir, la comprobacin se realiza sobre la propia URL, no sobre el archivo en el que se resuelve la URL en ltima instancia). sta podra parecer una diferencia sutil, pero permite a las aplicaciones utilizar esquemas de autenticacin como los basados en formularios o la autenticacin de Pasaporte, en los cuales los usuarios no se corresponden con un equipo o una cuenta de dominio. Tambin permite la autorizacin de recursos virtuales, para los cuales no existe un archivo fsico subyacente al recurso. Por ejemplo, una aplicacin podra optar por asignar todas las solicitudes de archivos que terminan en .stk a un controlador que proporciona cotizaciones de valores segn ciertas variables presentes en la cadena de consulta. En ese caso, no existe un archivo .stk con el que hacer las comprobaciones ACL; por lo tanto, se utiliza autorizacin de URL para controlar el acceso al recurso virtual. La autorizacin de archivo se realiza siempre con la cuenta autenticada suministrada por IIS. Si se permite el acceso annimo, esta cuenta es la cuenta annima configurada. En cualquier otro caso, se utiliza una cuenta NT. Esto funciona exactamente de la misma forma que ASP. Las listas ACL de archivos se configuran para un determinado archivo o directorio mediante la ficha Seguridad de la pgina de propiedades del Explorador. La autorizacin de URL se configura como parte de una aplicacin ASP.NET Framework y se describe en detalle en Autorizar usuarios y funciones. Para activar un servicio de autenticacin de ASP.NET, se debe configurar el elemento <authentication> en el archivo de configuracin de la aplicacin. Este elemento puede tener uno de los valores de la tabla siguiente. Valor Ninguno Windows Descripcin No hay ningn servicio de autenticacin de ASP.NET activo. Observe que los servicios de autenticacin de IIS pueden estar an presentes. Los servicios de autenticacin de ASP.NET asocian un WindowsPrincipal (System.Security.Principal.WindowsPrincipal) a la solicitud actual para permitir la autorizacin de usuarios o grupos de NT. Los servicios de autenticacin de ASP.NET administran las "cookies" y desvan a los usuarios no autenticados a una pgina de inicio de sesin. Este mtodo se suele utilizar en conjuncin con la opcin IIS que permite el acceso annimo a una aplicacin. Los servicios de autenticacin de ASP.NET proporcionan un envoltorio apropiado para los servicios suministrados por el kit de desarrollo de software para pasaporte (Passport SDK), el cual debe instalarse en el equipo.

Formularios

Passport

Por ejemplo, el siguiente archivo de configuracin permite la autenticacin basada en formularios (cookie) para una aplicacin:

<configuration> <system.web> <authentication mode="Forms"/> </system.web> </configuration>

Autenticacin basada en Windows

Al utilizar la autenticacin de Windows de ASP.NET, ASP.NET asocia un objeto WindowsPrincipal a la solicitud actual. La autorizacin de direccin URL utiliza este objeto. La aplicacin tambin puede utilizarlo mediante programacin para determinar si una identidad solicitante se encuentra en una funcin dada.

If User.IsInRole("Administrators") Then DisplayPrivilegedContent() End If


La clase WindowsPrincipal determina las funciones por la pertenencia al grupo de NT. Las aplicaciones que desean determinar sus propias funciones pueden hacerlo mediante el control del evento WindowsAuthentication_OnAuthenticate en su archivo Global.asax y la asociacin de su propia clase que implementa System.Security.Principal.IPrincipal a la solicitud, como se muestra en el ejemplo siguiente:

' Create a class that implements IPrincipal Public Class MyPrincipal : Inherits IPrincipal ' Implement application-defined role mappings End Class ' In a Global.asax file Public Sub WindowsAuthentication_OnAuthenticate(Source As Object, e As WindowsAuthenticationEventArgs) ' Attach a new application-defined class that implements IPrincipal to ' the request. ' Note that since IIS has already performed authentication, the provided ' identity is used. e.User = New MyPrincipal(e.Identity) End Sub
En el ejemplo siguiente se muestra cmo obtener acceso al nombre de un usuario autenticado, que est disponible como User.Identity.Name. Los programadores familiarizados con ASP deben observar que este valor tambin est an disponible, al igual que ocurre con la variable de servidor AUTH_USER:

html> <script language="VB" runat=server> Sub Page_Load(Src As Object, E As EventArgs) AuthUser.Text = User.Identity.Name AuthType.Text = User.Identity.AuthenticationType End Sub </script> <body> <h3><font face="Verdana">Utilizar autenticacin de Windows</font></h3> <table Width="700" rules="all" bordercolor="Black" style="background-color:#ccccff;bordercolor:black;fontfamily:Verdana;font-size:8pt;border-collapse:collapse;"> <tr> <td>Usuario:</td> <td><asp:label id=AuthUser runat=server/> </tr> <tr> <td>Tipo de autenticacin:</td> <td><asp:label id=AuthType runat=server/> </tr> </table> </body> </html>

Autenticacin basada en formularios


La autenticacin basada en formularios es un servicio de autenticacin de ASP.NET que permite a las aplicaciones suministrar su propia interfaz de inicio de sesin y hacer su propia verificacin de credenciales. ASP.NET permite autenticar usuarios y desviar a los usuarios no autenticados hacia la pgina de inicio de sesin, adems de realizar todas las tareas de administracin de "cookies". Este tipo de autenticacin es una tcnica habitual utilizada en muchos sitios Web. Para que una aplicacin pueda utilizar autenticacin basada en formularios, se debe configurar <authentication> con la opcin Forms y denegar el acceso a los usuarios annimos: Los administradores usan autenticacin basada en formularios para configurar el nombre de la "cookie" a usar, el tipo de proteccin, la direccin URL para la pgina de inicio de sesin, el tiempo de validez de la "cookie" y la ruta de acceso que se debe utilizar para la "cookie" suministrada. La siguiente tabla muestra los atributos vlidos para el elemento <Forms>, el cual es un subelemento del elemento <authentication> mostrado en la siguiente tabla: Atributo loginUrl Descripcin URL de inicio de sesin a la que se desvan los usuarios no autenticados. Puede estar en el mismo equipo o en uno remoto. Si es un equipo remoto, ambos equipos deben utilizar el mismo valor para el atributo decryptionkey. Nombre de la "cookie" HTTP que se va a utilizar a efectos de autenticacin. Observe que si varias aplicaciones desean utilizar servicios de autenticacin basados en formularios en un nico equipo, cada uno debera configurar un valor de "cookie" nica. Para evitar originar dependencias en direcciones URL, ASP.NET utiliza "/" como valor de la ruta de acceso al configurar "cookies" de autenticacin, de modo que stas se vuelvan a enviar a todas las aplicaciones del sitio. Tiempo, en minutos enteros, tras el cual la "cookie" caduca. El valor predeterminado es 30. El atributo timeout indica la caducidad con un valor continuo de n minutos contados desde el momento en que se recibi la ltima solicitud. Para evitar efectos negativos relacionados con el rendimiento y advertencias de los exploradores Web que tienen activadas las advertencias de "cookies", la "cookie" se actualiza si ha transcurrido ms de la mitad del tiempo. (Esto implica una prdida de precisin en algunos casos). Ruta de acceso que se utiliza para la "cookie" suministrada. Para evitar problemas con la escritura de las rutas, se utiliza "/" como valor predeterminado, ya que los exploradores Web distinguen estrictamente entre maysculas y minsculas cuando devuelven "cookies". Las aplicaciones en un entorno de un servidor compartido deberan utilizar esta directiva para mantener "cookies" privadas. (Otra posibilidad consiste en que especifiquen la ruta de acceso en tiempo de ejecucin y se utilicen las API para emitir "cookies"). Mtodo utilizado para proteger los datos de las "cookies". Los valores posibles son los siguientes:

name

timeout

path

protection

All: utiliza validacin y cifrado de datos para proteger la "cookie". El algoritmo de validacin de datos configurado se basa en el elemento . Triple DES se utiliza para cifrado, si est disponible y si la clave es suficientemente larga (48 bytes). All es el valor predeterminado (y sugerido). None: se utiliza con sitios que utilizan "cookies" slo para personalizacin y que tienen requisitos de seguridad menores. Tanto el cifrado como la validacin, se pueden deshabilitar. Aunque se debera tener precaucin al utilizar "cookies" de este modo, esta opcin proporciona el mejor rendimiento entre los mtodos de personalizacin mediante .NET Framework. Encryption: permite cifrar la "cookie" mediante TripleDES o DES, pero no se realiza validacin de datos. Este tipo de "cookie" puede sufrir ataques en lo que se refiere a la seleccin de texto sin formato. Validation: el contenido de la "cookie" no est cifrado, pero se valida para comprobar que no ha sido modificado durante la transmisin. Para crear la "cookie", la clave de validacin se concatena en un bfer con los datos de la "cookie" y, a continuacin, se genera un MAC que se agrega a la "cookie" saliente.

Tras haber configurado la aplicacin, se debe proporcionar una pgina de inicio de sesin. El siguiente ejemplo muestra una pgina de inicio de sesin. Cuando se ejecuta el ejemplo, ste solicita la pgina Default.aspx. Las solicitudes no autenticadas se desvan a la pgina de inicio de sesin (Login.aspx), la cual presenta un formulario sencillo que pide una direccin de correo electrnico y una contrasea. (Utilice "jdoe@contoso.com" y "password" como credenciales.) Despus de validar las credenciales, la aplicacin realiza las siguientes llamadas:

FormsAuthentication.RedirectFromLoginPage(UserEmail.Value, PersistCookie.Checked)
De esta forma, se vuelve a dirigir al usuario hacia la URL original solicitada. Las aplicaciones que no desean realizar la redireccin pueden llamar a FormsAuthentication.GetAuthCookie, para recuperar el valor de la "cookie", o bien a FormsAuthentication.SetAuthCookie, para asociar una "cookie" apropiadamente cifrada a la respuesta saliente. Estas tcnicas pueden resultar tiles para aplicaciones que proporcionan

una interfaz de usuario de inicio de sesin incrustada en la pgina contenedora o que desean tener ms control sobre el destino al que se desva a los usuarios. Las "cookies" de autenticacin pueden ser temporales o permanentes ("persistentes"). Las "cookies" temporales tienen la misma duracin que la sesin actual del explorador. Cuando se cierra el explorador, la "cookie" se pierde. El explorador se encarga de guardar las "cookies" permanentes, las cuales se vuelven a enviar en cada sesin de un explorador a menos que el usuario las elimine explcitamente.

<%@ Import Namespace="System.Web.Security " %> <html> <script language="VB" runat=server> Sub Page_Load(Src As Object, E As EventArgs) Welcome.Text = "Hola, " + User.Identity.Name End Sub Sub Signout_Click(Src As Object, E As EventArgs) FormsAuthentication.SignOut() Response.Redirect("login.aspx") End Sub </script> <body> <h3><font face="Verdana">Utilizar autenticacin con cookies</font></h3> <form runat=server> <h3><asp:label id="Welcome" runat=server/></h3> <asp:button text="Cerrar sesin" OnClick="Signout_Click" runat=server/> </form> </body> </html>
La "cookie" utilizada por la autenticacin basada en formularios consiste en una versin lineal de la clase System.Web.Security.FormsAuthenticationTicket . La informacin incluye el nombre de usuario (pero no la contrasea), la versin de autenticacin basada en formularios utilizada, la fecha en la que se emiti la "cookie" y un campo para datos opcionales especficos de la aplicacin. El cdigo de la aplicacin puede revocar o quitar las "cookies" de autenticacin mediante el mtodo FormsAuthentication.SignOut. Este mtodo permite quitar la "cookie" de autenticacin independientemente de si es temporal o permanente. Asimismo, se pueden suministrar servicios de autenticacin basados en formularios con una lista de credenciales vlidas que utilizan la configuracin, tal como se muestra en el siguiente ejemplo:

La aplicacin puede entonces realizar una llamada a FormsAuthentication.Authenticate, con el nombre de usuario y la contrasea, y ASP.NET se encargar de verificar las credenciales. Las credenciales se pueden almacenar en texto no cifrado o como cdigo "hash" de tipo SHA1 o MD5, segn los siguientes valores del atributo passwordFormat: Tipo Hash Clear SHA1 Descripcin Las contraseas se almacenan en texto no cifrado Las contraseas se almacenan en compendios SHA1

MD5

Las contraseas se almacenan en compendios MD5

Autorizar usuarios y funciones


ASP.NET se utiliza para controlar el acceso de los clientes a los recursos URL. Se puede configurar para el mtodo HTTP que se utilice para realizar la solicitud (GET o POST) y, tambin, para permitir o denegar el acceso a grupos de usuarios o funciones. El siguiente ejemplo muestra la concesin de acceso a un usuario llamado John y a una funcin denominada Admins, denegndosela a los dems usuarios. Los elementos que se permiten en las directivas de autorizacin pueden ser allow o deny. Cada elemento allow o deny debe contener un atributo users o un atributo roles. Se pueden especificar varios usuarios o funciones en un nico elemento mediante una lista de valores separados por comas. El mtodo HTTP se puede indicar mediante el atributo Verb: Este ejemplo permite a Mary y John utilizar el mtodo POST en los recursos protegidos, mientras que slo permite utilizar el mtodo GET al resto de los usuarios. Existen dos nombres de usuario especiales:

*: Todos los usuarios ?: Usuarios annimos (no autenticados)

Estos nombres de usuario especiales se utilizan comnmente en aplicaciones que usan autenticacin basada en formularios para denegar el acceso a los usuarios no autenticados, tal como se muestra en el siguiente ejemplo: La autorizacin de direcciones URL se evala jerrquicamente y las reglas que se utilizan para determinar el acceso son las siguientes:

Las reglas relevantes para la URL se obtienen de la jerarqua y con ellas se construye una lista combinada de reglas.

Las reglas ms recientes se colocan al principio de la lista. Esto significa que la configuracin situada en el directorio actual se encuentra al principio de la lista, seguida de la configuracin del nivel superior inmediato, y as sucesivamente, hasta el archivo de nivel superior para el equipo. Las reglas se comprueban hasta encontrar una que se cumpla. Si la regla es admisible, el acceso se concede. En caso contrario, el acceso se rechaza. Esto significa que las aplicaciones no interesadas en heredar su configuracin deberan configurar explcitamente todas las posibilidades relevantes. El archivo Web.config predeterminado de nivel superior para un determinado equipo permite el acceso a todos los usuarios. A menos que una aplicacin se configure de forma contraria (y suponiendo que un usuario reciba autenticacin y pase la comprobacin ACL para autorizacin de archivos), el acceso se concede. Cuando se comprueban las funciones, la autorizacin de URL recorre en sentido descendente la lista de funciones configuradas y hace algo similar al siguiente pseudocdigo:

If User.IsInRole("ConfiguredRole") Then ApplyRule() End If


Lo que esto significa para la aplicacin es que se puede utilizar una clase personalizada que implemente System.Security.Principal.IPrincipal para suministrar su propia semntica de asignacin de funciones, como se explic en Autenticacin basada en Windows. El siguiente ejemplo utiliza servicios de autenticacin basados en formularios. Deniega explcitamente el acceso a jdoe@contoso.com y a los usuarios annimos. Intente realizar un inicio de sesin en el ejemplo con Nombre de usuario="jdoe@contoso.com" y Contrasea="password". El acceso se denegar y volver a aparecer la pgina de inicio de sesin. Ahora, intente iniciar una sesin con Nombre de usuario="mary@contoso.com" y Contrasea="password". Observar que esta vez el acceso s se concede.

<%@ Import Namespace="System.Web.Security " %> <html> <script language="VB" runat=server>

Sub Page_Load(Src As Object, E As EventArgs) Welcome.Text = "Hola, " + User.Identity.Name End Sub Sub Signout_Click(Src As Object, E As EventArgs) FormsAuthentication.SignOut() Response.Redirect("login.aspx") End Sub </script> <body> <h3><font face="Verdana">Utilizar autenticacin con cookies</font></h3> <form runat=server> <h3><asp:label id="Welcome" runat=server/></h3> <asp:button text="Cerrar sesin" OnClick="Signout_Click" runat=server/> </form> </body> </html>

Suplantacin de cuentas de usuario


Como ya se mencion en Informacin general sobre seguridad, la suplantacin de identidad hace referencia a un proceso en el que un objeto COM se ejecuta con la identidad de la entidad en representacin de la cual est realizando su trabajo. Para una aplicacin Web esto implica que, si un servidor est realizando una suplantacin de identidad, est trabajando con la identidad del cliente que hace la solicitud. De forma predeterminada, ASP.NET no realiza suplantaciones por cada solicitud. En esto difiere de ASP, que s realiza suplantaciones en cada solicitud. Si se desea, se puede configurar una aplicacin de modo que realice suplantaciones de identidad en cada solicitud mediante la siguiente directiva Configuration:

Puesto que ASP.NET realiza una compilacin dinmica, para habilitar la suplantacin se requiere que todas las cuentas dispongan de acceso de lectura y escritura en el directorio Codegen de la aplicacin (donde el mdulo de ejecucin de ASP.NET almacena los objetos compilados dinmicamente) as como en la cach de ensamblado global (%Windir%\assembly). Algunas aplicaciones exigen habilitar la suplantacin para conseguir compatibilidad con ASP o utilizar servicios de autenticacin de Windows.

Seguridad y servicios Web


En esta seccin se describen mtodos para establecer la seguridad de los servicios Web de XML. Si an no ha ledo la seccin Seguridad de este tutorial, hgalo ahora antes de continuar con este tema.

Autenticacin y autorizacin de Windows


Se utiliza la misma tcnica para establecer la seguridad de los servicios Web de XML mediante autenticacin de Windows que para establecer la seguridad de las pginas .aspx (descrita en la seccin Autenticacin basada en Windows). Para solicitar autenticacin, hay que habilitar Autenticacin integrada de Windows para la aplicacin y deshabilitar Acceso annimo en la consola de administracin de IIS. Para permitir o denegar a usuarios especficos el acceso al servicio, utilice el sistema de configuracin de ASP.NET o establezca las ACL en el archivo del servicio, como se indica en el siguiente ejemplo:

<configuration> <system.web> <authentication mode="Windows"/> </system.web> <location path="secureservice.asmx">

<system.web> <authorization> <allow users="Administrator"/> <allow users="DOMAIN\Bradley"/> <deny roles="BUILTIN\Power Users"/> </authorization> </system.web> </location> </configuration>
Esto funciona bien cuando se sabe que el cliente del servicio Web de XML se ejecutar como un usuario de Windows especfico. Un caso ms interesante es el de un cliente que se ejecuta como un usuario que acta en nombre de otro. Considere una pgina ASP.NET que tiene acceso a un servicio Web de XML seguro que no suplanta a los clientes que tienen acceso al mismo. En este caso, es necesario establecer mediante programacin el nombre de usuario y la contrasea antes de conectarse al servicio Web. En el siguiente ejemplo se utiliza la autenticacin bsica y se ilustra un Servicio Web sencillo:

<%@ WebService language="VB" Class="SecureService" %> Imports System.Web.Services Imports System Class SecureService : Inherits WebService <WebMethod()> Public Function SecureTest As String Return "Hello from the secure web service" End End Class
Puede que desee solicitar autenticacin bsica para este servicio; para ello, debe establecer una configuracin apropiada en IIS de la manera siguiente: 1. 3. Abra la consola MMC de IIS.

2.

Start->Run "inetmgr"

En el panel de la izquierda, expanda el rbol para buscar el directorio virtual.

4. 5.

En el panel de la derecha, haga clic con el botn secundario del mouse (ratn) en Secureservice.asmx y elija Propiedades. Seleccione la ficha Seguridad del archivo. Bajo Control de acceso annimo y autenticacin, haga clic en Editar. o Deshabilite el acceso annimo. o Deshabilite la autenticacin integrada de Windows. o Habilite la autenticacin bsica. Haga clic en Aceptar para guardar esta configuracin y salir de la consola MMC.

6.

La clase base de proxy WebService proporciona dos propiedades, Username y Password, que se pueden utilizar para especificar las credenciales con las que conectarse al servicio Web remoto. Deben estar establecidas las credenciales vlidas de Windows en el equipo o dominio del servicio Web.

<%@ Import Namespace="SecureService" %> <html> <script language="VB" runat="server"> Public Sub Page_Load(sender As Object, e As EventArgs) Dim s As New SecureService s.Credentials = New System.Net.NetworkCredential("Administrator", "test123") Message.Text = s.SecureTest()

End Sub </script> <body> <h4><font face="verdana"> <asp:Label id="Message" runat="server"/> </font></h4> </body> </html>
La clase base WebService tambin proporciona una propiedad User de tipo System.Security.Principal.IPrincipal, que puede utilizarse para recuperar informacin acerca del usuario cliente. En este caso, tambin puede autorizar el acceso al servicio Web en la seccin Autorizacin del sistema de configuracin de ASP.NET.

Autenticacin y autorizacin personalizadas con encabezados SOAP


La autenticacin de Windows funciona correctamente para escenarios de la intranet, en los que se autentica con un usuario del propio dominio. Sin embargo, es probable que en Internet desee llevar a cabo una autenticacin y una autorizacin personalizadas, tal vez con una base de datos SQL. En ese caso, debe pasar credenciales personalizadas (como el nombre de usuario y la contrasea ) al servicio y dejarle controlar la autenticacin y la autorizacin. Una forma aconsejable de pasar informacin adicional junto con una solicitud al servicio Web de XML es un encabezado SOAP. Para hacerlo, hay que definir en el servicio una clase derivada de SOAPHeader y despus declarar un campo pblico del servicio como ese tipo. Esto se expone en el contrato pblico del servicio y est a la disposicin del cliente cuando se crea el proxy mediante WebServiceUtil.exe, como en el siguiente ejemplo:

Imports System.Web.Services Imports System.Web.Services.Protocols ' AuthHeader class extends from SoapHeader Public Class AuthHeader : Inherits SoapHeader Public Username As String Public Password As String End Class Public Class HeaderService : Inherits WebService Public sHeader As AuthHeader ... End Class
Cada atributo WebMethod del servicio puede definir un conjunto de encabezados asociados mediante el atributo personalizado SoapHeader. De forma predeterminada se solicitar el encabezado, aunque tambin es posible definir encabezados opcionales. El atributo SoapHeader especifica el nombre de un campo o una propiedad pblicos de la clase Client o Server (a la que se hace referencia como una propiedad Headers en este tema). WebServices establece el valor de una propiedad Headers antes de que se llame al mtodo para obtener encabezados de entrada y obtiene el valor cuando vuelve para obtener encabezados de salida. Para obtener ms informacin acerca de los resultados o encabezados opcionales vea la documentacin del kit de desarrollo de software (SDK) de .NET Framework.

<WebMethod(), SoapHeader("sHeader")> Public Function SecureMethod() As String If (sHeader Is Nothing) Return "ERROR: Please supply credentials" Else Return "USER: " & sHeader.Username End If End Function
A continuacin, un cliente establece el encabezado directamente en la clase de proxy antes de hacer una llamada a un mtodo que lo requiera, como se muestra en el ejemplo siguiente:

Dim h As New HeaderService Dim myHeader As New AuthHeader myHeader.Username = "JohnDoe" myHeader.Password = "password" h.AuthHeader = myHeader Dim result As String = h.SecureMethod()
Para ver el funcionamiento de este fragmento de cdigo, ejecute el siguiente ejemplo:

<%@ WebService Language="VB" Class="HeaderService" %> Imports System Imports System.Web.Services Imports System.Web.Services.Protocols ' AuthHeader class extends from SoapHeader Public Class AuthHeaderVB : Inherits SoapHeader Public Username As String Public Password As String End Class Public Class HeaderService Public sHeader As AuthHeaderVB <WebMethod, SoapHeader("sHeader")> Public Function SecureMethod() As String If (sHeader Is Nothing) Return "ERROR: escribir las credenciales" End If Dim usr As String = sHeader.Username Dim pwd As String = sHeader.Password If (AuthenticateUser(usr, pwd)) Return "CORRECTO: " & usr & "," & pwd Else Return "ERROR: no se pudo autenticar" End If End Function Private Function AuthenticateUser(usr As String, pwd As String) As Boolean If (Not (usr Is Nothing) And Not (pwd Is Nothing)) ' could query a database here for credentials... Return true End If Return false End Function End Class

Resumen de la seccin
1. Para establecer la seguridad de los servicios Web de XML en el servidor mediante autenticacin de Windows se sigue exactamente el mismo modelo que el descrito para las pginas .aspx.

2.

Tambin se pueden establecer mediante programacin las credenciales de Windows con las propiedades Username y Password de la clase de proxy WebService.

3.

Por ltimo, puede realizar una autenticacin personalizada mediante la transmisin de informacin de credenciales como SOAPHeaders, junto con una solicitud SOAP al mtodo que la requiera.

Localizacin Informacin general sobre internacionalizacin Compatibilidad de codificacin


ASP.NET utiliza internamente Unicode. Adems, utiliza la clase String de la biblioteca de clases .NET Framework y las funciones de utilidad relacionadas, que tambin usan internamente Unicode. A la hora de comunicarse con el exterior, ASP.NET se puede configurar de varias formas con el fin de utilizar una codificacin definida, tanto para los archivos .aspx como para los datos de solicitud o de respuesta. Por ejemplo, es posible almacenar archivos .aspx con codificacin Unicode y convertir el resultado HTML de una pgina en una pgina de cdigo ANSI como ISO-8859-1.

Adaptacin a diferentes idiomas


El acceso a las propiedades de un idioma se puede realizar por medio de la clase CultureInfo. Adems, ASP.NET realiza un seguimiento de dos propiedades de una cultura predeterminada por cada subproceso y solicitud: CurrentCulture para la opcin predeterminada de las funciones dependientes del idioma y CurrentUICulture para una bsqueda de datos de recursos especfica del idioma. El siguiente cdigo permite mostrar los valores culturales del servidor Web. Observe que la clase CultureInfo est completamente calificada.

<%@Import Namespace="System.Globalization"%> ... <%=CultureInfo.CurrentCulture.NativeName%> <%=CultureInfo.CurrentUICulture.NativeName%>


El resultado es el siguiente: English (United States) English (United States) Para datos dependientes del idioma, tales como formatos de fecha y hora, o moneda, ASP.NET aprovecha las posibilidades de la biblioteca de clases de .NET Framework en Common Language Runtime. El cdigo de las pginas ASP.NET puede utilizar rutinas de formato dependientes del idioma, como DateTime.Format. Por ejemplo, el siguiente cdigo muestra en pantalla la fecha actual en un formato largo: en la primera lnea, segn el idioma del sistema, y en la segunda, segn el idioma alemn ("de"):

<%=DateTime.Now.ToString("f")%> <%=DateTime.Now.ToString("f", new System.Globalization.CultureInfo("de"))%>


El resultado es el siguiente: Wednesday, December 14, 2005 9:39 AM Mittwoch, 14. Dezember 2005 09:39

Opciones de configuracin
Cuando se crean pginas ASP.NET o mdulos de cdigo en segundo plano, los programadores pueden utilizar la biblioteca de clases de .NET Framework con el fin de conseguir caractersticas necesarias para un entorno globalizado o para adaptar la aplicacin a un entorno local. ASP.NET tambin proporciona opciones de configuracin para facilitar el desarrollo y la administracin de aplicaciones de ASP.NET. ASP.NET utiliza archivos para definir la configuracin en cada directorio (configuracin que normalmente tambin heredan los subdirectorios). Cada archivo puede contener una seccin Globalization en la que se pueden especificar codificaciones y culturas predeterminadas. Los valores son vlidos si son aceptados por las clases relacionadas, Encoding y CultureInfo. Encontrar ms informacin acerca de las clases Encoding y CultureInfo en el kit de desarrollo de software (SDK) de .NET Framework. Dentro de la seccin Globalization, el valor de fileEncoding determina la forma en que ASP.NET codifica los archivos .aspx; los valores de requestEncoding y responseEncoding determinan la forma en que se codifican los datos de solicitud y respuesta, respectivamente. Los atributos de la seccin Globalization del archivo Web.config tambin se pueden especificar en la directiva Page (con la excepcin de fileEncoding, ya que ste se aplica al propio archivo). Estos valores de configuracin slo son vlidos para una pgina especfica y reemplazan a los valores de configuracin del archivo Web.config. La siguiente directiva de ejemplo especifica que la pgina debera utilizar los valores de configuracin de la cultura francesa y la codificacin UTF-8 para la respuesta:

<%@Page Culture="fr" UICulture="fr" ResponseEncoding="utf-8"%>


Nota: dentro de una pgina, los valores culturales se pueden cambiar mediante programacin actuando sobre Thread.CurrentCulture y Thread.UICulture.

Resumen de la seccin
1. ASP.NET admite una amplia variedad de codificaciones para archivos .aspx y datos de solicitud y de respuesta.

2.

La clase CultureInfo se encarga del tratamiento de datos dependientes del idioma y de realizar el seguimiento de los valores CurrentCulture y CurrentUICulture. 3. Se pueden configurar opciones de internacionalizacin para cada equipo, cada directorio y cada pgina.

Configurar el referente cultural y la codificacin Codificaciones Internamente, ASP.NET maneja todos los datos de cadenas en Unicode. En el siguiente ejemplo, se utiliza el atributo ResponseEncoding para pedir a ASP.NET que enve la pgina con codificacin UTF-8. Observe que es posible elegir cualquier codificacin arbitraria sin afectar al archivo .aspx. ASP.NET tambin define el atributo CharSet sobre el Tipo de contenido del encabezado HTTP segn el valor de ResponseEncoding. Esto permite a los exploradores determinar la codificacin sin tener que utilizar una metaetiqueta o deducir la codificacin correcta a partir del contenido.
<%@Page Language="VB" ResponseEncoding="UTF-8"%>

<html> <head> <link rel="stylesheet" href="../i18n_styles.css"> </head> <body> <h3>I18N: Codificacin</h3> <div class="details"> Este ejemplo utiliza diferentes codificaciones en la misma pgina. El origen de la pgina est almacenado con codificacin UTF-8. De forma interna, ASP.NET controla la pgina como Unicode. Al utilizar el atributo ResponseEncoding, se solicitar que ASP.NET enve esta pgina con codificacin UTF-8. </div> <hr> <center> <div class="details"> Texto en ingls. </div> <div class="details"> Dies ist ein deutscher Text. Er demonstriert die Mglichkeit von Umlauten. </div> <div class="details"> " "

</div> <div class="details" dir="rtl"> . , </div> </center> </body> </html> Nota: si algunos caracteres aparecen como rectngulos vacos, ser necesario instalar las opciones adicionales para permitir los idiomas Japons y Hebreo. En una plataforma de Windows 2000, abra Opciones regionales en el Panel de control y agregue la opcin de compatibilidad de idioma necesaria. El ejemplo anterior muestra cmo utilizar diferentes conjuntos de caracteres nacionales en la misma pgina. La pgina contiene texto ingls (ASCII), texto alemn con un carcter con diresis, texto japons y texto hebreo (utiliza dir="rtl"). El cdigo fuente de la propia pgina se almacena con codificacin UTF-8, neutral con respecto a la pgina de cdigos, segn se especifica en Web.config. La directiva Page especifica la opcin ResponseEncoding (codificacin de la respuesta) sobre la propia pgina: <%@Page ... ResponseEncoding="utf-8"%> Nota: ResponseEncoding en Web.config, tambin se especifica como UTF-8, de modo que repetirlo en la pgina resulta redundante. Sin embargo, si el archivo .aspx se traslada a un servidor que no utiliza UTF-8, el archivo seguira especificando la codificacin correcta. Utilizar CultureInfo El cdigo de las pginas ASP.NET puede utilizar la clase CultureInfo para suministrar valores propios de un determinado entorno regional. En el siguiente ejemplo, las propiedades de un determinado referente cultural, inicialmente la cultura del servidor, se definen del siguiente modo: culture = CultureInfo.CurrentCulture Si se suministra el nombre de una nueva cultura, se utilizar sta: culture = New CultureInfo(NewCulture.Value) La cultura suministrada se establece como el nuevo valor predeterminado y se muestran algunas propiedades: <% Thread.CurrentThread.CurrentCulture = culture %> ... Current Culture is <%= CultureInfo.CurrentCulture.Name %> (<%=Thread.CurrentThread.CurrentCulture.Name%>), <%= CultureInfo.CurrentCulture.EnglishName %>/<%=CultureInfo.CurrentCulture.NativeName%>, The localized date is: <%= DateTime.Now.ToString("D", CultureInfo.CurrentCulture) %>

<%@Page Language="VB" ResponseEncoding="utf-8" %> <%@Import Namespace="System.Threading"%> <%@Import Namespace="System.Globalization"%> <html> <head> <link rel="stylesheet" href="../i18n_styles.css"> <script language="VB" runat="server"> Dim cult as CultureInfo

Sub Page_Load(sender as Object,args as EventArgs) If(IsPostBack) Then Try cult = new CultureInfo(NewCulture.Value) Catch ' unknown culture cult = Nothing End Try Else cult = CultureInfo.CurrentCulture End If End Sub </script> </head> <body> <h3>I18N: Clase CultureInfo</h3> <p> Este ejemplo utiliza la clase CultureInfo. En el caso del hombre de negocios japons en Suecia, esta clase reflejar el origen del usuario, es decir, Japn. </p> <% If(Not (cult is Nothing)) Then Thread.CurrentThread.CurrentCulture = cult %> Referencia cultural actual: <%= CultureInfo.CurrentCulture.Name %> (<%=Thread.CurrentThread.CurrentCulture.Name%>), <%= CultureInfo.CurrentCulture.EnglishName %>/<%=CultureInfo.CurrentCulture.NativeName%>, Fecha localizada: <%= DateTime.Now.ToString("D", CultureInfo.CurrentCulture) %> <% Else %> <b>Referencia cultural "<%=NewCulture.Value%>" no compatible.</b> <% End If %> <form runat="server"> Cambiar a <input id="NewCulture" type="text" runat="server"> </form> <hr> <center> Algunas referencias culturales de ejemplo: <table width="99%"> <tr> <td><b>Nombre</b></td> <td><b>Nombre ingls</b></td> <td><b>Nombre nativo</b></td> <td><b>LCID</b></td> </tr> <% Dim cultures() As String = { "en-us", "de-de", "ja-jp", "fr-fr" } Dim obj As Object For Each obj In cultures cult = new CultureInfo(obj.ToString())

%> <tr> <td><%=cult.Name%></td> <td><%=cult.EnglishName%></td> <td><%=cult.NativeName%></td> <td><%=cult.LCID%></td> </tr> <% Next %> </table> </center> </body> </html> Utilizar RegionInfo El cdigo de las pginas ASP.NET tambin puede utilizar la clase RegionInfo para suministrar valores de configuracin regional. En el siguiente ejemplo, se muestran las propiedades de una regin. Inicialmente, se muestra la regin predeterminada del servidor. region = RegionInfo.CurrentRegion ... Current region is <%= region.EnglishName %> (<%=region.DisplayName%>), currency is <%= region.CurrencySymbol %>.

En subsiguientes solicitudes, se muestra la regin especificada:


region = New RegionInfo(NewRegion.Value)

<%@Page Language="VB" ResponseEncoding="UTF-8"%> <%@Import Namespace="System.Threading"%> <%@Import Namespace="System.Globalization"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="../i18n_styles.css"> <script runat="server" Language="VB"> Dim _region as RegionInfo = Nothing Sub Page_Load(sender As Object, args As EventArgs) If(IsPostBack) Then Try _region = new RegionInfo(NewRegion.Value) Catch ' unknown region _region = Nothing End Try Else _region = RegionInfo.CurrentRegion End If End Sub

</script> </head> <body> <h3>I18N: Configuracin regional</h3> <p>Este ejemplo utiliza la clase RegionInfo. En el caso del hombre de negocios japons en Suecia, esta clase mostrara la ubicacin en Suecia. </p> <% If(Not(_region is Nothing)) Then %> Regin actual: <%= _region.EnglishName %> (<%=_region.DisplayName%>), moneda: <%= _region.CurrencySymbol %>. <% Else %> <b>Regin "<%=NewRegion.Value%>" no compatible.</b> <% End If %> <form runat="server"> Cambiar a <input id="NewRegion" type="text" runat="server"> </form> <hr> <center> Algunas regiones de ejemplo: <table width="99%"> <tr> <td><b>Nombre</b></td> <td><b>Nombre ingls</b></td> <td><b>Nombre para mostrar</b></td> <td><b>Moneda</b></td> <td><b>Sistema mtrico</b></td> </tr> <% Dim regions() As String = {"us", "de", "jp", "fr", "il"} Dim obj As Object For Each obj In regions _region = new RegionInfo(obj.ToString()) %> <tr> <td><%=_region.Name%></td> <td><%=_region.EnglishName%></td> <td><%=_region.DisplayName%></td> <td><%=_region.CurrencySymbol%></td> <td><%=_region.IsMetric%></td> </tr> <% Next %> </table> </center>

</body> </html>

Resumen de la seccin
ASP.NET puede utilizar pginas que se almacenan con codificacin UTF-8, compatibles con diferentes caracteres nacionales. La clase CultureInfo se puede definir y utilizar, mediante programacin, para adaptar pginas a diferentes entornos regionales. La clase RegionInfo se puede utilizar para suministrar valores de configuracin regional en pginas ASP.NET.

DEPURACION Depurador del SDK .NET Framework de Microsoft


Todos los programadores, por muy competentes que sean, pueden cometer errores en algn momento. Realizar un seguimiento de los problemas en el cdigo puede resultar desesperante si no se dispone de la herramienta adecuada. Afortunadamente, la naturaleza compilada de ASP.NET hace que depurar aplicaciones Web no se diferencie de depurar otras aplicaciones administradas y, adems, el kit de desarrollo de software (SDK) de .NET Framework incluye un pequeo depurador perfectamente adaptado para esta tarea. En esta seccin se describen los pasos necesarios para depurar aplicaciones ASP.NET Framework mediante el depurador suministrado en este SDK. El depurador admite depuracin manual de procesos en un equipo de desarrollo local. La documentacin del depurador incluida en este kit de desarrollo es el mejor recurso para obtener informacin sobre caractersticas especficas.

Habilitar el modo de depuracin para aplicaciones ASP.NET


Ya que muchas partes de una aplicacin ASP.NET Framework se compilan dinmicamente en tiempo de ejecucin (los archivos .aspx y .asmx, por ejemplo), se debe configurar el mdulo de ejecucin de ASP.NET para que compile la aplicacin con informacin simblica antes de poder depurarla. Los smbolos (archivos .pdb) indican al depurador cmo encontrar los archivos de cdigo fuente originales correspondientes a un archivo binario, y cmo asignar los puntos de interrupcin del cdigo a las lneas de los archivos de cdigo fuente. Para configurar una aplicacin de modo que se compile con smbolos, hay que incluir un atributo debug en la seccin compilation del grupo system.web del archivo Web.config correspondiente al directorio raz de la aplicacin, como se indica a continuacin:

<configuration> <compilation debug="true"/> </configuration>


Importante: slo se debera habilitar esta opcin cuando se est depurando una aplicacin, ya que puede afectar significativamente al rendimiento de la aplicacin.

Depurar aplicaciones ASP.NET


Cuando se haya habilitado la depuracin de la aplicacin, se debera realizar la solicitud de la pgina que se desea depurar. Esto hace que se cree el proceso en tiempo de ejecucin de ASP.NET (Aspnet_wp.exe) y que la aplicacin se cargue en memoria. Para iniciar la depuracin: 1. Ejecute el depurador de .NET Framework, DbgClr.exe.

2. 3. 4. 5. 6. 7.

Utilice el men Archivo...Archivos varios...Abrir archivo para abrir el archivo de cdigo fuente correspondiente a la pgina que desea depurar. En el men Herramientas, elija Procesos de depuracin. Aparecer la pantalla de la figura en cuestin. Active la casilla de verificacin Mostrar procesos del sistema, si no est ya activada. Busque el proceso Aspnet_wp.exe y haga doble clic en l para abrir el cuadro de dilogo Asociar al proceso. Asegrese de que la aplicacin aparece en la lista de aplicaciones en ejecucin y seleccione Aceptar para asociarla. Cierre el cuadro de dilogo Programas.

Importante: cuando se asocia el depurador al proceso Aspnet_wp.exe, todos los subprocesos de ese proceso se congelan. No se debera intentar, bajo ninguna circunstancia, depurar una aplicacin que se est utilizando en produccin, ya que las solicitudes de cliente no se podrn ejecutar normalmente hasta que el depurador se desconecte.

Establecer puntos de interrupcin


Para establecer un punto de interrupcin en la pgina, haga clic en el margen izquierdo de una lnea que contenga una instruccin ejecutable o una firma de funcin o mtodo. Aparecer un punto rojo que indicar la posicin del punto de interrupcin. Coloque el puntero del mouse (ratn) sobre el punto de interrupcin para asegurarse de que est bien asociado a la instancia correcta de la aplicacin en el proceso Aspnet_wp.exe. Vuelva a solicitar de nuevo la pgina desde su explorador. El depurador se detiene en el punto de interrupcin y obtiene el foco de la ventana actual. Desde este punto, se puede realizar una ejecucin paso a paso, establecer inspecciones de variables, ver valores locales, obtener informacin de la pila, del cdigo desensamblado, etc. Puede ver los objetos intrnsecos de la pgina, como Request, Response y Session, si utiliza this (C#) o Me (VB) en la ventana de inspeccin.

Generar smbolos para componentes precompilados


Para poder depurar componentes precompilados, tales como objetos empresariales o archivos de cdigo en segundo plano, deber compilar previamente con informacin simblica. Los smbolos para ensamblados se detectan normalmente mediante un algoritmo de bsqueda basado en la ruta de acceso. El algoritmo utilizado por la biblioteca PDB (Mspdb70.dll) para encontrar informacin simblica es el siguiente:

1. Busca en la misma ruta de acceso que el ensamblado. sta es la ubicacin normal para archivos .pdb. Para ensamblados locales, coloque los smbolos (archivos .pdb) en el directorio /bin de la aplicacin con las DLL. 2. Busca en la ruta de acceso especificada en el archivo PE (el encabezado de depuracin NB10).

3.

Busca en ubicaciones de archivos de smbolos de NT (variables de entorno _NT_SYMBOL_PATH y _NT_ALT_SYMBOL_PATH). Nota: si la informacin simblica no se encuentra, el depurador pide al usuario que especifique una ubicacin.

Resumen de la seccin
1. El depurador descrito en esta seccin admite depuracin manual de procesos en un equipo de desarrollo local.

2.

El proceso de depuracin permite al mdulo de ejecucin de ASP.NET compilar dinmicamente con informacin simblica. Esta opcin se puede habilitar si se especifica <compilation debug="true"/> en el archivo Web.config situado en el directorio raz de la aplicacin. Esta opcin del depurador slo se debe habilitar cuando se desee depurar una aplicacin, ya que produce una degradacin del rendimiento de la aplicacin. 3. Para depurar una aplicacin, realice una solicitud de pgina, asocie el depurador al proceso Aspnet_wp.exe, establezca puntos de interrupcin y solicite de nuevo la pgina anterior. 4. Cuando se asocia al proceso Aspnet_wp.exe, todos los subprocesos de ese proceso se congelan. No se debera depurar, bajo ninguna circunstancia, una aplicacin que se est utilizando en produccin, ya que las solicitudes de los clientes no se podrn ejecutar normalmente hasta que el depurador se desconecte. 5. Para poder depurar componentes precompilados, tales como objetos empresariales o archivos de cdigo en segundo plano, deber compilar previamente con informacin simblica.

RENDIMIENTO Introduccin sobre el rendimiento


Aquellas aplicaciones Web que presenten muchas caractersticas no sern de utilidad si no funcionan correctamente. Las exigencias de las aplicaciones Web son de tal naturaleza que, ahora ms que nunca, se espera del cdigo que haga ms en menos tiempo. En esta seccin se describen algunos principios clave del rendimiento de aplicaciones Web, sugerencias para escribir cdigo que se ejecute correctamente y herramientas para medir el rendimiento. ASP.NET proporciona varias mejoras de rendimiento integradas. Por ejemplo, las pginas slo se compilan una vez y se almacenan en cach para posibles solicitudes posteriores. Como estas pginas compiladas se guardan en disco, seguirn siendo vlidas incluso despus de reiniciar completamente el servidor. ASP.NET tambin almacena en cach objetos internos, como variables de servidor, para acelerar el acceso del cdigo del usuario. Adems, ASP.NET aprovecha todas las mejoras de rendimiento de la biblioteca Common Language Runtime: compilacin incremental (Just-in-time), una biblioteca Common Language Runtime optimizada para equipos de un solo procesador o multiprocesador, etc. Sin embargo, todas estas mejoras no sirven de nada si el cdigo est mal escrito. Por ltimo, debe asegurarse de que la aplicacin satisface las necesidades de los usuarios. En la prxima seccin se describen algunas de las formas comunes de evitar cuellos de botella en lo que se refiere al rendimiento. Pero primero es necesario comprender las mtricas siguientes:

Rendimiento: nmero de solicitudes que una aplicacin Web puede atender por unidad de tiempo, generalmente medido en solicitudes/segundo. El rendimiento puede variar en funcin de la carga (nmero de subprocesos cliente) del servidor. Normalmente, se suele considerar que sta es la mtrica de rendimiento ms importante que hay que optimizar. Tiempo de respuesta: tiempo transcurrido entre la emisin de una solicitud y el primer byte devuelto al cliente desde el servidor. ste suele ser el aspecto del rendimiento que mejor puede percibir el usuario cliente. Si una aplicacin tarda mucho en responder, el usuario podra impacientarse y pasar a otro sitio. El tiempo de respuesta puede variar independientemente de la tasa de rendimiento (incluso inversamente). Tiempo de ejecucin: tiempo que tarda en procesarse una solicitud, generalmente entre el primer y el ltimo byte devuelto al cliente desde el servidor. El tiempo de ejecucin afecta directamente al clculo del rendimiento. Escalabilidad: medida de la capacidad de una aplicacin de ofrecer mejor rendimiento a medida que se le asignen ms recursos (memoria, procesos o equipos). Generalmente se trata de una medida de la tasa de cambio del rendimiento con respecto al nmero de procesadores. La base de la programacin de aplicaciones con buen rendimiento es lograr un equilibrio entre estas mtricas. Ninguna medida individual puede caracterizar el comportamiento de la aplicacin en distintas circunstancias; varias medidas realizadas a la vez pueden ofrecer una imagen aproximada del rendimiento de una aplicacin.

Sugerencias de ajuste del rendimiento


Cualquier modelo de programacin tiene problemas de rendimiento comunes y ASP.NET no es una excepcin. En esta seccin se describen algunas formas de evitar los cuellos de botella en lo que se refiere al rendimiento del cdigo.

1.

Deshabilite el estado de sesin cuando no lo utilice: No todas las pginas y aplicaciones requieren estado de la sesin para cada usuario. Si no es necesario, deshabiltelo completamente. Esto se consigue fcilmente mediante una directiva para pginas, como la siguiente:

2.

<%@ Page EnableSessionState="false" %>

Nota: si una pgina necesita acceso a variables de sesin pero no las crea ni las modifica, establezca el valor de la directiva en ReadOnly. Tambin se puede deshabilitar el estado de sesin para mtodos de servicio Web de XML. Vea Utilizar objetos y elementos intrnsecos en la seccin de servicios Web de XML.

3.

Elija cuidadosamente el proveedor de estado de sesin: ASP.NET proporciona tres formas diferentes de almacenar datos de sesin para la aplicacin: estado de sesin en proceso, estado de sesin fuera de proceso como un servicio de Windows y estado de sesin fuera de proceso en una base de datos SQL. Cada una de las formas tiene ventajas, pero el estado de sesin en proceso es con mucho la mejor solucin. Si slo se almacenan pequeas cantidades de datos voltiles en el estado de sesin, sera conveniente utilizar el proveedor en proceso. Las soluciones fuera de proceso son tiles principalmente en escenarios de unidad Web y batera Web, o en situaciones en las que no se pueden perder datos en caso de reinicio del servidor o del proceso.

4.

Evite realizar demasiados viajes de ida y vuelta al servidor: el marco de trabajo de pgina de formularios Web es una de las mejores caractersticas de ASP.NET, porque permite reducir en gran medida la cantidad de cdigo que se debe escribir para realizar una tarea. El acceso mediante programacin a elementos de pgina con controles de servidor y el modelo de control de eventos de devolucin automtica son posiblemente las caractersticas que permiten ahorrar ms tiempo. Sin embargo, hay formas apropiadas y formas no tan apropiadas de utilizar estas caractersticas, y es importante saber cundo es apropiado utilizarlas. Normalmente, una aplicacin slo necesita realizar un viaje de ida y vuelta al servidor para recuperar o almacenar datos. La mayora de las manipulaciones de datos pueden realizarse en el cliente, entre viajes de ida y vuelta. Por ejemplo, la validacin de entradas de formulario suele tener lugar en el cliente antes de que el usuario enve datos. En general, si se tiene que devolver informacin al servidor, no se debe hacer un viaje de ida y vuelta al servidor. Si est programando sus propios controles de servidor, considere la posibilidad de prepararlos con el fin de procesar el cdigo del cliente para exploradores de nivel superior (compatibles con ECMAScript). Al utilizar controles "inteligentes" se puede reducir en gran medida el nmero de visitas innecesarias al servidor Web.

5.

Utilice Page.IsPostback para evitar trabajo adicional en un viaje de ida y vuelta: si controla devoluciones automticas de controles de servidor, a menudo ser necesario ejecutar cdigo diferente la primera vez que se solicite la pgina desde el cdigo que se utiliza para el viaje de ida y vuelta al desencadenarse un evento. Si se activa la propiedad Page.IsPostBack, se podr ejecutar el cdigo condicionalmente, en funcin de si hay una solicitud inicial para la pgina o una respuesta a un evento de control de servidor. Hacer esto puede parecer obvio, pero en la prctica es posible omitir esta opcin sin que se vea modificado el comportamiento de la pgina. Por ejemplo:

<script language="VB" runat="server"> Public ds As DataSet ... Sub Page_Load(sender As Object, e As EventArgs) ' ...set up a connection and command here... If Not (Page.IsPostBack) Dim query As String = "select * from Authors where FirstName like '%JUSTIN%'" myCommand.Fill(ds, "Authors") myDataGrid.DataBind() End If End Sub Sub Button_Click(sender As Object, e As EventArgs) Dim query As String = "select * from Authors where FirstName like '%BRAD%'" myCommand.Fill(ds, "Authors") myDataGrid.DataBind() End Sub </script> <form runat="server"> <asp:datagrid datasource='<%# ds.Tables["Authors"].DefaultView %>' runat="server"/><br> <asp:button onclick="Button_Click" runat="server"/> </form>

1.

El evento Page_Load se ejecuta en cada solicitud, por lo que activamos Page.IsPostBack de forma que la primera consulta no se ejecute cuando procesemos la devolucin automtica del evento Button_Click. Tenga en cuenta que la pgina tendra el mismo comportamiento si no se activara esta opcin, ya que la llamada a DataBind del controlador de eventos volcara el enlace desde la primera consulta. Recuerde que es fcil pasar por alto esta sencilla mejora de rendimiento al escribir pginas.

2.

Utilice pocos controles de servidor y de forma apropiada: aunque son muy fciles de usar, los controles de servidor podran no ser siempre la mejor opcin. En muchos casos se puede lograr el mismo objetivo mediante procesamiento simple o sustitucin de enlace de datos. Por ejemplo:

<script language="VB" runat="server"> Public imagePath As String Sub Page_Load(sender As Object, e As EventArgs) '...retrieve data for imagePath here... DataBind() End Sub </script> <%--the span and img server controls are unecessary...--%> The path to the image is: <span innerhtml='<%# imagePath %>' runat="server"/><br> <img src='<%# imagePath %>' runat="server"/> <br><br> <%-- use databinding to substitute literals instead...--%> The path to the image is: <%# imagePath %><br> <img src='<%# imagePath %>' /> <br><br> <%-- or a simple rendering expression...--%> The path to the image is: <%= imagePath %><br> <img src='<%= imagePath %>' />

1. En este ejemplo no es necesario un control de servidor para reemplazar valores en el cdigo HTML resultante que se devuelve al cliente. Hay muchos otros casos en los que esta tcnica funciona correctamente, incluso en plantillas de control de servidor. Sin embargo, si desea manipular mediante programacin las propiedades del control, controlar eventos desde el control o aprovechar su conservacin de estado, lo ms apropiado es utilizar un control de servidor. Debe analizar el uso de los controles de servidor y localizar el cdigo que se puede optimizar.

2.

Evite utilizar demasiado el estado de vista de un control de servidor: la administracin automtica de estados es una caracterstica que permite a los controles de servidor volver a llenar sus valores en un viaje de ida y vuelta sin que sea necesario programar cdigo. Sin embargo esta caracterstica no es libre, ya que el estado de un control se pasa al servidor y se recibe del servidor en un campo de formulario oculto. Debe saber cundo resulta til ViewState y cuando no. Por ejemplo, si enlaza un control a datos en cada viaje de ida y vuelta (como en la cuadrcula de datos de la sugerencia N 4), no necesita que el control mantenga su estado de vista, ya que en cualquier caso se eliminarn los datos con los que se vuelva a llenar. La opcin ViewState est habilitada de forma predeterminada para todos los controles de servidor. Para deshabilitarla, establezca el valor de la propiedad EnableViewState del control en false, como se indica en el siguiente ejemplo:

<asp:datagrid EnableViewState="false" datasource="..." runat="server"/>


Tambin puede desactivar ViewState para la pgina. Esto es til cuando no se realizan devoluciones automticas desde una pgina, como en el siguiente ejemplo:

<%@ Page EnableViewState="false" %>


Tenga en cuenta que tambin se admite este atributo mediante la directiva User Control. Para analizar la cantidad de estado de vista utilizado por los controles de servidor de la pgina, habilite el seguimiento y vea la columna Estado de vista en la tabla Jerarqua de controles. Para obtener informacin acerca de la caracterstica Seguimiento y la forma de habilitarla, vea la caracterstica Registro de seguimiento de aplicacin.

3.

Utilice el mtodo Response.Write para concatenar cadenas: utilice el mtodo HttpResponse.Write en las pginas o controles de usuario para concatenar cadenas. Este mtodo ofrece servicios de bfer y concatenacin muy eficaces. En el caso de que pretenda realizar una concatenacin compleja, la tcnica descrita en el ejemplo siguiente (utilizando varias llamadas a Response.Write) resulta ms rpido que concatenar una cadena con una sola llamada al mtodo Response.Write.

Response.Write("a") Response.Write(myString) Response.Write("b") Response.Write(myObj.ToString()) Response.Write("c") Response.Write(myString2) Response.Write("d")

1.

No utilice las excepciones del cdigo: las excepciones son costosas y raramente se producen en el cdigo. Nunca debe utilizar las excepciones como una forma de controlar el flujo normal de un programa. Si es posible detectar en el cdigo una condicin que puede causar una excepcin, debe hacerlo en lugar de esperar a detectar la excepcin antes de controlar la condicin. Algunos escenarios comunes incluyen la comprobacin de valores NULL, la asignacin a una cadena que se analizar para devolver un valor numrico o la comprobacin de valores especficos antes de aplicar operaciones matemticas. Por ejemplo:

' Consider changing this: Try result = 100 / num Catch (e As Exception) result = 0 End Try // To this: If Not (num = 0) result = 100 / num Else result = 0 End If

1.

Utilice enlace en tiempo de compilacin en cdigo de Visual Basic o JScript: una de las ventajas de Visual Basic, VBScript y JScript es su naturaleza de lenguaje sin tipos. Es posible crear variables simplemente utilizndolas sin necesidad de una declaracin explcita de tipo. Al realizar una asignacin de un tipo a otro, las conversiones tambin se realizan automticamente. Esto puede ser una ventaja y una desventaja, ya que el enlace en tiempo de ejecucin es una utilidad muy costosa en trminos de rendimiento. Ahora el lenguaje Visual Basic admite programacin protegida por tipos mediante el uso de una directiva de compilador especial, Option Strict. Por compatibilidad con las versiones anteriores, ASP.NET no habilita Option Strict de forma predeterminada. Sin embargo, con el fin de obtener un rendimiento ptimo debe habilitar Option Strict para las pginas mediante un atributo Strict en la pgina o la directiva Control:

<%@ Page Language="VB" Strict="true" %> <% Dim B Dim C As String ' This causes a compiler error: A = "Hello" ' This causes a compiler error: B = "World"

' This does not: C = "!!!!!!" ' But this does: C=0 %>
JScript tambin admite la programacin sin tipos, aunque no ofrece ninguna directiva de compilador para forzar el enlace en tiempo de compilacin. Una variable se enlaza en tiempo de ejecucin si:

o o o

Se declara explcitamente como un objeto. Es un campo de una clase sin ninguna declaracin de tipo. Es un miembro privado de funcin o mtodo privado sin declaracin explcita de tipos, y no se puede inferir su tipo a partir de su uso. La ltima distincin es complicada. El compilador de JScript se optimizar si puede averiguar cul es el tipo a partir del uso de la variable. En el siguiente ejemplo, la variable A se enlaza en tiempo de compilacin; en cambio, la variable B se enlaza en tiempo de ejecucin:

var A; var B; A = "Hello"; B = "World"; B = 0;


Para obtener el mejor rendimiento, declare las variables de JScript como variables con tipo. Por ejemplo, "var A : String".

2.

Adapte los componentes COM que requieran muchas llamadas a cdigo administrado: la plataforma .NET Framework proporciona una manera sencilla de interoperar con componentes COM tradicionales. La ventaja es que puede aprovechar la nueva plataforma manteniendo el cdigo existente. Sin embargo, hay algunas circunstancias en las que el coste de rendimiento que supone mantener los componentes antiguos es mayor que el coste de migrar los componentes a cdigo administrado. Cada situacin es nica y la mejor manera de decidir qu cambios son necesarios es medir el rendimiento del sitio. Sin embargo, en general el impacto en el rendimiento de la interoperabilidad COM es proporcional al nmero de llamadas a funciones realizadas o la cantidad de datos para los que se calculan referencias de cdigo no administrado a cdigo administrado. Un componente que requiere un volumen elevado de llamadas para interactuar se denomina "hablador" a causa del nmero de comunicaciones entre capas. Debe considerar la posibilidad de adaptar estos componentes a cdigo totalmente administrado para aprovechar las mejoras de rendimiento proporcionadas por la plataforma .NET. Como alternativa, puede considerar la posibilidad de volver a disear el componente para que requiera menos llamadas o para calcular ms referencias de datos simultneamente.

3.

Utilice procedimientos SQL almacenados para el acceso a datos: de todos los mtodos de acceso a datos proporcionados por .NET Framework, el acceso a datos basado en SQL es la mejor opcin para generar aplicaciones Web escalables con el mejor rendimiento. Al utilizar el proveedor de SQL administrado, se obtiene un aumento de rendimiento adicional mediante el uso de procedimientos almacenados compilados en lugar de consultas ad hoc. Si desea examinar un ejemplo de uso de procedimientos almacenados de SQL, vea la seccin Acceso a datos en el servidor de este tutorial.

4.

Utilice SqlDataReader para obtener un cursor de datos de desplazamiento hacia adelante rpido: un objeto SqlDataReader proporciona un cursor hacia adelante de slo lectura para datos obtenidos de una base de datos de SQL. El rendimiento de SqlDataReader es mejor que el uso de un objeto DataSet, si puede utilizarlo en el escenario. Como SqlDataReader es compatible con la interfaz IEnumerable, tambin es posible enlazar controles de servidor. Si desea examinar un ejemplo de uso SqlDataReader, vea la seccin Acceso a datos en el servidor de este tutorial.

5.

Almacene en cach datos y resultados siempre que sea posible: el modelo de programacin ASP.NET proporciona un mecanismo sencillo para almacenar en cach resultados o datos de pginas cuando no sea necesario calcularlos dinmicamente para cada solicitud. Puede disear las pginas con almacenamiento en cach con el fin de optimizar los puntos de la aplicacin en los que espera que haya ms trfico. El uso apropiado del almacenamiento en cach es ms importante que ninguna otra caracterstica de la plataforma .NET Framework con el fin de mejorar el rendimiento del sitio, a veces en un orden de magnitud e incluso ms. Para obtener ms informacin sobre cmo utilizar el almacenamiento en cach, vea la seccin Servicios de almacenamiento en cach de este tutorial.

6.

Habilite el uso de unidades Web para equipos multiprocesador: el modelo de procesos de ASP.NET permite habilitar la escalabilidad en equipos con varios procesadores distribuyendo el trabajo entre varios procesos, uno para cada CPU, cada uno con la afinidad de procesador establecida en la CPU correspondiente. Esta tcnica se denominada Uso de unidades Web y permite mejorar en gran medida el rendimiento de algunas aplicaciones. Para aprender a habilitar el uso de unidades Web, consulte la seccin Utilizar el modelo de procesos.

7.

No olvide deshabilitar el modo de depuracin: la seccin <compilacin> de la configuracin de ASP.NET controla si una aplicacin se compila en modo de depuracin o no. El modo de depuracin degrada en gran medida el rendimiento. Recuerde siempre que debe deshabilitar este modo antes de implantar una aplicacin de produccin o medir el rendimiento. Para obtener ms informacin acerca del modo de depuracin, vea la seccin titulada Depurador de SDK.

Medir el rendimiento
La medicin del rendimiento de un servidor Web es una caracterstica que slo se puede mejorar mediante la experiencia y la experimentacin continua. Hay muchas variables en juego, como el nmero de clientes, la velocidad de las conexiones de clientes, los recursos de servidor, el cdigo de la aplicacin, etc. Para ello resulta til tener buenas herramientas y, afortunadamente, estas herramientas estn disponibles. Microsoft proporciona la herramienta Web Application Stress (WAS), que simula la conexin al sitio Web de varios clientes HTTP. Es posible controlar la carga de clientes, el nmero de conexiones, el formato de las cookies, los encabezados y otros parmetros de la interfaz grfica de la herramienta. Despus de una ejecucin de prueba, WAS proporciona informes con mtricas de rendimiento, como los datos de tiempo de respuesta, de rendimiento y de contadores de rendimiento relevantes para la aplicacin. El objetivo es sencillo: maximizar el rendimiento y el uso de la CPU para altos niveles de carga. WAS est disponible en el Kit de recursos de Microsoft Internet Information Server y tambin se puede descargar por separado desde la direccin http://webtool.rte.microsoft.com. ASP.NET tambin expone varios contadores de rendimiento que se pueden utilizar para hacer un seguimiento de las aplicaciones. A diferencia de la tecnologa ASP tradicional, la mayora de estos contadores de rendimiento se exponen para aplicaciones individuales, en lugar de exponerse globalmente para todo el equipo. Los contadores para aplicaciones estn disponibles con el objeto de rendimiento de aplicaciones ASP.NET Framework; hay que seleccionar una instancia de aplicacin concreta al seleccionar un contador para supervisar. Por supuesto, an podrn verse los valores del contador para todas las aplicaciones que utilicen una instancia de aplicacin especial "__Total__" en el monitor de sistema. ASP.NET tambin expone contadores que son slo globales y que no estn enlazados a ninguna instancia de aplicacin especfica. Estos contadores se encuentran con el objeto de rendimiento del sistema de ASP.NET. Para poder ver todos los contadores disponibles de ASP.NET (en sistemas Windows 2000):

1. 2. 3. 4. 5.

Seleccione Inicio->Programas->Herramientas administrativas->Rendimiento. Haga clic en el botn Ver informe del Monitor de sistema. Haga clic en el botn Agregar.

Seleccione Aplicaciones ASP.NET y despus seleccione el botn de opcin Todos los contadores. Haga clic en Aceptar. Seleccione ASP.NET y despus seleccione el botn de opcin Todos los contadores. Haga clic en Aceptar.

La caracterstica de seguimiento de ASP.NET tambin resulta til para identificar cuellos de botella de rendimiento en el cdigo. Puede mostrar informacin temporal importante entre sucesivas instrucciones con resultados de seguimiento, as como informacin acerca de la jerarqua de control del servidor, la cantidad de estado de vista utilizado y el tamao de procesamiento de los controles en la pgina. Para obtener ms informacin acerca de la caracterstica Seguimiento, vea la seccin Realizar un seguimiento de este tutorial.

APLICACIONES DE EJEMPLO Portal personalizado


Este ejemplo ilustra una aplicacin de pgina principal de portal personalizado. La aplicacin permite a los usuarios personalizar una pgina principal para mostrar varios mdulos de su eleccin, como un directorio de sitios o una lista de vnculos favoritos. Cada mdulo se implementa como un control de usuario que se agrega dinmicamente a la pgina principal si el usuario ha elegido incluirlo. Los datos de configuracin relacionados con la personalizacin se mantienen en una base de datos SQL y se recuperan mediante un componente de mdulo HTTP de personalizacin (que funciona de forma muy similar a los mdulos HTTP de estado de la sesin y de estado de la aplicacin). Cada pgina de la aplicacin hereda de una clase base comn Page que est por detrs del cdigo y que utiliza el componente de personalizacin para exponer un diccionario especial denominado UserState. Este diccionario UserState proporciona a las pginas de la aplicacin acceso a la configuracin de personalizacin de usuario (como pares de cadenas clave/valor). Adems de almacenar las selecciones del mdulo del usuario, el diccionario UserState almacena otros parmetros de personalizacin, como los esquemas de colores. Los mdulos individuales tambin pueden utilizar el diccionario UserState para almacenar sus propias configuraciones de personalizacin. La aplicacin de portal utiliza el valor de FormsAuthenticationModule para la autenticacin de usuarios. Cuando un usuario solicita por primera vez visitar la pgina principal, se muestra la configuracin de un usuario annimo. Si el usuario intenta tener acceso a una parte del portal que est restringida a usuarios autenticados (como la pgina de personalizacin del mdulo), el mdulo FormsAuthenticationModule lo redirige a una pgina de inicio de sesin para que escriba sus credenciales. Los usuarios que no hayan iniciado nunca una sesin pueden utilizar un formulario de registro para crear una nueva cuenta de usuario con su contrasea. En visitas posteriores a la pgina principal del portal, los usuarios slo tendrn que iniciar una sesin con estas credenciales de cuenta (que se comprobarn en una base de datos SQL). Para empezar a explorar la aplicacin de portal, siga los pasos descritos arriba para crear una cuenta de usuario. Cuando haya creado su cuenta, podr explorar y personalizar todo el portal.

<%@ Page Language="VB" Inherits="DefaultPage" Src="Default.vb" Description="Main Portal Page" %> <%@ Register TagPrefix="LoginModule" TagName="LoginModule" Src="modules/login/login.ascx" %>

<html> <head> <title>ASP.NET PORTAL SITE</title> </head> <body bgcolor="<%=UserState("BackColor")%>" style="margin:0,0,0,0"> <form runat=server> <table border=0 width="100%" cellspacing=0 cellpadding=0 bgcolor="ffffff"> <tr> <td align=left> <img src="/Quickstart/aspplus/samples/portal/VB/images\home_<%# UserState("ColorScheme") %>.gif"> </td> <td align=right valign=top style="padding:5,15,5,5"> <font face=Arial size=-1> <a href="/Quickstart/aspplus/samples/portal/VB/default.aspx?default.aspx">Actualizar</a> <a OnServerClick="SignOff_Click" runat=server>Cerrar sesin</a> </font> </td> </tr> <tr height="8"/> </table> <table border=0 width="100%" bgcolor="ffffff" cellspacing=0 cellpadding=0 > <tr> <span id="PagePanelLinks" EnableViewState="false" runat=server/> <td width="1%">&nbsp;</td> <td align=right bgcolor="<%=UserState("SubheadColor")%>" width="50%" style="padding:0,10,0,0"> <font size=-1 face=Arial> [<a id="anchorAdd" href="" OnServerClick="AddPage_Click" runat="server">Agregar pgina</a> <asp:Label id="spanAdd" Text="&nbsp;-&nbsp;" runat="server"/> <a id="anchorDelete" href="" runat="server">Eliminar pgina</a> <asp:Label id="spanDelete" Text="&nbsp;-&nbsp;" runat="server"/> <a id="anchorOptions" href="" runat="server">Cambiar colores</a>] </font> </td> </tr> <tr> <td width="100%" colspan=11> <table border=0 cellspacing=0 width="100%"> <tr> <td bgcolor="<%=UserState("HeadColor")%>"> <table border=0 cellspacing=0 cellpadding=0> <tr><td height=3></td></tr> </table> </td> </tr> </table> </td> </tr> </table> <table border=0 width="100%" cellspacing=0 cellpadding=0 style="padding:0,0,0,0"> <tr> <td width="1%" valign="top"> <table border=0 width="100%" cellspacing=10 cellpadding=0 style="padding:0,0,0,0">

<tr valign="top"> <td height="10" style="padding-top:5" align="left"> <table cellpadding=0 cellspacing=0> <tr> <td><img border=0 src="/Quickstart/aspplus/samples/portal/VB/images\personal.gif"></td> <td><a id="anchorCustomize" runat="server"><img border=0 src="/Quickstart/aspplus/samples/portal/VB/images\content.gif"></a></td> <td><img border=0 src="/Quickstart/aspplus/samples/portal/VB/images\space.gif"></td> <td><a id="anchorOptions2" runat="server"><img border=0 src="/Quickstart/aspplus/samples/portal/VB/images\layout.gif"></a></td> </tr> </table> </td> </tr> <tr> <td> <!-- BEGIN DYNAMIC LEFT MODULE LIST --> <asp:Panel id="Login" EnableViewState="false" visible="false" runat="server"> <LoginModule:LoginModule runat="server"/> </asp:Panel> <asp:PlaceHolder id="LeftUIModules" runat=server/> <!-- END DYNAMIC LEFT MODULE LIST --> </td> </tr> </table> </td> <td width="99%" valign="top"> <table border=0 width="100%" cellspacing=10 cellpadding=0> <!-- BEGIN DYNAMIC RIGHT MODULE LIST --> <asp:PlaceHolder id="RightUIModules" runat=server/> <!-- END DYNAMIC RIGHT MODULE LIST --> </table> </td> </tr> </table> </form> </body> </html>

Establecimiento de comercio electrnico


La siguiente aplicacin de ejemplo es una maqueta de un tpico establecimiento de comercio electrnico. La aplicacin muestra los elementos ms habituales de este tipo de aplicaciones: un explorador de productos, un carrito de compra para la sesin, detalles de productos, etc. Para almacenar los datos de los productos, se utiliza una base de datos SQL Server, mientras que para compilar esos datos, se utilizan los controles DataList y Repeater. La parte de acceso a datos de la aplicacin se implementa como un componente administrado.

<%@ Import Namespace="System.Data" %> <%@ Import Namespace="Market" %> <html> <head> <title>GrocerToGo</title> <link rel="stylesheet"href="grocerstyle.css">

<style> div.details { background-color:ffffcc; padding-top:15; padding-bottom:20; } div.details table { width:375; } div.details table td { font-family:Verdana; font-size:8pt; } </style> <script language="VB" runat=server> public Sub Page_Load(sender As Object, e As EventArgs) if (Not IsPostBack) Then ProductListing.SelectedIndex = 0 UpdateProducts() UpdateShoppingCart() End If End Sub public Sub CategoryList_Select(sender As Object, e As EventArgs) CurrentCategory.Text = CategoryList.Items(CategoryList.SelectedIndex).Text UpdateProducts() End Sub public Sub ProductListing_Select(sender As Object, e As EventArgs) UpdateProducts() End Sub public Sub AddBtn_Click(sender As Object, e As ImageClickEventArgs) Dim productID As Integer productID = Int32.Parse(ProductListing.DataKeys(ProductListing.SelectedIndex).ToString()) Dim market As InventoryDB market = new InventoryDB() Dim product As DataRow product = market.GetProduct(productID) Dim shoppingCart As Market.OrderList shoppingCart = Ctype(Session("ShoppingCart"), Market.OrderList) shoppingCart.Add(new Market.OrderItem(productID, CStr(product("ProductName")), Double.Parse(product("UnitPrice").ToString()), 1)) UpdateShoppingCart() End Sub public Sub Recalculate_Click(sender As Object, e As ImageClickEventArgs) ' Obtain Shopping Cart From Session State Dim shoppingCart As Market.OrderList shoppingCart = Ctype(Session("ShoppingCart"), Market.OrderList) ' Iterate over items in shopping cart (update cart with current row qty textbox value Dim i As Integer Dim qty As HtmlInputText

for i = 0 To ShoppingCartList.Items.Count - 1 qty = Ctype(ShoppingCartList.Items(i).FindControl("Qty"), HtmlInputText) Try shoppingCart(CStr(ShoppingCartList.DataKeys(i))).Quantity = CInt(qty.Value) Catch exc As Exception End Try Next i UpdateShoppingCart() End Sub public Sub ClearCart_Click(sender As Object, e As ImageClickEventArgs) ' Obtain access to Shopping Cart From Session State Dim shoppingCart As Market.OrderList shoppingCart = Ctype(Session("ShoppingCart"), Market.OrderList) ' Clear Items From Shopping Cart and then Update UI shoppingCart.ClearCart() UpdateShoppingCart() End Sub Sub UpdateProducts() Dim market As New InventoryDB ' Update Product Listing at Bottom of Page Dim categoryID As Integer categoryID = Int32.Parse(CategoryList.Items(CategoryList.SelectedIndex).Value) ProductListing.DataSource = market.GetProducts(categoryID).DefaultView ProductListing.DataBind() ' Update Product Information Dim productID As Integer productID = Int32.Parse(ProductListing.DataKeys(ProductListing.SelectedIndex).ToString()) Dim product As DataRow product = market.GetProduct(productID) Name.Text = product("ProductName").ToString() SelectedProdPicture.Src = product("ImagePath").ToString() ServingSize.Text = product("ServingSize").ToString() Servings.Text = product("Servings").ToString() ' Update Product Calory Information DetailsListing.DataSource = market.GetProductCalories(productID).DefaultView DetailsListing.DataBind() End Sub Sub UpdateShoppingCart() ' Update Shopping Cart UI from Basket Stored in Session State Dim shoppingCart As Market.OrderList shoppingCart = Ctype(Session("ShoppingCart"), Market.OrderList) SubTotal.Text = System.String.Format("{0:C}", shoppingCart.SubTotal)

Tax.Text = System.String.Format("{0:C}", shoppingCart.Tax) Total.Text = System.String.Format("{0:C}", shoppingCart.Total) ShoppingCartList.DataSource = shoppingCart.Values ShoppingCartList.DataBind() End Sub </script> </head> <body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0"> <form runat="server"> <table cellspacing=0 cellpadding=3 bgcolor="DC6035" border=0 width="100%"> <tr> <td align="left"><img src="images/logo.gif"></td> <td align="right"> <a><img border=0 src="images/home.gif"></a> </td> </tr> <tr> <td align="right" class="seleccionar" colspan="2"> <b>Seleccionar una categora: &nbsp;</b> <select id="CategoryList" style="width:75" runat="server"> <option selected value="1">Leche</option> <option value="2">Cereales</option> <option value="3">Refresco</option> </select> <asp:button text="Seleccionar" OnClick="CategoryList_Select" runat=server/> </td> </tr> </table> <table border=0 width=100% cellspacing=0 cellpadding=15 bgcolor="ffffcc"> <tr> <td valign=top bgcolor=ffffcc> <p> <h3> <b>Categora del producto: <asp:label id="CurrentCategory" runat=server>Leche</asp:label><b> </h3> <table width="100%" cellpadding=0 cellspacing=0 > <tr style="padding-left:12" > <td align="center" style="border-style:inset;" bgcolor="EDBE7B" width=140> <img id="SelectedProdPicture" runat=server> </td> <td align="center" bgcolor="ffffcc" style="padding-right:0;"> <div class="details"> <table cellpadding=1 > <tr> <td colspan=3>

<b><font face="Verdana" size=3><asp:label id="Name" runat=server> </asp:label></font></b> </td> <td align=right> <asp:imagebutton ImageUrl="images/addcart.gif" OnClick="AddBtn_Click" runat=server/> </td> </tr> <tr> <td colspan=4 > Tamao de la racin <asp:label id="ServingSize" runat=server> </asp:label> </td> </tr> <tr> <td colspan=4> Raciones por envase <asp:label id="Servings" runat=server> </asp:label> </td> </tr> <tr> <td height=5 colspan=4 bgcolor="000000"></td> </tr> </table> <asp:repeater id="DetailsListing" runat="server"> <ItemTemplate> <table cellpadding=0> <tr> <td colspan=3> <b><%# DataBinder.Eval(Container.DataItem, "Name") %></b> <%# DataBinder.Eval(Container.DataItem, "Grams") %> </td> <td align=right> <b><%# DataBinder.Eval(Container.DataItem, "Percent") %>%</b> </td> </tr> </table> </ItemTemplate> <SeparatorTemplate> <table cellpadding=0 > <tr> <td colspan=4 height=1 bgcolor="000000"></td> </tr> </table> </SeparatorTemplate> <FooterTemplate> <table cellpadding=0 > <tr> <td colspan=4 height=5 bgcolor="000000"></td> </tr> </table> </FooterTemplate> </asp:repeater> </div> </td> </tr> </table> <p>

<table> <tr> <td class="Products"> <asp:datalist id="ProductListing" DataKeyField="ProductID" showheader=false showfooter=false OnSelectedIndexChanged="ProductListing_Select" repeatdirection="horizontal" borderwidth=0 runat="server"> <ItemTemplate> <table> <tr> <td width="150"> <asp:imagebutton borderwidth=6 bordercolor="#ffffcc" commandname="Select" ImageUrl='<%# DataBinder.Eval(Container.DataItem, "ImagePath") %>' runat=server/> <p> <%# DataBinder.Eval(Container.DataItem, "ProductName") %> <br> <%# DataBinder.Eval(Container.DataItem, "UnitPrice", "{0:C}") %><br> </td> </tr> </table> </ItemTemplate> <SelectedItemTemplate> <table> <tr> <td width="150"> <asp:imagebutton borderwidth=6 bordercolor="red" commandname="select" ImageUrl='<%# DataBinder.Eval(Container.DataItem, "ImagePath") %>' runat=server/> <p> <%# DataBinder.Eval(Container.DataItem, "ProductName") %><br> <%# DataBinder.Eval(Container.DataItem, "UnitPrice", "{0:C}") %><br> </td> </tr> </table> </SelectedItemTemplate> </asp:datalist> </td> </tr> </table> </td> <td width="315" valign=top class="cart" bgcolor="#EDBE7B"> <h3>Carro de la compra</h3> <asp:datalist id="ShoppingCartList" DataKeyField="Name" borderwidth=0 runat="server"> <HeaderTemplate> <table width="100%">

<tr> <td width=35> <b>Ctd.</b> </td> <td width=175> <b>Producto</b> </td> <td width=50> <b>Precio</b> </td> <td align="right" style="padding-right:10"> <b>Total</b> </td> </tr> </HeaderTemplate> <ItemTemplate> <tr> <td width=35> <input type=text size=1 id="Qty" runat=server value='<%# DataBinder.Eval(Container.DataItem, "Quantity") %>'> </td> <td width=175> <%# DataBinder.Eval(Container.DataItem, "Name") %> </td> <td width=50> <%# DataBinder.Eval(Container.DataItem, "Price", "{0:C}") %> </td> <td align=right style="padding-right:10"> <%# DataBinder.Eval(Container.DataItem, "Total", "{0:C}") %> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:datalist> <table border=0 width="100%"> <tr> <td colspan=4><hr></td> </tr> <tr> <td width=52></td> <td width=225 colspan="2" align="left"> <b>Subtotal</b> </td> <td align="right" style="padding-right:10"> <asp:label id="Subtotal" runat=server/> </td> </tr> <tr> <td width=52></td> <td width=225 colspan="2" align="left"> <b>Impuestos</b> </td>

<td align="right" style="padding-right:10"> <asp:label id="Tax" runat=server/> </td> </tr> <tr> <td width=52></td> <td width=225 colspan="2" align="left"> <b>Total general</b> </td> <td align="right" style="padding-right:10"> <b><asp:label id="Total" runat=server/></b> </td> </tr> </table> <p> <div id="CheckoutPanel" runat="server"> <center> <asp:imagebutton borderwidth=0 OnClick="Recalculate_Click" ImageUrl='images\recalculate.gif' runat=server/> <asp:imagebutton borderwidth=0 ImageUrl='images\checkout.gif' runat=server/> <asp:imagebutton borderwidth=0 OnClick="ClearCart_Click" ImageUrl='images\clear_cart.gif' runat=server/> </center> </div> </td> </tr> </table> </form> </body> </html>

Aplicacin de un examinador de clases


La siguiente aplicacin de ejemplo implementa un examinador de clases basado en .NET Framework y utiliza las API System.Reflection para recopilar informacin acerca de una clase. Para simplificar el cdigo .aspx, la aplicacin emplea un componente administrado que encapsula los detalles de la reflexin. La propia pgina .aspx depende enormemente de varios controles DataList para obtener los espacios de nombres, clases y detalles de clases. El ejemplo tambin muestra el uso de controles DataList anidados para procesar las listas de parmetros. Si desea ver el ejemplo, haga clic en el icono que aparece a continuacin.

<%@ Page Debug="true" %> <%@ Import NameSpace="ClassInfoVB" %> <%@ Import NameSpace="System.Collections" %> <%@ Import NameSpace="System.Collections.Specialized" %> <%@ Import NameSpace="System.Reflection" %> <html> <head> <title>Explorador de clases de .NET Framework</title> <link rel="stylesheet" href="../classstyle.css"> <script runat="server" language="VB"> public SelectedAssembly As String public SelectedNameSpace As String public ModuleName As New ArrayList() Protected Sub Page_Load(Sender As Object, e As EventArgs)

Dim ConfigSettings As NameValueCollection = CType(Context.GetConfig("system.web/ClassBrowser"), NameValueCollection) Dim I As Integer For I = 0 To ConfigSettings.Count - 1 ModuleName.Add(ConfigSettings(I).ToString()) Next DisplayNamespaces() If Request.QueryString("namespace") Is Nothing Then SelectedNameSpace = "System" Else SelectedNameSpace = Request.QueryString("namespace") End If If Request.QueryString("assembly") Is Nothing Or Request.QueryString("assembly") = "" Then SelectedAssembly = "mscorlib" Else SelectedAssembly = Request.QueryString("assembly") End If If Not Request.QueryString("class") Is Nothing And Not Request.QueryString("assembly") Is Nothing Then DisplayClass(Request.QueryString("assembly"), Request.QueryString("class")) Else DisplayClassList(SelectedNameSpace) End If End Sub Private Sub DisplayNamespaces() Dim NameSpaceList As New ArrayList() Dim NameSpaceHash As New Hashtable() Dim Y As Integer For Y = 0 To ModuleName.Count - 1 Dim CorRuntime() As System.Reflection.Module = System.Reflection.Assembly.Load(ModuleName(y).ToString()).GetModules() Dim CorClasses() As Type = CorRuntime(0).GetTypes() Dim X As Integer For X = 0 To CorClasses.Length - 1 If Not CorClasses(x).Namespace Is Nothing If Not NameSpaceHash.ContainsKey(CorClasses(x).Namespace) And CorClasses(x).IsPublic NameSpaceHash.Add(CorClasses(x).Namespace,"") NameSpaceList.Add(CorClasses(x).Namespace) End If End If Next Next NameSpaceList.Sort() Namespace1.DataSource = NameSpaceList Namespace1.DataBind() End Sub Private Sub DisplayClassList(CurrentNameSpace As String) Dim ClassList As New ArrayList() Dim InterfaceList As New ArrayList() Dim Y As Integer

For Y = 0 To ModuleName.Count - 1 Dim CorRuntime() As System.Reflection.Module = System.Reflection.Assembly.Load(ModuleName(y).ToString()).GetModules() Dim CorClasses() As Type = CorRuntime(0).GetTypes() Dim X As Integer For X = 0 To CorClasses.Length - 1 If CorClasses(x).Namespace = CurrentNameSpace And CorClasses(x).IsPublic Dim props As New SortTable("GetType") props("GetType") = CorClasses(x).Name props("Namespace") = CorClasses(x).Namespace props("Assembly") = CorClasses(x).Assembly.ToString() If CorClasses(x).IsInterface InterfaceList.Add(props) Else ClassList.Add(props) End If End If Next Next If InterfaceList.Count > 0 Then IHeader.Visible = true If ClassList.Count > 0 Then CHeader.Visible = true ClassList.Sort() Classes.DataSource = ClassList Classes.DataBind() InterfaceList.Sort() Interfaces.DataSource = InterfaceList Interfaces.DataBind() End Sub Private Sub DisplayClass(asmName As String, className As String) If asmName Is Nothing Or asmName = "" Then DisplayClassList(SelectedNamespace) Return End If Dim a As System.Reflection.Assembly = System.Reflection.Assembly.Load(asmName) Dim ClassType As Type = a.GetType(SelectedNameSpace.ToString() & "." & className, False, True) If ClassType Is Nothing Then DisplayClassList(SelectedNameSpace) Return End If Dim SubClassDetails As ArrayList = New DisplaySubClasses(ClassType, ModuleName) Dim ConstructorDetails As DisplayConstructors = New DisplayConstructors(ClassType) Dim FieldDetails As DisplayFields = New DisplayFields(ClassType) Dim PropertyDetails As DisplayProperties = new DisplayProperties(ClassType) Dim MethodDetails As DisplayMethods = new DisplayMethods(ClassType, className) Dim SuperClassDetails As DisplaySuperclasses = new DisplaySuperclasses(ClassType) Dim InterfaceDetails As DisplayInterfaces = new DisplayInterfaces(ClassType) Dim EventDetails As DisplayEvents = new DisplayEvents(ClassType) If ConstructorDetails.Count <> 0 Then Constructors.DataSource = ConstructorDetails

If SubClassDetails.Count <> 0 Then SubClasses.DataSource = SubClassDetails If FieldDetails.Count <> 0 Then Fields.DataSource = FieldDetails If PropertyDetails.Count <> 0 Then Properties.DataSource = PropertyDetails If MethodDetails.Count <> 0 Then Methods.DataSource = MethodDetails If InterfaceDetails.Count <> 0 Then Interface1.DataSource = InterfaceDetails If SuperClassDetails.Count <> 0 Then SuperClasses.DataSource = SuperClassDetails If EventDetails.Count <> 0 Then Events.DataSource = EventDetails DataBind() If ClassType.IsInterface Then spnClassName.InnerHtml = "Interfaz" & SelectedNameSpace & "." & className Else spnClassName.InnerHtml = "Clase" & SelectedNameSpace & "." & className End If NameSpacePanel.Visible = False ClassPanel.Visible = True End Sub Function GetUrl(objTable As Object) As String If TypeOf objTable Is String Then return "classbrowser.aspx?assembly=" & SelectedAssembly & "&namespace=" & SelectedNameSpace & "&class=" & objTable End If If Not TypeOf objTable Is Hashtable Then Response.Write(objTable.GetType().ToString()) Response.End() End If Dim table As Hashtable = CType(objTable, Hashtable) Return "classbrowser.aspx?assembly=" & table("Assembly") & "&namespace=" & table("Namespace") & "&class=" & table("GetType") End Function </script> </head> <body> <form runat="server"> <table class="top" width=100% height="40" cellpadding=0 cellspacing=0> <tr> <td bgcolor=#000666> <b><font size=5 color=white>Explorador de clases de .NET Framework</b> </td> </tr> </table> <table width=100% height=700 cellpadding=0 cellspacing=0> <tr> <td width=25% bgcolor=#CCCCFF valign=top > <br> <asp:DataList EnableViewState="false" runat=server id="Namespace1" RepeatLayOut="flow" ItemStyle-Font-Size="9pt" HeaderStyle-Font-Size="12pt" > <HeaderTemplate> <div left-margin="10"> <font size=4> <b>Espacios de nombres</b> </font> <br> </HeaderTemplate> <ItemTemplate> <asp:HyperLink runat="server" text=<%# Container.DataItem %> NavigateUrl=<%# "classbrowser.aspx?namespace=" + Container.DataItem %> /> </ItemTemplate>

<SelectedItemTemplate> <b><asp:HyperLink runat=server text=<%# Container.DataItem %>/></b> </SelectedItemTemplate> </asp:DataList> <p> </td> <td valign=top > <div id="ClassPanel" style="margin-top:15;margin-left:10" visible="false" runat="server"> <b><font size=4 color="000666"><span style="text-indent:8" id="spnClassName" EnableViewState="false" runat="server"/></font></b> </div> <div id="NameSpacePanel" runat="server"> <table class="main" width=100%> <tr> <td class="main_header"> <span runat=server id="CHeader" visible="false" style="text-indent:8"> <b><font size=4 color=#000666>Classes in <%= SelectedNameSpace %> </b> </font></span> </td> </tr> <tr> <td align="left"> <asp:DataList EnableViewState="false" runat=server id="Classes" RepeatColumns="3" Gridlines=None borderstyle=none borderwidth=0 > <ItemTemplate> <asp:HyperLink runat=server text=<%# CType(Container.DataItem, SortTable)("GetType") %> NavigateUrl=<%# GetUrl(Container.DataItem) %> /> </ItemTemplate> </asp:DataList> </td> </tr> </table> <table class="main" width=100% > <tr> <td class="main_header" > <span runat=server id="IHeader" visible="false" style="text-indent:8"> <b><font size=4 color=#000666>Interfaces in <%= SelectedNameSpace %> </font> </b> </span> </td> </tr> <tr> <td align="left"> <asp:DataList EnableViewState="false" runat=server id="Interfaces" RepeatColumns="4" Gridlines=None borderstyle=none borderwidth=0 > <ItemTemplate> <asp:HyperLink runat=server text=<%# CType(Container.DataItem, SortTable)("GetType") %> NavigateUrl=<%# GetUrl(Container.DataItem) %>/> </ItemTemplate> </asp:DataList> </td> </tr> </table> </div> <table class="main" width=100% cellpadding=0 cellspacing=0 > <tr>

<td class="main_header" valign="top" > <asp:DataList EnableViewState="false" id="Constructors" runat="server" Gridlines=None borderstyle="none" borderwidth=0 width="100%"> <HeaderTemplate> <table cellspacing=0 width="100%"> <tr><td class="class_header"><b><font size=2> Constructores </font></b></td></tr> <tr bgcolor="eeeeee"> <td width="75" > <b><u> Visibilidad </u> </td> <td width="100"> <b><u> Constructor </u> </td> <td> <b><u> Parmetros </u> </td> </tr> </HeaderTemplate> <ItemTemplate> <tr bgcolor="eeeeee"> <td width="75"> <span runat=server InnerHtml=<%# CType(Container.DataItem, SortTable)("Access") %> /> </td> <td width="100"> <span runat=server InnerHtml =<%# CType(Container.DataItem, SortTable)("Name") %> /> </td> <td width="1000"> <asp:DataList EnableViewState="false" runat=server RepeatDirection="Horizontal" RepeatLayout=Flow showfooter=true datasource=<%# CType(Container.DataItem, SortTable)("Params") %> > <HeaderTemplate> ( </HeaderTemplate> <ItemTemplate> <asp:HyperLink text=<%# CType(Container.DataItem, SortTable)("ParamType") %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server /> <span innerhtml=<%# CType(Container.DataItem, SortTable)("ParamName") %> runat=server /> </ItemTemplate> <SeparatorTemplate>, </SeparatorTemplate> <FooterTemplate> ) </FooterTemplate> </asp:DataList> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="Fields" runat="server" Gridlines=None BorderStyle="none" width="100%" BorderWidth=0> <HeaderTemplate> <table cellspacing=0 width="100%"> <tr><td class="class_header"><b><font size=2> Campos </font></b></td></tr> <tr bgcolor="eeeeee"> <td width="120" ><b><u> Visibilidad </td> <td width="100"><b><u> Tipo </td> <td ><b><u> Nombre </td> </tr> </HeaderTemplate>

<ItemTemplate> <tr bgcolor="eeeeee"> <td width="120"> <nobr><span InnerHTML=<%# CType(Container.DataItem, SortTable)("Access") %> runat=server /></nobr> </td> <td width="100"> <asp:HyperLink text=<%# CType(Container.DataItem, SortTable)("Type") %> NavigateUrl=< %# GetUrl(Container.DataItem) %> runat=server/> </td> <td> <span InnerHTML=<%# CType(Container.DataItem, SortTable)("Name") %> runat=server /> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="Events" runat="server" Gridlines=None BorderStyle="none" width="100%" BorderWidth=0> <HeaderTemplate> <table cellspacing=0 width="100%"> <tr><td class="class_header"><b><font size=2> Eventos </font></b></td></tr> <tr bgcolor="eeeeee"> <td width="120" ><b><u> Multidifusin </td> <td width="100"><b><u> Tipo </td> <td ><b><u> Nombre </td> </tr> </HeaderTemplate> <ItemTemplate> <tr bgcolor="eeeeee"> <td width="120"> <nobr><span InnerHTML=<%# CType(Container.DataItem, SortTable)("Access")%> runat=server /></nobr> </td> <td width="100"> <asp:HyperLink text=<%# CType(Container.DataItem, SortTable)("Type") %> NavigateUrl=< %# GetUrl(Container.DataItem) %> runat=server/> </td> <td> <span InnerHTML=<%# CType(Container.DataItem, SortTable)("Name") %> runat=server /> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="Properties" runat="server" Gridlines=None BorderStyle="none" BorderWidth=0 width="100%">

<HeaderTemplate> <table cellspacing=0 width="100%" > <tr><td class="class_header"><b><font size=2> Propiedades </font></b></td></tr> <tr bgcolor="eeeeee"> <td width="75"><b><u>Visibilidad</td> <td width="100"><b><u>Tipo</td> <td width="150"><b><u>Nombre</td> <td><b><u>Accesibilidad</td> </tr> </HeaderTemplate> <ItemTemplate> <tr bgcolor="eeeeee"> <td width="75"><span InnerHTML=<%# CType(Container.DataItem, SortTable)("Visibility") %> runat=server /> </td> <td width="100"> <asp:HyperLink runat=server runat="server" text=<%# CType(Container.DataItem, SortTable)("Type") %> NavigateUrl=<%# GetUrl(Container.DataItem) %>/> </td> <td width="150"><span InnerHTML=<%# CType(Container.DataItem, SortTable)("Name")%> runat=server/> <asp:DataList EnableViewState="false" runat=server RepeatLayout="Flow" ShowFooter=true RepeatDirection="Horizontal" datasource=<%# CType(Container.DataItem, SortTable) ("Params") %>> <ItemTemplate> ( <asp:HyperLink runat=server text=<%# CType(Container.DataItem, SortTable) ("ParamType")%> NavigateUrl=<%# GetUrl(Container.DataItem) %> /> <span InnerHtml=<%# CType(Container.DataItem, SortTable)("ParamName") %> runat=server /> ) </ItemTemplate> </asp:DataList> </td> <td><span InnerHTML=<%# CType(Container.DataItem, SortTable)("Access")%> runat=server/></td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="Methods" runat="server" Gridlines=None borderstyle="none" borderwidth="0" width="100%"> <HeaderTemplate> <table cellspacing=0 > <tr><td class="class_header"><b><font size=2> Mtodos </font></b></td></tr> <tr bgcolor="eeeeee"> <td width="75" ><b><u>Visibilidad</td> <td width="170"><b><u>Tipo devuelto </td> <td width="100"><b><u>Nombre</td> <td width="600"><b><u>Parmetros</td> </tr> </HeaderTemplate> <ItemTemplate> <tr bgcolor="eeeeee"> <td width="75"><nobr><span runat=server InnerHtml=<%# CType(Container.DataItem, SortTable)("Access")%> /></nobr></td> <td width="100">

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# CType(Container.DataItem, SortTable)("Type")%>/> </td> <td width="100"><span runat=server InnerHtml=<%# CType(Container.DataItem, SortTable) ("Name")%>/></td> <td width="900"> <asp:DataList EnableViewState="false" runat=server datasource=<%# CType(Container.DataItem, SortTable)("Params") %> RepeatLayout=Flow RepeatDirection="Horizontal" showfooter=true > <HeaderTemplate> ( </HeaderTemplate> <ItemTemplate> <asp:HyperLink text=<%# CType(Container.DataItem, SortTable) ("ParamType").ToString() %> NavigateUrl=<%# GetUrl(Container.DataItem) %> runat=server /> <span InnerHtml=<%# CType(Container.DataItem, SortTable)("ParamName") %> runat=server /> </ItemTemplate> <SeparatorTemplate> ,</SeparatorTemplate> <FooterTemplate> ) </FooterTemplate> </asp:DataList> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="SuperClasses" style="margin-left:10" runat="server" RepeatLayout="Flow" RepeatDirection="horizontal" width="100%"> <HeaderTemplate> <font size=2><b> Jerarqua </b></font> <br> </HeaderTemplate> <ItemTemplate> <asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# CType(Container.DataItem, SortTable)("FullName")%> /> </ItemTemplate> <SeparatorTemplate> <font face="Verdana" style="font-size:8pt"><nobr>---></nobr> </SeparatorTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="Interface1" runat=server style="margin-left:10" RepeatDirection="horizontal" RepeatLayout="Flow" width="100%"> <HeaderTemplate> <font size=2><b> Implementaciones </b></font> <br> </HeaderTemplate> <ItemTemplate>

<asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# CType(Container.DataItem, SortTable)("FullName")%> /> </ItemTemplate> <SeparatorTemplate> <font face="Verdana" style="font-size:8pt">, </SeparatorTemplate> </asp:DataList> <p> <asp:DataList EnableViewState="false" id="SubClasses" style="margin-left:10" runat=server RepeatLayout="Flow" RepeatDirection="horizontal" width="100%"> <HeaderTemplate> <font size=2> <b>Subclases implementadas por </b></font> <br> </HeaderTemplate> <ItemTemplate> <asp:HyperLink runat=server NavigateUrl=<%# GetUrl(Container.DataItem) %> text=<%# CType(Container.DataItem, SortTable)("FullName")%> /> </ItemTemplate> <SeparatorTemplate> <font face="Verdana" style="font-size:8pt">, </SeparatorTemplate> </asp:DataList> <p> </td> </tr> </table> </td> </tr> </table> </form> </body> </html>
El examinador de clases tambin utiliza el sistema de configuracin de ASP.NET para determinar qu mdulos se deben cargar y reflejar. Se asigna una seccin de configuracin al controlador HashtableSectionHandler, que mantiene pares clave/valor para el archivo y el nombre de ensamblado. Se pueden agregar ensamblados a esta lista si se incluye una lnea en la seccin de configuracin de la aplicacin del examinador de clases, como se indica a continuacin:

<configuration> <configSections> <sectionGroup name="system.web"> <section name="ClassBrowser" type="System.Configuration.NameValueSectionHandler, System,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"/> </sectionGroup> </configSections> <system.web> <ClassBrowser> <add key="ASP.NET Class Library" value="System.Web, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <add key=".NET Framework class Library" value="mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </ClassBrowser> </system.web> </configuration>

You might also like