Professional Documents
Culture Documents
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.
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
' 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(" !!!")
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
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(...), ...
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
Mdulo estndar
Imports System Public Module ConsoleVB Public Sub Main() Console.WriteLine("Hello World") End Sub
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.
<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.
<%@ 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.
<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.
<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.
<%@ 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.
<%@ 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.
<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>
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.
<%@ 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>
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.
<html> <body> <h3><font face="Verdana">Declarar controles de servidor</font></h3> Este ejemplo muestra cmo declarar el control de servidor <asp:label> 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>
<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 <asp:label> 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>
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 <asp:textbox> del evento "Click" de <asp:button> y utilizar el contenido para modificar el texto de <asp:label>. <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>
<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 <asp:button>. <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>
<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>
' 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 <asp:button> Click, pasando <asp:textbox> 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>
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.
.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'> " 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>
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
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"
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> </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>
<%@ 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> </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.
<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>
<%@ 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>
( 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>
<%@ 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>
<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>
<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>
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:
<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 (!@#$%^&*+;:) </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> </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 /> <font face=Arial size=2>Cdigo postal:</font> <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> </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.
<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.
<body style="font: 10pt verdana"> <h3>Control de usuario simple</h3> <Acme:Message runat="server"/> </body> </html>
<%@ 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.
<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>
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>
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:
<%@ 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.
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:
<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>
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>
<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.
<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>
<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>
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.
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.
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.
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.
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.
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.
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.
<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.
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.
<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.
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>
<%@ 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> * </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> * </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> * </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> * </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>
<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.
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> * </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> * </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> * </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>
<%@ 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>
<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>
<%@ 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>
<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>
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> Seleccionar un ao: <select id="SelectYear" runat="server"> <option>1996</option> <option>1997</option> <option>1998</option> </select> <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" />
<%@ 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>
<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.
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.
<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.
<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.
<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>
<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>
<%@ 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>
<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>
<%@ 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.
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.
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.
<%@ 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.
<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.
<%@ 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.
<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"/> Id. de cliente preferido: <ASP:TextBox id="CustomerId" Width="35" runat="server"/> <input type="Submit" OnServerClick="Submit_Click" Value="Obtener productos" runat="server"/> <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.
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>
<%@ 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>
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.
<%@ 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>
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.
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/> |
<%@ 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>
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.
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.
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>
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>
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
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/>
<%@ 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"/>
<%@ 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.
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
<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
<%@ WebService Class="MyWebApplication.MyWebService" %> MyWebApplication.MyWebService define la clase WebService y est incluido en el subdirectorio \bin de la aplicacin ASP.NET.
de salida para el proxy. Tambin es posible compilar con un archivo WSDL guardado anteriormente en lugar del identificador URI al propio servicio:
<%@ 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">
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).
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 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.
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
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>
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>
<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
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>(.*?)<'/> <match name='H1' pattern='H1>(.*?)<'/> </text> </output> </operation> </binding> <service name="TestIt"> <port name="TestItHttpGet" binding="s0:TestItHttpGet"> <http:address location="http://localhost" /> </port> </service>
</definitions>
<%@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).
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:
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.
<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:
<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.
<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.
<%@ 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.
<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.
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
<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):
<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.
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.
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.
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
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.
<%@ 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" %> <%@ 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.
<%@ 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.
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:
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.
<%@ 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:
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.
Cache("mykey") = myValue
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.
<%@ 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.
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.
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.
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
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.
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
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>
<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>
<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:
<httpHandlers>
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.
<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
<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:
<%@ 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
C:\inetpub\wwwroot Web.cfg Default.aspx \bin <= Application assembly cache directory MyPages.dll
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.
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.
<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.
memoryLimit
shutdownTimeout
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
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
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.
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:
<%@ 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.
<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"/>
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>
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:
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.
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:
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.
<%@ 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>
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:
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.
' 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>
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
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:
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>
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.
<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"
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.
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.
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:
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 %>.
<%@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.
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.
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: 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.
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.
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:
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.
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:
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.
<%@ 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%"> </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=" - " runat="server"/> <a id="anchorDelete" href="" runat="server">Eliminar pgina</a> <asp:Label id="spanDelete" Text=" - " 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>
<%@ 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: </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>
<%@ 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>