Compartir a través de


Usar el control UpdatePanel con un servicio web

Actualización: noviembre 2007

El control UpdatePanel simplifica la representación parcial de las páginas web ASP.NET porque la funcionalidad de AJAX de ASP.NET administra automáticamente las solicitudes y actualizaciones de las devoluciones de datos asincrónicas. La funcionalidad de AJAX también permite llamar a los servicios web ASP.NET utilizando ECMAScript (JavaScript) en el explorador. Una de las ventajas de llamar a un servicio web utilizando un script de cliente es que la espera de la respuesta a una solicitud de servicio web no bloquea el explorador. Los usuarios pueden continuar trabajando sin esperar a que el servicio web termine de procesar la solicitud.

Este tutorial muestra cómo utilizar un servicio web utilizando un control UpdatePanel. Una función JavaScript llama al servicio web para recuperar datos y, a continuación, rellena los elementos DOM dentro de un control UpdatePanel con datos devueltos por el servicio web. El código de servidor conserva los datos del servicio web recuperados entre las devoluciones de datos asincrónicas.

En este tema se supone que está familiarizado con el control UpdatePanel y con los servicios web. Si no es así, revise los temas siguientes:

Requisitos previos

Para implementar los procedimientos en su propio entorno de desarrollo, necesitará:

  • Microsoft Visual Studio 2005 o Visual Web Developer Express.

  • Un sitio web ASP.NET habilitado para AJAX.

  • Acceso a la base de datos Northwind y una cadena de conexión denominada NorthwindConnectionString definida en el archivo Web.config. Para obtener información sobre cómo crear una cadena de conexión, vea Cómo: Leer las cadenas de conexión en un archivo Web.config.

Crear un servicio web

Para comenzar, creará un servicio web al que pueda llamar.

Para crear un servicio web para devolver cantidades de productos

  1. En un sitio web ASP.NET habilitado para AJAX, cree un nuevo archivo de servicio web denominado ProductQueryService.asmx.

    Para obtener más información acerca de cómo crear un servicio web, vea Llamar a servicios web desde script de cliente.

  2. En el código del servicio web, importe los espacios de nombres N:System.Data, N:System.Data.SqlClient, System.Configuration y N:System.Web.Script.Services.

    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Configuration
    Imports System.Web.Script.Services
    
    using System.Web.Script.Services;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    

    Los tipos de estos espacios de nombres se utilizarán en el método del servicio web que creará.

  3. Coloque la clase ProductQueryService dentro de un espacio de nombres denominado Samples.

  4. Agregue el atributo ScriptServiceAttribute a la clase.

    Este atributo permite invocar el servicio web desde un script de cliente.

  5. Reemplace el método HelloWorld predeterminado por el siguiente método GetProductQuantity:

    <WebMethod()> _
    Public Function GetProductQuantity(ByVal productID As String) As String
        Dim cn As SqlConnection = _
            New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString)
        Dim cmd As SqlCommand = _
            New SqlCommand("SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn)
        cmd.Parameters.AddWithValue("productID", productID)
        Dim unitsInStock As String = ""
        cn.Open()
        Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
            Do While dr.Read()
                unitsInStock = dr(0).ToString()
            Loop
    
        End Using
        System.Threading.Thread.Sleep(3000)
        Return unitsInStock
    End Function
    
    [WebMethod]
    public string GetProductQuantity(string productID)
    {
        SqlConnection cn =
            new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
        SqlCommand cmd = new SqlCommand(
            "SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn);
        cmd.Parameters.Add("productID", productID);
        String unitsInStock = "";
        cn.Open();
        using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (dr.Read())
                unitsInStock = dr[0].ToString();
        }
        System.Threading.Thread.Sleep(3000);
        return unitsInStock;
    }
    

    El código realiza las tareas siguientes:

    • Crea un nuevo objeto SqlConnection que utiliza una cadena de conexión denominada NorthwindConnectionString.

    • Crea un nuevo objeto SqlCommand que contiene un comando SQL para recuperar el número de unidades en almacén para un identificador de producto especificado.

    • Establece el valor devuelto en una cadena que se utiliza como la respuesta que se envía al explorador.

      Nota:

      En este tutorial, el método web introduce un retraso artificial. En la práctica, no debería incluir un retraso. Si se produce un retraso, será como resultado del tráfico del servidor o debido a que el código del servicio web tarda mucho en tiempo en procesarse, como ocurre con las consultas de base de datos de ejecución prolongada.

  6. Guarde los cambios y presione CTRL+F5 para ver la página en un explorador.

  7. Haga clic en el vínculo GetProductQuantity para invocar el método web.

  8. Escriba 6 en el cuadro productID y, a continuación, haga clic en Invocar.

    La cantidad del producto se devuelve como XML en el explorador. Esto muestra que el servicio web funciona como está previsto.

    <%@ WebService Language="VB" Class="Samples.ProductQueryService" %>
    
    Imports System
    Imports System.Web
    Imports System.Web.Services
    Imports System.Web.Services.Protocols
    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Configuration
    Imports System.Web.Script.Services
    Namespace Samples
    
        <ScriptService()> _
        <WebService(Namespace:="http://tempuri.org/")> _
        <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
        Public Class ProductQueryService
            Inherits System.Web.Services.WebService
    
            <WebMethod()> _
            Public Function GetProductQuantity(ByVal productID As String) As String
                Dim cn As SqlConnection = _
                    New SqlConnection(ConfigurationManager.ConnectionStrings("NorthwindConnectionString").ConnectionString)
                Dim cmd As SqlCommand = _
                    New SqlCommand("SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn)
                cmd.Parameters.AddWithValue("productID", productID)
                Dim unitsInStock As String = ""
                cn.Open()
                Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
                    Do While dr.Read()
                        unitsInStock = dr(0).ToString()
                    Loop
    
                End Using
                System.Threading.Thread.Sleep(3000)
                Return unitsInStock
            End Function
        End Class
    End Namespace
    
    <%@ WebService Language="C#" Class="Samples.ProductQueryService" %>
    
    using System;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.Web.Script.Services;
    using System.Data;
    using System.Data.SqlClient;
    using System.Configuration;
    namespace Samples
    {
        [ScriptService]
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class ProductQueryService : System.Web.Services.WebService
        {
    
            [WebMethod]
            public string GetProductQuantity(string productID)
            {
                SqlConnection cn =
                    new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
                SqlCommand cmd = new SqlCommand(
                    "SELECT [UnitsInStock] FROM [Alphabetical list of products] WHERE ([ProductID] = @ProductID)", cn);
                cmd.Parameters.Add("productID", productID);
                String unitsInStock = "";
                cn.Open();
                using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    while (dr.Read())
                        unitsInStock = dr[0].ToString();
                }
                System.Threading.Thread.Sleep(3000);
                return unitsInStock;
            }
        }
    }
    

Crear código JavaScript para llamar al servicio web

En este procedimiento, creará un archivo JavaScript que llama al servicio web creado en el procedimiento anterior.

Para crear un archivo JavaScript para utilizar el servicio web

  1. Cree un nuevo archivo JScript denominado ProductQueryScript.js.

  2. Agregue el siguiente script al archivo:

    function GetQuantity(productID, elemToUpdate, productLabelElem, buttonElem) {
       var userContext = [productID, elemToUpdate, productLabelElem, buttonElem];
       Samples.ProductQueryService.GetProductQuantity(productID, OnSucceeded, null, userContext, null);
       $get(buttonElem).value = "Retrieving value...";
    }
    function OnSucceeded(result, userContext) {
       var productID = userContext[0];
       var elemToUpdate = userContext[1];
       var productLabelElem = userContext[2];
       var buttonElem = userContext[3];
       $get(buttonElem).value = "Get Quantity from Web Service";
       if ($get(elemToUpdate) !== null && $get(productLabelElem).innerHTML == productID) {
         $get(elemToUpdate).value = result;
       }
    }
    
    function GetQuantity(productID, elemToUpdate, productLabelElem, buttonElem) {
       var userContext = [productID, elemToUpdate, productLabelElem, buttonElem];
       Samples.ProductQueryService.GetProductQuantity(productID, OnSucceeded, null, userContext, null);
       $get(buttonElem).value = "Retrieving value...";
    }
    function OnSucceeded(result, userContext) {
       var productID = userContext[0];
       var elemToUpdate = userContext[1];
       var productLabelElem = userContext[2];
       var buttonElem = userContext[3];
       $get(buttonElem).value = "Get Quantity from Web Service";
       if ($get(elemToUpdate) !== null && $get(productLabelElem).innerHTML == productID) {
         $get(elemToUpdate).value = result;
       }
    }
    

    El script realiza las siguientes tareas:

    • Crea una función denominada GetQuantity que invoca el método de servicio web GetProductQuantity.

    • Crea una función denominada OnSucceeded que se invoca cuando la llamada al servicio web se devuelve con un resultado.

Crear una página web para mostrar datos

A continuación, creará una página web que contiene un control UpdatePanel. Los controles dentro del control UpdatePanel muestran la información del producto de la base de datos Northwind.

Para crear una página web para mostrar productos

  1. Cree una nueva página web y cambie a la vista Diseño.

  2. En la ficha Extensiones AJAX del cuadro de herramientas, haga doble clic en el control ScriptManager para agregarlo a la página.

  3. En el cuadro de herramientas, haga doble clic en el control UpdatePanel para agregar un control UpdatePanel a la página web.

  4. Haga clic dentro del control UpdatePanel y, a continuación, en la ficha Datos del cuadro de herramientas, haga doble clic en el control DataList.

  5. En el panel Tareas de DataList, en la lista Elegir origen de datos, seleccione <Nuevo origen de datos...>.

    Nota:

    Si no se muestra el panel Tareas de DataList, haga clic con el botón secundario del mouse en el control DataList y seleccione Mostrar etiqueta inteligente.

    Aparece el Asistente para configuración de orígenes de datos.

  6. Seleccione Base de datos, acepte el nombre predeterminado SqlDataSource1 y, a continuación, haga clic en Aceptar.

  7. En la lista ¿Qué conexión de datos debería utilizar la aplicación para conectarse a la base de datos?, seleccione NorthwindConnectionString y, a continuación, haga clic en Siguiente.

  8. En ¿Cómo desea recuperar los datos de la base de datos?, seleccione Especificar columnas de una tabla o vista, seleccione Products en la lista y, en la lista Columnas, seleccione ProductID y ProductName.

  9. Haga clic en el botón WHERE.

    Aparecerá el cuadro de diálogo Agregar cláusula WHERE.

  10. En la lista Columnas, seleccione CategoryID y, en la lista Origen, seleccione Ninguno.

  11. En la sección Propiedades del parámetro del cuadro de diálogo, en el cuadro de texto Valor, escriba 1.

  12. Haga clic en Agregar para agregar la cláusula WHERE a la instrucción SQL.

  13. Haga clic en Aceptar para cerrar el cuadro de diálogo Agregar cláusula WHERE.

  14. Haga clic en Siguiente y, a continuación, haga clic en Finalizar para cerrar el asistente.

  15. Cambie a la vista Código fuente y confirme que el control SqlDataSource se parece al ejemplo siguiente:

    <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
        <SelectParameters>
            <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
        </SelectParameters>
    </asp:SqlDataSource>
    
    <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
        <SelectParameters>
            <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
        </SelectParameters>
    </asp:SqlDataSource>
    
  16. Cambie a la vista Diseño.

  17. Seleccione el control DataList y, en el panel Tareas de DataList, haga clic en Editar plantillas.

  18. Agregue dos controles Button al control UpdatePanel fuera del control DataList.

  19. Establezca la propiedad ID del primer botón en Category1Button y su propiedad Text en Categoría 1. Establezca la propiedad ID del segundo botón en Category2Button y su propiedad Text en Categoría 2.

  20. Seleccione el control UpdatePanel y, en la ventana Propiedades, establezca la propiedad UpdateMode en Conditional y establezca la propiedad ChildrenAsTriggers en false.

  21. En el cuadro Triggers, haga clic en el botón de puntos suspensivos (...) y, en el cuadro de diálogo Editor de la colección UpdatePanelTrigger, agregue cada botón de categoría como un desencadenador de devolución de datos asincrónica.

  22. Establezca el controlador de eventos Click del primer botón en Category1Button_Click y el controlador de eventos Click del segundo botón en Category2Button_Click.

  23. Cambie a la vista Código fuente y cree los siguientes controladores de eventos para los dos botones:

    Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        SqlDataSource1.SelectParameters(0).DefaultValue = "1"
    End Sub
    
    Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        SqlDataSource1.SelectParameters(0).DefaultValue = "2"
    End Sub
    
    protected void Category1Button_Click(object sender, EventArgs e)
    {
        SqlDataSource1.SelectParameters[0].DefaultValue = "1";
    }
    
    protected void Category2Button_Click(object sender, EventArgs e)
    {
        SqlDataSource1.SelectParameters[0].DefaultValue = "2";
    }
    

    El código del controlador de eventos establece el parámetro CategoryID de la colección SelectParameters en el control SqlDataSource, según qué botón se haya presionado. Esto permite a los usuarios alternar entre dos categorías.

  24. Guarde los cambios y presione CTRL+F5 para ver la página en un explorador.

  25. Haga clic en Categoría 2 y compruebe que la página muestra la nueva información pero no se actualiza la página entera.

    Nota:

    No cierre la página.

    <%@ Page Language="VB" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script >
    
        Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
            SqlDataSource1.SelectParameters(0).DefaultValue = "1"
        End Sub
    
        Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
            SqlDataSource1.SelectParameters(0).DefaultValue = "2"
        End Sub
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head >
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1"  ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button"  Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button"  OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1"  DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="231px">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel"  Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel"  Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                            SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
                            <SelectParameters>
                                <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
                            </SelectParameters>
                        </asp:SqlDataSource>
                    </ContentTemplate>
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="Category1Button" />
                        <asp:AsyncPostBackTrigger ControlID="Category2Button" />
                    </Triggers>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    
    <%@ Page Language="C#" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script >
    
        protected void Category1Button_Click(object sender, EventArgs e)
        {
            SqlDataSource1.SelectParameters[0].DefaultValue = "1";
        }
    
        protected void Category2Button_Click(object sender, EventArgs e)
        {
            SqlDataSource1.SelectParameters[0].DefaultValue = "2";
        }
    
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head >
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1"  ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button"  Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button"  OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1"  DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="231px">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel"  Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel"  Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                            SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
                            <SelectParameters>
                                <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
                            </SelectParameters>
                        </asp:SqlDataSource>
                    </ContentTemplate>
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="Category1Button" />
                        <asp:AsyncPostBackTrigger ControlID="Category2Button" />
                    </Triggers>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    

Llamar a un servicio web para r recuperar los datos

Ahora llamará al servicio web utilizando el archivo JavaScript creado anteriormente. El código JavaScript utiliza los datos devueltos para rellenar los elementos DOM dentro del control UpdatePanel. El código de servidor de la página conserva los datos que rellenó el servicio web y agrega los datos al estado de vista de la página. De esta manera se conservan los datos en las devoluciones de datos asincrónicas posteriores.

Para usar un servicio web para devolver cantidades de productos

  1. En la página, cambie a la vista Diseño.

  2. Seleccione el control DataList y, en el panel Tareas de DataList, seleccione Editar plantillas.

  3. Agregue TextBox y un control Button a la plantilla de elemento.

    Agregue los nuevos controles debajo del texto y etiquetas existentes en la plantilla.

  4. Seleccione el botón y, en la ventana Propiedades, establezca su propiedad Text en Obtener cantidad del servicio web.

    La plantilla de elemento del control DataList debe parecerse a la ilustración siguiente.

  5. Seleccione el control DataList y, a continuación, en la ficha Eventos de la ventana Propiedades, haga doble clic en el evento ItemDataBound.

  6. Agregue el código siguiente:

    Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As DataListItemEventArgs)
        Dim label As Label = CType(e.Item.FindControl("ProductIDLabel"), Label)
        Dim button As Button = CType(e.Item.FindControl("Button1"), Button)
        Dim textbox As TextBox = CType(e.Item.FindControl("TextBox1"), TextBox)
        button.OnClientClick = "GetQuantity(" & label.Text & ",'" & textbox.ClientID & "','" & _
            label.ClientID + "','" & button.ClientID & "')"
        Dim ProductInfo As SortedList = Me.ProductInfo
        If (ProductInfo.ContainsKey(label.Text)) Then
            textbox.Text = ProductInfo(label.Text).ToString()
        End If
    End Sub
    
    protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
    {
        Label label = (Label)e.Item.FindControl("ProductIDLabel");
        Button button = (Button)e.Item.FindControl("Button1");
        TextBox textbox = (TextBox)e.Item.FindControl("TextBox1");
        button.OnClientClick = "GetQuantity(" + label.Text + ",'" + 
            textbox.ClientID + "','" + label.ClientID + "','" + button.ClientID + "')";
        SortedList ProductInfo = this.ProductInfo;
        if (ProductInfo.ContainsKey(label.Text))
        {
            textbox.Text = ProductInfo[label.Text].ToString();
        }        
    }
    

    El código establece las propiedades de los controles en cada objeto DataListItem, de la siguiente manera:

    • La propiedad OnClientClick del botón llama a una función JavaScript que, a su vez, llama al servicio web.

    • El valor del cuadro de texto se establece si una propiedad de seguimiento denominada ProductInfo contiene una clave para el id. de producto. La propiedad ProductInfo se define en el paso siguiente de este procedimiento.

  7. Agregue una propiedad denominada ProductInfo a la página.

    Protected Property ProductInfo() As SortedList
        Get
            If ViewState("ProductInfo") IsNot Nothing Then
                Return CType(ViewState("ProductInfo"), SortedList)
            Else
                Return New SortedList()
            End If
        End Get
        Set(ByVal value As SortedList)
            ViewState("ProductInfo") = value
        End Set
    End Property
    
    protected SortedList ProductInfo
    {
        get { return (SortedList)(ViewState["ProductInfo"] ?? new SortedList()); }
        set { ViewState["ProductInfo"] = value; }
    }
    

    Esta propiedad es un objeto SortedList que realiza el seguimiento de los datos agregados a la página desde el servicio web. La primera vez que se representa la página, la lista está vacía. Durante las devoluciones de datos asincrónicas posteriores, se podrían agregar elementos a la lista.

  8. Agregue el siguientes controlador de eventos Page_Load:

    Protected Sub Page_Load()
        If (ScriptManager1.IsInAsyncPostBack) Then
            Dim ProductInfo As SortedList = Me.ProductInfo
            For Each d As DataListItem In DataList1.Items
                Dim label As Label = CType(d.FindControl("ProductIDLabel"), Label)
                Dim textbox As TextBox = CType(d.FindControl("TextBox1"), TextBox)
                If (textbox.Text.Length > 0) Then
                    ProductInfo(label.Text) = textbox.Text
                End If
            Next
            Me.ProductInfo = ProductInfo
        End If
    End Sub
    
    protected void Page_Load(object sender, EventArgs e)
    {
        if (ScriptManager1.IsInAsyncPostBack)
        {
            SortedList ProductInfo = this.ProductInfo;
            foreach (DataListItem d in DataList1.Items)
            {
                Label label = (Label)d.FindControl("ProductIDLabel");
                TextBox textbox = (TextBox)d.FindControl("TextBox1");
                if (textbox.Text.Length > 0)
                {
                    ProductInfo[label.Text] = textbox.Text;
                }
            }
            this.ProductInfo = ProductInfo;
        }
    }
    

    El código comprueba si la solicitud es una devolución de datos asincrónica. Si lo es, todos los elementos de datos agregados por el servicio web se agregan a la propiedad ProductInfo. Esto permite realizar el seguimiento de los mismos en el estado de vista y mostrarlos en el UpdatePanel durante las posteriores actualizaciones parciales de la página. Si no se realiza el seguimiento de los elementos de datos en el estado de vista, no se conservan en posteriores devoluciones de datos asincrónicas.

  9. Cambie a la vista Diseño.

  10. Seleccione el control ScriptManager.

  11. En la ventana Propiedades, seleccione la propiedad Servicios y haga clic en el botón de puntos suspensivos (…) para mostrar el cuadro de diálogo Editor de la colección ServiceReference.

  12. Haga clic en Agregar para agregar una referencia de servicio.

  13. Establezca la propiedad Path de la referencia de servicio en ProductQueryService.asmx, que es el servicio web creado previamente.

    Al agregar una referencia de servicio, el control ScriptManager genera clases de proxy de cliente para que se pueda llamar al servicio web mediante JavaScript.

  14. Haga clic en Aceptar para cerrar el cuadro de diálogo Editor de la colección ServiceReference.

  15. Seleccione el control ScriptManager y, en la ventana Propiedades, seleccione la propiedad Scripts y haga clic en el botón de puntos suspensivos (…) para mostrar el cuadro de diálogo Editor de la colección ScriptReference.

  16. Haga clic en Agregar para agregar una referencia de script.

  17. Establezca la propiedad Path de la referencia de script en ProductQueryScript.js, el archivo JavaScript creado previamente.

    Al agregar una referencia de script, el control ScriptManager inserta el script después de que Microsoft AJAX Library se haya cargado.

  18. Haga clic en Aceptar para cerrar el cuadro de diálogo Editor de la colección ScriptReference.

  19. Guarde los cambios y presione CTRL+F5 para ver la página en un explorador.

    La página muestra los productos de la base de datos Northwind cuyo identificador de categoría es 1. Los cuadros de texto situados al lado de cada producto están vacíos porque no se ha realizado ninguna llamada al servicio web.

    <%@ Page Language="VB" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script >
    
        Protected Property ProductInfo() As SortedList
            Get
                If ViewState("ProductInfo") IsNot Nothing Then
                    Return CType(ViewState("ProductInfo"), SortedList)
                Else
                    Return New SortedList()
                End If
            End Get
            Set(ByVal value As SortedList)
                ViewState("ProductInfo") = value
            End Set
        End Property
    
        Protected Sub Category1Button_Click(ByVal sender As Object, ByVal e As EventArgs)
            SqlDataSource1.SelectParameters(0).DefaultValue = "1"        
        End Sub
    
        Protected Sub Category2Button_Click(ByVal sender As Object, ByVal e As EventArgs)
            SqlDataSource1.SelectParameters(0).DefaultValue = "2"
        End Sub
    
        Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As DataListItemEventArgs)
            Dim label As Label = CType(e.Item.FindControl("ProductIDLabel"), Label)
            Dim button As Button = CType(e.Item.FindControl("Button1"), Button)
            Dim textbox As TextBox = CType(e.Item.FindControl("TextBox1"), TextBox)
            button.OnClientClick = "GetQuantity(" & label.Text & ",'" & textbox.ClientID & "','" & _
                label.ClientID + "','" & button.ClientID & "')"
            Dim ProductInfo As SortedList = Me.ProductInfo
            If (ProductInfo.ContainsKey(label.Text)) Then
                textbox.Text = ProductInfo(label.Text).ToString()
            End If
        End Sub
    
        Protected Sub Page_Load()
            If (ScriptManager1.IsInAsyncPostBack) Then
                Dim ProductInfo As SortedList = Me.ProductInfo
                For Each d As DataListItem In DataList1.Items
                    Dim label As Label = CType(d.FindControl("ProductIDLabel"), Label)
                    Dim textbox As TextBox = CType(d.FindControl("TextBox1"), TextBox)
                    If (textbox.Text.Length > 0) Then
                        ProductInfo(label.Text) = textbox.Text
                    End If
                Next
                Me.ProductInfo = ProductInfo
            End If
        End Sub
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head >
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                    <Services>
                        <asp:ServiceReference Path="ProductQueryService.asmx" />
                    </Services>
                    <Scripts>
                        <asp:ScriptReference Path="ProductQueryScript.js" />
                    </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1"  ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button"  Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button"  OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1"  DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="400px" OnItemDataBound="DataList1_ItemDataBound">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel"  Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel"  Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <asp:TextBox ID="TextBox1" ></asp:TextBox>
                                <asp:Button ID="Button1"  Text="Get Quantity from Web Service" /><br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                            SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
                            <SelectParameters>
                                <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
                            </SelectParameters>
                        </asp:SqlDataSource>
                    </ContentTemplate>
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="Category1Button" />
                        <asp:AsyncPostBackTrigger ControlID="Category2Button" />
                    </Triggers>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    
    <%@ Page Language="C#" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script >
    
        protected SortedList ProductInfo
        {
            get { return (SortedList)(ViewState["ProductInfo"] ?? new SortedList()); }
            set { ViewState["ProductInfo"] = value; }
        }
    
        protected void Category1Button_Click(object sender, EventArgs e)
        {
            SqlDataSource1.SelectParameters[0].DefaultValue = "1";
        }
    
        protected void Category2Button_Click(object sender, EventArgs e)
        {
            SqlDataSource1.SelectParameters[0].DefaultValue = "2";
        }
    
        protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
        {
            Label label = (Label)e.Item.FindControl("ProductIDLabel");
            Button button = (Button)e.Item.FindControl("Button1");
            TextBox textbox = (TextBox)e.Item.FindControl("TextBox1");
            button.OnClientClick = "GetQuantity(" + label.Text + ",'" + 
                textbox.ClientID + "','" + label.ClientID + "','" + button.ClientID + "')";
            SortedList ProductInfo = this.ProductInfo;
            if (ProductInfo.ContainsKey(label.Text))
            {
                textbox.Text = ProductInfo[label.Text].ToString();
            }        
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            if (ScriptManager1.IsInAsyncPostBack)
            {
                SortedList ProductInfo = this.ProductInfo;
                foreach (DataListItem d in DataList1.Items)
                {
                    Label label = (Label)d.FindControl("ProductIDLabel");
                    TextBox textbox = (TextBox)d.FindControl("TextBox1");
                    if (textbox.Text.Length > 0)
                    {
                        ProductInfo[label.Text] = textbox.Text;
                    }
                }
                this.ProductInfo = ProductInfo;
            }
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head >
        <title>Products Display</title>
    </head>
    <body>
        <form id="form1" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                    <Services>
                        <asp:ServiceReference Path="ProductQueryService.asmx" />
                    </Services>
                    <Scripts>
                        <asp:ScriptReference Path="ProductQueryScript.js" />
                    </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel ID="UpdatePanel1"  ChildrenAsTriggers="False" UpdateMode="Conditional">
                    <ContentTemplate>
                        <asp:Button ID="Category1Button"  Text="Category 1" OnClick="Category1Button_Click" />
                        <asp:Button ID="Category2Button"  OnClick="Category2Button_Click" Text="Category 2" />
                        <asp:DataList ID="DataList1"  DataKeyField="ProductID" DataSourceID="SqlDataSource1"
                            Width="400px" OnItemDataBound="DataList1_ItemDataBound">
                            <ItemTemplate>
                                ProductName:
                                <asp:Label ID="ProductNameLabel"  Text='<%# Eval("ProductName") %>'>
                                </asp:Label><br />
                                ProductID:
                                <asp:Label ID="ProductIDLabel"  Text='<%# Eval("ProductID") %>'></asp:Label><br />
                                <asp:TextBox ID="TextBox1" ></asp:TextBox>
                                <asp:Button ID="Button1"  Text="Get Quantity from Web Service" /><br />
                            </ItemTemplate>
                        </asp:DataList>
                        <asp:SqlDataSource ID="SqlDataSource1"  ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
                            SelectCommand="SELECT [ProductName], [ProductID] FROM [Alphabetical list of products] WHERE ([CategoryID] = @CategoryID)">
                            <SelectParameters>
                                <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
                            </SelectParameters>
                        </asp:SqlDataSource>
                    </ContentTemplate>
                    <Triggers>
                        <asp:AsyncPostBackTrigger ControlID="Category1Button" />
                        <asp:AsyncPostBackTrigger ControlID="Category2Button" />
                    </Triggers>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    

Comprobar que los datos se conservan durante las devoluciones de datos asincrónicas

Ahora puede ver cómo se conservan los datos del servicio web durante las devoluciones de datos asincrónicas.

Para comprobar que los datos del servicio web se conservan durante las devoluciones de datos asincrónicas

  1. Si la página no se está ejecutando aún, presione CTRL+F5 para ejecutarla.

  2. Haga clic en el botón Obtener cantidad del servicio web de cualquier producto de la lista y, a continuación, espere a que se muestre el valor en el cuadro de texto.

  3. Haga clic en el botón Categoría 2.

  4. Haga clic en el botón Categoría 1.

    Observe que el valor devuelto anteriormente por el servicio web todavía aparece, incluso después de las devoluciones de datos asincrónicas.

Revisión

En este tutorial se mostró un ejemplo de cómo utilizar un control UpdatePanel con un servicio web al que se llama desde código JavaScript en el explorador. El servicio web devuelve datos que se muestran dentro del control UpdatePanel.

El resultado de llamar al servicio web desde el script de cliente y de rellenar los elementos DOM con los datos devueltos es el mismo con o sin controles UpdatePanel. Cuando una página realiza una devolución de datos o cuando se produce una devolución de datos asincrónica, se pierden los datos que se mostraron previamente mediante el script de cliente. Para evitar este problema, puede utilizar código de servidor para conservar los datos, haciendo que forme parte del estado de vista. De esta manera, puede mantener los datos durante las devoluciones de datos posteriores. Si los datos del servicio web se muestran en elementos DOM fuera de los controles UpdatePanel y no desea conservarlos durante las devoluciones de datos asincrónicas, no es necesario que proporcione el código de servidor para mantenerlos.

Debido a que el botón que desencadenó la llamada al servicio web está dentro del control UpdatePanel, la propiedad ChildrenAsTriggers se establece en false. Los demás controles de devolución de datos dentro del panel se definen como desencadenadores del panel.

Vea también

Conceptos

Exponer servicios web a script de cliente

Llamar a servicios web desde script de cliente