Utilizzo del controllo UpdatePanel con un servizio Web
Aggiornamento: novembre 2007
Il controllo UpdatePanel semplifica il rendering a pagina parziale nelle pagine Web ASP.NET poiché la funzionalità AJAX di ASP.NET gestisce automaticamente le richieste di postback asincrone e gli aggiornamenti. La funzionalità AJAX consente inoltre di chiamare i servizi Web ASP.NET utilizzando ECMAScript (JavaScript) nel browser. Uno dei vantaggi offerti dalla chiamata di un servizio Web utilizzando uno script client deriva dal fatto che l'attesa della risposta da una richiesta del servizio Web non blocca il browser. Gli utenti possono continuare a lavorare senza attendere che il servizio Web completi l'elaborazione della richiesta.
In questa esercitazione viene illustrato come utilizzare un servizio Web mediante un controllo UpdatePanel. Una funzione JavaScript chiama il servizio Web per recuperare i dati e popolare gli elementi DOM all'interno di un controllo UpdatePanel con i dati restituiti dal servizio Web. Il codice server mantiene i dati recuperati dal servizio Web tra postback asincroni.
In questo argomento si presuppone la conoscenza del controllo UpdatePanel e dei servizi Web. In caso contrario, consultare i seguenti argomenti:
Prerequisiti
Per implementare le procedure nell'ambiente di sviluppo in uso è necessario:
Microsoft Visual Studio 2005 o Visual Web Developer Express Edition.
Sito Web ASP.NET con supporto AJAX.
Accesso al database Northwind e una stringa di connessione denominata NorthwindConnectionString definita nel file Web.config. Per ulteriori informazioni su come creare una stringa di connessione, vedere Procedura: leggere stringhe di connessione dal file Web.config.
Creazione di un servizio Web
Per iniziare verrà creato un servizio Web che sia possibile chiamare.
Per creare un servizio Web per restituire quantità di prodotto
In un sito Web ASP.NET con supporto AJAX creare un nuovo file del servizio Web denominato ProductQueryService.asmx.
Per ulteriori informazioni sulla creazione di un servizio Web, vedere Chiamata a servizi Web da script client.
Nel codice del servizio Web importare gli spazi dei nomi N:System.Data, N:System.Data.SqlClient, System.Configuration e 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;
Nel metodo del servizio Web che verrà creato, verranno utilizzati i tipi di questi spazi dei nomi.
Inserire la classe ProductQueryService in un spazio dei nomi denominato Samples.
Aggiungere l'attributo ScriptServiceAttribute alla classe.
Questo attributo consente al servizio Web di essere richiamato da uno script client.
Sostituire il metodo HelloWorld predefinito con il metodo GetProductQuantity seguente:
<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; }
Mediante il codice vengono effettuate le seguenti operazioni:
Viene creato un nuovo oggetto SqlConnection che utilizza una stringa di connessione denominata NorthwindConnectionString.
Viene creato un nuovo oggetto SqlCommand che contiene un comando SQL per recuperare il numero di unità in magazzino per un ID del prodotto specificato.
Il valore restituito viene impostato su una stringa utilizzata come risposta inviata al browser.
Nota: Per questa esercitazione il metodo Web introduce un ritardo artificiale. In pratica, non si introduce un ritardo. Il ritardo invece è il risultato del traffico del server o del servizio Web che richiede lunghi tempi di elaborazione, ad esempio una query di database di lunga durata.
Salvare le modifiche, quindi premere CTRL+F5 per visualizzare la pagina in un browser.
Fare clic sul collegamento GetProductQuantity per richiamare il metodo Web.
Immettere 6 nella casella productID, quindi fare clic su Richiama.
La quantità del prodotto viene restituita come XML nel browser dimostrando che il servizio Web funziona come 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; } } }
Creazione di codice JavaScript per chiamare il servizio Web
In questa procedura verrà creato un file JavaScript che chiama il servizio Web creato nella procedura precedente.
Per creare un file JavaScript per utilizzare il servizio Web
Creare un nuovo file JScript denominato ProductQueryScript.js.
Aggiungere al file il seguente script:
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; } }
Lo script esegue le seguenti attività:
Crea una funzione denominata GetQuantity che richiama il metodo del servizio Web GetProductQuantity.
Crea una funzione denominata OnSucceeded richiamata quando la chiamata del servizio Web restituisce un risultato.
Creazione di una pagina Web per la visualizzazione dei dati
Verrà ora creata una pagina Web contenente un controllo UpdatePanel. I controlli all'interno del controllo UpdatePanel consentono di visualizzare le informazioni dal database Northwind.
Per creare una pagina Web per visualizzare i prodotti
Creare una nuova pagina Web e passare alla visualizzazione Progettazione.
Nella scheda Estensioni AJAX della casella degli strumenti, fare doppio clic sul controllo ScriptManager per aggiungerlo alla pagina.
Fare doppio clic sul controllo UpdatePanel nella casella degli strumenti per aggiungere un controllo UpdatePanel alla pagina.
Fare clic all'interno del controllo UpdatePanel, quindi nella scheda Dati della casella degli strumenti fare doppio clic sul controllo DataList.
Nel pannello Attività DataList selezionare <Nuova origine dati...> dall'elenco Scegli origine dati.
Nota: Se il pannello Attività DataList non viene visualizzato, fare clic con il pulsante destro del mouse sul controllo DataList e selezionare Mostra smart tag.
Verrà visualizzata la Configurazione guidata origine dati.
Selezionare Database, accettare il nome predefinito SqlDataSource1, quindi fare clic su OK.
Nell'elenco Specificare la connessione dati che deve essere utilizzata dall'applicazione per connettersi al database selezionare NorthwindConnectionString, quindi scegliere Avanti.
In Specificare la modalità di recupero dei dati dal database selezionare Specificare le colonne di una tabella o visualizzazione, selezionare Products dall'elenco e nell'elenco Colonne selezionare ProductID e ProductName.
Fare clic sul pulsante WHERE.
Viene visualizzata la finestra di dialogo Aggiungi clausola WHERE.
Nell'elenco Colonne selezionare CategoryID e nell'elenco Origine selezionare Nessuna.
Nella sezione Proprietà parametro della finestra di dialogo immettere 1 nella casella di testo Valore.
Fare clic su Aggiungi per aggiungere la clausola WHERE all'istruzione SELECT.
Scegliere OK per chiudere la finestra di dialogo Aggiungi clausola WHERE.
Fare clic su Avanti, quindi su Fine per chiudere la procedura guidata.
Passare alla visualizzazione Origine e verificare che il controllo SqlDataSource sia simile a quello riportato nell'esempio seguente:
<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>
Passare alla visualizzazione Progettazione.
Selezionare il controllo DataList e nel pannello Attività DataList fare clic su Modifica modelli.
Aggiungere due controlli Button al controllo UpdatePanel all'esterno del controllo DataList.
Impostare la proprietà ID del primo pulsante su Category1Button e la relativa proprietà Text su Categoria 1. Impostare la proprietà ID del secondo pulsante su Category2Button e la relativa proprietà Text su Categoria 2.
Selezionare il controllo UpdatePanel e nella finestra Proprietà impostare la proprietà UpdateMode su Conditional e impostare la proprietà ChildrenAsTriggers su false.
Nella casella Trigger fare clic sul pulsante con i puntini di sospensione (…) e nella finestra di dialogo Editor dell'insieme UpdatePanelTrigger aggiungere ogni pulsante della categoria come trigger del postback asincrono.
Impostare il gestore eventi Click per il primo pulsante su Category1Button_Click e impostare il gestore eventi Click per il secondo pulsante su Category2Button_Click.
Passare alla visualizzazione Origine e creare i seguenti gestori eventi per i due pulsanti:
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"; }
Il codice del gestore eventi imposta il parametro CategoryID dell'insieme SelectParameters nel controllo SqlDataSource in base al pulsante che è stato premuto. In questo modo gli utenti possono passare facilmente da una categoria all'altra.
Salvare le modifiche e premere CTRL+F5 per visualizzare la pagina in un browser.
Fare clic su Categoria 2 e verificare che nella pagina vengano visualizzate le nuove informazioni ma non aggiornare l'intera pagina.
Nota: Non chiudere la pagina.
<%@ 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>
Chiamata di un servizio Web per il recupero dei dati
Verrà ora chiamato il servizio Web utilizzando il file JavaScript creato precedentemente. Il codice JavaScript utilizza i dati restituiti per popolare gli elementi DOM nel controllo UpdatePanel. Il codice server della pagina conserva i dati popolati dal servizio Web e aggiunge i dati allo stato di visualizzazione della pagina. Mantiene i dati in tutti i postback asincroni successivi.
Per utilizzare un servizio Web per restituire quantità di prodotto
Nella pagina passare alla visualizzazione Progettazione.
Selezionare il controllo DataList e nel pannello Attività DataList selezionare Modifica modelli.
Aggiungere un controllo TextBox e un controllo Button al modello di elemento.
Aggiungere i nuovi controlli sotto il testo e le etichette esistenti all'interno del modello.
Selezionare il pulsante e nella finestra Proprietà impostare la relativa proprietà Text su Ottieni quantità da servizio Web.
Il modello di elemento del controllo DataList deve essere simile a quello riportato nella figura seguente.
Selezionare il controllo DataList, quindi nella scheda Eventi della finestra Proprietà fare doppio clic sull'evento ItemDataBound.
Aggiungere il codice riportato di seguito.
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(); } }
Il codice imposta le proprietà per i controlli in ogni oggetto DataListItem come indicato di seguito:
La proprietà OnClientClick del pulsante chiama una funzione JavaScript che a sua volta chiama il servizio Web.
Il valore della casella di testo viene impostato se una proprietà di rilevamento denominata ProductInfo contiene una chiave per l'ID del prodotto. La proprietà ProductInfo viene definita nel successivo passaggio di questa procedura.
Aggiungere una proprietà denominata ProductInfo alla pagina.
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; } }
Questa proprietà è un oggetto SortedList che tiene traccia dei dati aggiunti alla pagina dal servizio Web. La prima volta che viene eseguito il rendering della pagina, l'elenco è vuoto. Gli elementi possono essere aggiunti all'elenco durante i successivi postback asincroni.
Aggiungere il seguente gestore eventi 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; } }
Il codice controlla se la richiesta è un postback asincrono. In caso affermativo, tutti gli elementi di dati aggiunti dal servizio Web verranno aggiunti alla proprietà ProductInfo. In questo modo è possibile tenerne traccia nello stato di visualizzazione e possono essere visualizzati nel controllo UpdatePanel durante i successivi aggiornamenti a pagina parziale. Gli elementi di dati non vengono mantenuti nei successivi postback asincroni se non ne viene tenuta traccia nello stato di visualizzazione.
Passare alla visualizzazione Progettazione.
Selezionare il controllo ScriptManager.
Nella finestra Proprietà selezionare la proprietà Services e fare clic sul pulsante con i puntini di sospensione (…) per visualizzare la finestra di dialogo Editor dell'insieme ServiceReference.
Fare clic su Aggiungi per aggiungere un riferimento al servizio.
Impostare la proprietà Path del riferimento al servizio su ProductQueryService.asmx, che rappresenta il servizio Web creato precedentemente.
Se si aggiunge un riferimento al servizio, il controllo ScriptManager genera le classi proxy client in modo da poter chiamare il servizio Web mediante JavaScript.
Scegliere OK per chiudere la finestra di dialogo Editor dell'insieme ServiceReference.
Selezionare il controllo ScriptManager, quindi nella finestra Proprietà selezionare la proprietà Scripts e fare clic sul pulsante con i puntini di sospensione (…) per visualizzare la finestra di dialogo Editor dell'insieme ScriptReference.
Fare clic su Aggiungi per aggiungere un riferimento allo script.
Impostare la proprietà Path del riferimento allo script su ProductQueryScript.js, che rappresenta il file JavaScript creato precedentemente.
Se si aggiunge un riferimento allo script, il controllo ScriptManager inserisce lo script dopo il caricamento della Microsoft AJAX Library.
Scegliere OK per chiudere la finestra di dialogo Editor dell'insieme ScriptReference.
Salvare le modifiche e premere CTRL+F5 per visualizzare la pagina in un browser.
Nella pagina vengono visualizzati i prodotti dal database Northwind con l'ID categoria 1. Le caselle di testo accanto a ogni prodotto sono vuote poiché non è stata effettuata alcuna chiamata del servizio 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>
Verifica della persistenza dei dati durante i postback asincroni
È ora possibile verificare la persistenza dei dati del servizio Web durante i postback asincroni.
Per verifica la persistenza dei dati del servizio Web durante i postback asincroni
Se la pagina non è in esecuzione, premere CTRL+F5 per eseguire la pagina.
Fare clic sul pulsante Ottieni quantità da servizio Web per un prodotto dell'elenco e attendere che il valore venga visualizzato nella casella di testo.
Fare clic sul pulsante Categoria 2.
Fare clic sul pulsante Categoria 1.
Il valore restituito precedentemente dal servizio Web rimane visualizzato anche dopo i postback asincroni.
Verifica
In questa esercitazione è stato illustrato un esempio dell'utilizzo di un controllo UpdatePanel con un servizio Web chiamato dal codice JavaScript nel browser. Il servizio Web restituisce i dati visualizzati nel controllo UpdatePanel.
Il risultato della chiamata del servizio Web dallo script client e del popolamento degli elementi DOM utilizzando i dati restituiti è lo stesso con o senza i controlli UpdatePanel. Quando una pagina esegue un postback o quando si verifica un postback asincrono, i dati visualizzati precedentemente mediante lo script client andranno persi. Per evitare questo problema è possibile utilizzare il codice server per rendere persistenti i dati includendoli nello stato di visualizzazione. In questo modo è possibile mantenere i dati durante i successivi postback. Se i dati dal servizio Web vengono visualizzati negli elementi DOM all'esterno dei controlli UpdatePanel e non si desidera rendere persistenti i dati durante i postback asincroni, non è necessario fornire il codice server per conservare i dati.
Poiché il pulsante che ha generato la chiamata del servizio Web è all'interno del controllo UpdatePanel, la proprietà ChildrenAsTriggers viene impostata su false. Gli altri controlli di postback nel pannello vengono definiti come trigger del pannello.