다음을 통해 공유


웹 서비스에서 UpdatePanel 컨트롤 사용

업데이트: 2007년 11월

ASP.NET의 AJAX 기능은 비동기 포스트백 요청을 관리하고 자동으로 업데이트하기 때문에 UpdatePanel 컨트롤은 ASP.NET 웹 페이지에서의 부분 페이지 렌더링을 단순화합니다. 또한 AJAX 기능을 사용하면 브라우저에서 ECMAScript(JavaScript)를 사용하여 ASP.NET 웹 서비스를 호출할 수 있습니다. 클라이언트 스크립트를 사용하여 웹 서비스를 호출할 때의 장점 중 하나는 웹 서비스 요청의 응답을 기다려도 브라우저를 차단하지 않는다는 것입니다. 사용자는 웹 서비스가 요청 처리를 완료할 때까지 기다리지 않고도 계속 작업할 수 있습니다.

이 자습서에서는 UpdatePanel 컨트롤을 사용하여 웹 서비스를 사용하는 방법을 보여 줍니다. JavaScript 함수는 웹 서비스를 호출하여 데이터를 검색한 다음 UpdatePanel 컨트롤 내부의 DOM 요소를 웹 서비스에서 반환된 데이터로 채웁니다. 서버 코드는 비동기 포스트백 사이에서 검색된 웹 서비스 데이터를 유지합니다.

이 항목에서는 사용자가 UpdatePanel 컨트롤과 웹 서비스에 대해 잘 알고 있다고 가정합니다. 그렇지 않은 경우 다음 항목을 검토하십시오.

사전 요구 사항

고유한 개발 환경에서 절차를 구현하려면 다음이 필요합니다.

  • Microsoft Visual Studio 2005 또는 Visual Web Developer Express Edition

  • AJAX 사용 ASP.NET 웹 사이트

  • Web.config 파일에 정의된 NorthwindConnectionString이라는 Northwind 데이터베이스 및 연결 문자열에 대한 액세스. 연결 문자열을 만드는 방법에 대한 자세한 내용은 방법: Web.config 파일에서 연결 문자열 읽기를 참조하십시오.

웹 서비스 만들기

시작하기 위해 호출할 수 있는 웹 서비스를 만듭니다.

웹 서비스를 만들어 제품 수량을 반환하려면

  1. AJAX 사용 ASP.NET 웹 사이트에서 ProductQueryService.asmx라는 웹 서비스 파일을 새로 만듭니다.

    웹 서비스를 만드는 방법에 대한 자세한 내용은 클라이언트 스크립트에서 웹 서비스 호출을 참조하십시오.

  2. 웹 서비스 코드에서 N:System.Data, N:System.Data.SqlClient, System.ConfigurationN: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;
    

    이러한 네임스페이스의 형식은 만들 웹 서비스 메서드에서 사용됩니다.

  3. ProductQueryService 클래스를 Samples라는 네임스페이스 내부에 배치합니다.

  4. 클래스에 ScriptServiceAttribute 특성을 추가합니다.

    이 특성을 사용하면 클라이언트 스크립트에서 웹 서비스를 호출할 수 있습니다.

  5. 기본 HelloWorld 메서드를 다음 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;
    }
    

    이 코드는 다음 작업을 수행합니다.

    • NorthwindConnectionString이라는 연결 문자열을 사용하는 새 SqlConnection 개체를 만듭니다.

    • 지정한 제품 ID에 대해 재고 단위 수를 검색하는 SQL 명령이 포함된 SqlCommand 개체를 새로 만듭니다.

    • 반환 값을 브라우저로 보낼 응답으로 사용된 문자열로 설정합니다.

      참고:

      이 자습서에서는 웹 메서드에서 인위적 지연을 적용합니다. 실제로는 지연을 적용하지 않습니다. 대신 지연은 서버 트래픽의 결과이거나, 실행 시간이 긴 데이터베이스 쿼리 같이 처리 시간이 오래 걸리는 웹 서비스 코드의 결과가 됩니다.

  6. 변경 내용을 저장한 다음 Ctrl+F5를 눌러 브라우저에서 페이지를 봅니다.

  7. GetProductQuantity 링크를 클릭하여 웹 메서드를 호출합니다.

  8. productID 상자에 6을 입력한 다음 호출을 클릭합니다.

    제품 수량이 브라우저에서 XML로 반환됩니다. 이는 웹 서비스가 의도한 대로 작동되고 있음을 나타냅니다.

    <%@ 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;
            }
        }
    }
    

JavaScript 코드를 만들어 웹 서비스 호출

이 절차에서는 이전 절차에서 만든 웹 서비스를 호출하는 JavaScript 파일을 만듭니다.

JavaScript 파일을 만들어 웹 서비스를 사용하려면

  1. ProductQueryScript.js라는 JScript 파일을 새로 만듭니다.

  2. 이 파일에 다음 스크립트를 추가합니다.

    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;
       }
    }
    

    이 스크립트는 다음 작업을 수행합니다.

    • GetProductQuantity 웹 서비스 메서드를 호출하는 GetQuantity라는 함수를 만듭니다.

    • 웹 서비스 호출이 결과와 함께 반환될 때 호출되는 OnSucceeded라는 함수를 만듭니다.

웹 페이지를 만들어 데이터 표시

다음에는 UpdatePanel 컨트롤이 포함된 웹 페이지를 만듭니다. UpdatePanel 컨트롤 내부의 컨트롤은 Northwind 데이터베이스에서 제품 정보를 표시합니다.

웹 페이지를 만들어 제품을 표시하려면

  1. 새 웹 페이지를 만들고 디자인 뷰로 전환합니다.

  2. 도구 상자의 AJAX 확장 탭에서 ScriptManager 컨트롤을 두 번 클릭하여 페이지에 추가합니다.

  3. 도구 상자에서 UpdatePanel 컨트롤을 두 번 클릭하여 UpdatePanel 컨트롤을 페이지에 추가합니다.

  4. UpdatePanel 컨트롤의 내부를 클릭한 다음 도구 상자의 데이터 탭에서 DataList 컨트롤을 두 번 클릭합니다.

  5. DataList 작업 패널의 데이터 소스 선택 목록에서 **<새 데이터 소스...>**를 선택합니다.

    참고:

    DataList 작업 패널이 표시되지 않으면 DataList 컨트롤을 마우스 오른쪽 단추로 클릭하고 스마트 태그 표시를 선택합니다.

    데이터 소스 구성 마법사가 표시됩니다.

  6. 데이터베이스를 선택하고 기본 이름인 SqlDataSource1을 적용한 다음 확인을 클릭합니다.

  7. 응용 프로그램이 데이터베이스에 연결하기 위해 사용해야 하는 데이터 연결 목록에서 NorthwindConnectionString을 선택하고 다음을 클릭합니다.

  8. 데이터베이스에서 데이터를 검색하는 방법에서 테이블 또는 뷰의 열 지정을 선택하고 목록에서 제품을 선택한 다음 목록에서 ProductIDProductName을 선택합니다.

  9. WHERE 단추를 클릭합니다.

    그러면 WHERE 절 추가 대화 상자가 표시됩니다.

  10. 목록에서 CategoryID를 선택하고 소스 목록에서 없음을 선택합니다.

  11. 대화 상자의 매개 변수 속성 섹션에 있는 텍스트 상자에 1을 입력합니다.

  12. 추가를 클릭하여 WHERE 절을 SQL 문에 추가합니다.

  13. 확인을 클릭하여 WHERE 절 추가 대화 상자를 닫습니다.

  14. 다음을 클릭한 다음 마침을 클릭하여 마법사를 닫습니다.

  15. 소스 뷰로 전환하고 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>
    
    <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. 디자인 뷰로 전환합니다.

  17. DataList 컨트롤을 선택하고 DataList 작업 패널에서 템플릿 편집을 클릭합니다.

  18. DataList 컨트롤 외부에 있는 UpdatePanel 컨트롤에 두 개의 Button 컨트롤을 추가합니다.

  19. 첫 번째 단추의 ID 속성을 Category1Button으로 설정하고 해당 Text 속성을 Category 1로 설정합니다. 두 번째 단추의 ID 속성을 Category2Button으로 설정하고 해당 Text 속성을 Category 2로 설정합니다.

  20. UpdatePanel 컨트롤을 선택하고 속성 창에서 UpdateMode 속성을 Conditional로 설정한 다음 ChildrenAsTriggers 속성을 false로 설정합니다.

  21. 트리거 상자에서 줄임표(…) 단추를 클릭하고 UpdatePanel Trigger 컬렉션 편집기 대화 상자에서 각 범주 단추를 비동기 포스트백 트리거로 추가합니다.

  22. 첫 번째 단추의 Click 이벤트 처리기를 Category1Button_Click으로 설정하고 두 번째 단추의 Click 이벤트 처리기를 Category2Button_Click으로 설정합니다.

  23. 소스 뷰로 전환하고 두 개의 단추에 대해 다음 이벤트 처리기를 만듭니다.

    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";
    }
    

    이벤트 처리기 코드는 눌러진 단추에 따라 SqlDataSource 컨트롤에서 SelectParameters 컬렉션의 CategoryID 매개 변수를 설정합니다. 따라서 사용자는 두 범주 사이를 전환할 수 있습니다.

  24. 변경 내용을 저장하고 Ctrl+F5를 눌러 브라우저에서 페이지를 봅니다.

  25. Category 2를 클릭하고 해당 페이지에서 새 정보가 표시되지만 전체 페이지를 새로 고치지는 않음을 확인합니다.

    참고:

    해당 페이지를 닫지 마십시오.

    <%@ 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>
    

웹 서비스를 호출하여 데이터 검색

이제 앞서 만든 JavaScript 파일을 사용하여 웹 서비스를 호출합니다. JavaScript 코드는 반환된 데이터를 사용하여 UpdatePanel 컨트롤 내부의 DOM 요소를 채웁니다. 페이지의 서버 코드는 웹 서비스에서 채운 데이터를 유지하고 해당 데이터를 페이지의 뷰 상태에 추가합니다. 이렇게 하면 모든 후속 비동기 포스트백에서 데이터가 유지됩니다.

웹 서비스를 사용하여 제품 수량을 반환하려면

  1. 페이지의 디자인 뷰로 전환합니다.

  2. DataList 컨트롤을 선택하고 DataList 작업 패널에서 템플릿 편집을 선택합니다.

  3. TextBoxButton 컨트롤을 항목 템플릿에 추가합니다.

    새 컨트롤을 템플릿의 기존 텍스트와 레이블 아래에 추가합니다.

  4. 단추를 선택하고 속성 창에서 해당 Text 속성을 Get Quantity from Web Service로 설정합니다.

    DataList 컨트롤의 항목 템플릿은 다음 그림과 유사해야 합니다.

  5. DataList 컨트롤을 선택하고 속성 창의 이벤트 탭에서 ItemDataBound 이벤트를 두 번 클릭합니다.

  6. 아래와 같은 코드를 추가합니다.

    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();
        }        
    }
    

    이 코드는 각 DataListItem 개체의 컨트롤에 대한 속성을 다음과 같이 설정합니다.

    • 해당 단추의 OnClientClick 속성은 JavaScript 함수를 호출하고 이 함수는 웹 서비스를 호출합니다.

    • ProductInfo라는 추적 속성에 제품 ID의 키가 포함된 경우 텍스트 상자의 값이 설정됩니다. ProductInfo 속성은 이 절차의 다음 단계에 정의됩니다.

  7. ProductInfo라는 속성을 페이지에 추가합니다.

    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; }
    }
    

    이 속성은 웹 서비스에서 페이지로 추가된 데이터를 추적하는 SortedList 개체입니다. 페이지가 처음으로 렌더링되면 해당 목록이 비어 있습니다. 후속 비동기 포스트백 동안 항목이 목록에 추가될 수 있습니다.

  8. 다음 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;
        }
    }
    

    이 코드는 요청이 비동기 포스트백인지 여부를 검사합니다. 비동기 포스트백인 경우 웹 서비스에 의해 추가된 데이터 항목이 ProductInfo 속성에 추가됩니다. 따라서 후속 부분 페이지 업데이트 동안 뷰 상태에서 데이터 항목을 추적할 수 있고 UpdatePanel에서 표시할 수 있습니다. 데이터 항목이 뷰 상태에서 추적되지 않는 경우 후속 비동기 포스트백에서 유지되지 않습니다.

  9. 디자인 뷰로 전환합니다.

  10. ScriptManager 컨트롤을 선택합니다.

  11. 속성 창에서 서비스 속성을 선택하고 줄임표(…) 단추를 클릭하여 ServiceReference 컬렉션 편집기 대화 상자를 표시합니다.

  12. 추가를 클릭하여 서비스 참조를 추가합니다.

  13. 서비스 참조의 경로 속성을 앞에서 만든 웹 서비스인 ProductQueryService.asmx로 설정합니다.

    서비스 참조를 추가하면 JavaScript를 사용하여 웹 서비스를 호출할 수 있도록 ScriptManager 컨트롤에서 클라이언트 프록시 클래스를 생성하게 합니다.

  14. 확인을 클릭하여 ServiceReference 컬렉션 편집기 대화 상자를 닫습니다.

  15. ScriptManager 컨트롤을 선택한 다음 속성 창에서 스크립트 속성을 선택하고 줄임표(…) 단추를 클릭하여 ScriptReference 컬렉션 편집기 대화 상자를 표시합니다.

  16. 추가를 클릭하여 스크립트 참조를 추가합니다.

  17. 스크립트 참조의 경로 속성을 이전에 만든 JavaScript 파일인 ProductQueryScript.js로 설정합니다.

    스크립트 참조를 추가하면 Microsoft AJAX 라이브러리가 로드된 다음 ScriptManager 컨트롤이 스크립트를 삽입합니다.

  18. 확인을 클릭하여 ScriptReference 컬렉션 편집기 대화 상자를 닫습니다.

  19. 변경 내용을 저장하고 Ctrl+F5를 눌러 브라우저에서 페이지를 봅니다.

    페이지에 범주 ID가 1인 Northwind 데이터베이스의 제품이 표시됩니다. 웹 서비스를 호출한 적이 없기 때문에 각 제품 옆의 텍스트 상자가 비어 있습니다.

    <%@ 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>
    

비동기 포스트백 동안 데이터가 유지되는지 확인

이제 비동기 포스트백 동안 웹 서비스의 데이터가 어떻게 유지되는지 알아 보겠습니다.

비동기 포스트백 동안 웹 서비스 데이터가 유지되는지 확인하려면

  1. 페이지가 아직 실행되고 있지 않으면 Ctrl+F5를 눌러 페이지를 실행합니다.

  2. 목록에 있는 임의의 제품에 대해 Get Quantity from Web Service 단추를 클릭하고 텍스트 상자에 해당 값이 표시될 때까지 기다립니다.

  3. Category 2 단추를 클릭합니다.

  4. Category 1 단추를 클릭합니다.

    비동기 포스트백 후에도 웹 서비스에서 이전에 반환한 값이 계속 표시됩니다.

검토

이 자습서에서는 브라우저의 JavaScript 코드에서 호출된 웹 서비스에서 UpdatePanel 컨트롤을 사용하는 예제를 보여 줍니다. 웹 서비스에서는 UpdatePanel 컨트롤 내에 표시되는 데이터를 반환합니다.

클라이언트 스크립트에서 웹 서비스를 호출하고 반환된 데이터를 사용하여 DOM 요소를 채우는 결과는 UpdatePanel 컨트롤 사용 여부에 상관없이 같습니다. 페이지에서 포스트백을 수행하거나 비동기 포스트백이 발생하면 클라이언트 스크립트를 사용하여 이전에 표시한 데이터는 손실됩니다. 이 문제를 방지하기 위해 서버 코드를 사용하여 데이터를 뷰 상태의 일부로 만들어서 해당 데이터를 유지할 수 있습니다. 이렇게 하면 후속 포스트백 동안 데이터가 유지될 수 있습니다. 웹 서비스의 데이터가 UpdatePanel 컨트롤의 외부에 있는 DOM 요소에 표시되고 비동기 포스트백 동안 데이터를 유지하지 않으려는 경우 데이터를 유지하기 위해 서버 코드를 제공할 필요가 없습니다.

웹 서비스 호출을 트리거한 단추가 UpdatePanel 컨트롤 내부에 있기 때문에 ChildrenAsTriggers 속성이 false로 설정됩니다. 패널 내부에 있는 다른 포스트백 컨트롤은 해당 패널에 대한 트리거로 정의됩니다.

참고 항목

개념

웹 서비스를 클라이언트 스크립트로 노출

클라이언트 스크립트에서 웹 서비스 호출