Silverlight를 설치하려면 여기를 클릭합니다.*
Korea 대한민국변경|Microsoft 전체 사이트
MSDN
|개발자 센터
MSDN 홈 > MSDN 칼럼 > At Your Service > .NET Framework를 사용하여 HTTP를 통해 비동기 Web Service 호출

.NET Framework를 사용하여 HTTP를 통해 비동기 Web Service 호출

Matt Powell
Microsoft Corporation

2002년 9월 9일

요약: Matt Powell은 HTTP를 통해 비동기 Web Service를 호출하기 위해 Microsoft .NET Framework에서 제공하는 다양한 옵션을 조사했습니다. HTTP를 통해 비동기 Web Service를 호출하면 시간이 오래 걸릴 수 있는 네트워크 호출을 완료하면서 응용 프로그램을 차단하지 않고 Web Service를 효율적으로 호출할 수 있습니다(11페이지/인쇄 페이지 기준).


Web Service를 사용하는 응용 프로그램을 작성할 때 네트워크에서 호출을 할 경우 관련된 대기 시간을 반드시 처리해야 합니다. 특정한 경우에, 특히 대역폭이 높은 개인 네트워크에서 호출은 0.5초 이내로 완료될 수 있고 대기 시간은 별로 중요하지 않습니다. 그러나 인터넷을 통해 원격 위치로 요청을 보내거나 처리 시간이 많이 필요한 호출을 할 경우 오랜 시간의 지연이 응용 프로그램에 미칠 수 있는 영향을 고려해 보아야 합니다. 예를 들어, Microsoft Windows Forms 응용 프로그램이 Web Service에 대한 호출이 반환되기를 기다리는 동안 중지된 것 처럼 보일 수 있습니다. Microsoft ASP.NET 페이지에서 Web Service를 호출할 경우 여러 Web Service를 호출하면 페이지 표시가 몇 배나 더 느려지는 것을 알 수 있습니다. 많은 Web Service를 호출 중인 응용 프로그램이 있는 경우 가능한 한 효율적으로 Web Service를 호출하는 방법에 대해 생각해 보아야 합니다.

이러한 많은 문제점에 대한 해결책은 Web Service 호출을 비동기적으로 만드는 것입니다. 비동기 호출은 즉시 반환되고 실제 호출이 완료된 시기를 나타내기 위해 다른 메커니즘을 사용합니다. 그러면 응용 프로그램에서 필요한 백그라운드 작업과 같은 다른 작업을 수행할 수 있고, UI를 사용하여 사용자 상호 작용에 응답하고, 요청의 현재 상태에 대한 피드백을 제공하거나, 심지어 다른 Web Service 호출을 시작할 수도 있습니다. Microsoft .NET Framework에서 HTTP를 통해 비동기 Web Service 호출을 하기 위한 지원을 제공하는 방법과 몇 가지 일반 시나리오에서 이 호출을 사용할 수 있는 방법에 대해 살펴보겠습니다.

빌딩 블록

Microsoft Visual Studio .NET에서 웹 참조 추가 옵션을 선택한 경우 System.Web.Services.Protocols.SoapHttpClientProtocol에서 상속된 클래스가 자동으로 만들어집니다. SoapHttpClientProtocol에는 Web Service에서 노출한 메서드 중 하나로 호출할 때 실제 사용되는 Invoke라는 보호된 함수가 있습니다. Web Service의 WSDL에 정의된 각각의 웹 메서드에 대해 마법사는 해당하는 이름 매개 변수와 반환 값이 있는 함수를 만듭니다. 그런 다음 이러한 각각의 함수에서 매개 변수 정보 등을 전달하여 SoapHttpClientProtocol 클래스에서 Invoke 함수를 호출합니다. 이 기사의 경우 의도적으로 반환하는 데 시간이 오래 걸리는 메서드를 사용하여 Web Service를 만들었습니다. 이 웹 메서드는 DelayedResponse라고 하며 유일한 매개 변수로 정수를 사용하고 문자열을 반환합니다. 웹 참조 추가 옵션은 이 메서드에 대한 다음 프록시 코드를 생성합니다.

Public Function DelayedResponse(ByVal waitPeriod As Integer) _
        As String
    Dim results() As Object _
        = Me.Invoke("DelayedResponse", _
                    New Object() {waitPeriod})
    Return CType(results(0),String)
End Function
 

Invoke 메서드는 두 개의 매개 변수를 사용하는데, 함수 이름과 매개 변수를 갖고 있는 개체 배열이 함수에 전달됩니다. Invoke 메서드는 개체 배열을 반환하는데, 이 경우 함수에서 반환된 문자열인 하나의 요소만 포함되어 있습니다. 이것이 반환하기 전에 응답을 받을 때까지 대기하는 동기 호출을 만드는 메커니즘입니다.

SoapHttpClientProtocol 클래스에도 BeginInvoke라는 메서드가 있는데, 이것이 바로 비동기 요청을 시작하는 데 사용하는 메커니즘입니다. 웹 참조 추가로 만든 클래스도 이전에 살펴본 차단 DelayedResponse 함수와 함께 이동하는 BeginDelayedResponse라는 공용 함수를 만듭니다. BeginDelayedResponse에 대한 코드는 다음과 같습니다.

Public Function BeginDelayedResponse( _
        ByVal waitPeriod As Integer, _
        ByVal callback As System.AsyncCallback, _
        ByVal asyncState As Object) As System.IAsyncResult
   Return Me.BeginInvoke("DelayedResponse", _
                         New Object() {waitPeriod}, _
                         callback, _
                         asyncState)
End Function

BeginDelayedResponse에서는 이전에 사용한 Invoke 메서드와 여러 가지 유사한 점이 있는 BeginInvoke 메서드를 사용합니다. 처음 두 개의 매개변수는 Invoke 메서드에 사용한 매개 변수와 같습니다. 그러나 BeginInvoke에는 두 개의 추가 매개 변수가 있고 더 이상 개체 배열을 반환하지 않습니다. 중요한 차이점은 BeginInvoke에서는 즉시 반환하고 Web Service 호출이 완료될 때까지 기다리지 않는다는 것입니다.

BeginInvoke에 대한 두 개의 추가 매개 변수 중 첫 번째 것을 살펴보면 System.AsyncCallback이라는 것이 있습니다. 이것은 '대리자'라고 하는 것인데, 기본적으로 관리되는 코드에서 함수 포인터를 선언하기 위한 메커니즘입니다. 이 경우 웹 메서드 호출이 완료되면 해당 함수가 호출되고 응답을 받게 됩니다.

BeginInvoke에 대한 마지막 매개 변수는 asyncState라고 하는 것인데 개체 형식으로 간단하게 선언됩니다. 이것이 바로 이 요청을 추적하기 위해 사용하려는 것입니다. 여러 다른 비동기 요청에 대해 동일한 콜백 함수를 사용할 수 있습니다. 따라서 한 호출의 응답을 다른 호출의 응답과 구분하려면 호출에 대한 정보를 asyncState 매개 변수에 넣습니다. 그러면 콜백 함수에서 이 정보를 사용할 수 있습니다.

BeginInvoke에 대해 구별되는 마지막 한 가지는 반환하는 내용입니다. 확실한 것은 호출이 완료되지 않으면 웹 메서드에 대한 응답 데이터를 반환할 수 없습니다. 반환하는 내용은 System.IAsyncResult 인터페이스 포인터입니다. IAsyncResult 인터페이스 포인터를 사용하여 요청에 대한 정보를 가져올 수 있습니다. IAsyncResult에서는 다음과 같은 네 개의 공용 속성을 노출합니다.

속성 설명
AsyncState BeginInvoke 메서드의 네 번째 매개 변수로 전달된 데이터입니다.
AsyncWaitHandle 하나 이상의 Web Service 호출이 완료될 때까지 스레드의 현재 실행을 차단하는 데 사용할 수 있는 WaitHandle 개체입니다.
CompletedSynchronously 이 매개 변수는 Web Service 호출에 적용되지 않습니다. 여러 I/O 작업에 IAsyncResult 인터페이스를 사용합니다. 이 속성을 사용하면 비동기 I/O 작업 요청이 빠르게 완료되어 Begin 함수가 반환되지 전에 완료되었는지 여부를 알 수 있습니다.
IsCompleted 호출이 완료되었는지 여부를 확인하는 데 사용할 수 있는 플래그입니다.

IAsyncResult 포인터를 사용하면 사용자와 시스템에서 비동기 완료를 서로 구분할 수 있습니다. 또한 호출이 완료된 시기를 확인할 수 있는 다른 옵션도 제공합니다. 이러한 옵션을 사용하는 방법에 대해 간단히 살펴보겠습니다.

이전에 설명한 것처럼 웹 참조 추가 옵션은 BeginInvoke를 사용하는 서비스에서 제공한 각각의 웹 메서드에 대한 함수를 만듭니다. 이번 경우에 생성된 함수는 BeginDelayedResponse라고 하는데, BeginInvoke 메서드에 대한 씬 래퍼이고 BeginInvoke에서 제공하는 콜백 및 asyncState 매개 변수 뿐만 아니라 웹 메서드에 대한 매개 변수도 노출합니다. 다음에는 비동기 요청을 만들고 이 요청이 완료되는 시기를 확인하기 위한 세 가지 옵션을 살펴보겠습니다.

비동기 호출을 위한 세 가지 옵션

각각의 응용 프로그램은 서로 다르며, 일부 응용 프로그램에서는 작동하고 다른 응용 프로그램에서는 작동하지 않을 수 있는 비동기 호출을 만들기 위한 시나리오가 있습니다. 비동기 호출을 만들기 위해 제공된다는 점에서 .NET Framework는 매우 융통성이 있습니다. 요청이 완료된 시기를 확인하기 위해 폴링하거나, WaitHandle에서 차단하거나, 콜백 함수를 기다릴 수 있습니다. 각각의 방법을 살펴보겠습니다.

완료 폴링

BeginDelayedResponse 함수에서 반환된 IAsyncResult 인터페이스에는 요청이 완료되었는지 여부를 확인하기 위해 선택할 수 있는 IsCompleted 속성이 있습니다. 사용자에게 있는 한 가지 옵션은 이 속성에서 True 값을 반환할 때까지 이 속성을 폴링하는 것입니다. 다음은 이 방법을 보여주는 약식 코드입니다.

' 프로세서를 종료시킬 수 있는 폴링 코드
Dim proxy as New localhost.Service1()
Dim result as IAsyncResult
Result = proxy.BeginDelayedResponse(2000, _
                                    Nothing, _
                                    Nothing)
While (result.IsCompleted = False)
    ' 작업을 처리합니다. 
        ...
Wend
Dim response as String
response = proxy.EndDelayedResponse(result)

완료 폴링은 상당히 간단한 방법이지만 몇 가지 단점이 있습니다. 이 코드는 BeginDelayedResponse에 대한 초기 호출을 만들고, 웹 메서드에 전달할 매개 변수로 2000을 전달한 다음 콜백과 asyncState를 Nothing으로 설정하는 것을 보여줍니다. 그러면 IsCompleted 속성이 True가 될 때까지 이 속성을 폴링하는 while 루프가 생깁니다. 호출이 완료되고 IsCompleted 속성이 True로 설정되면 while 루프에서 빠져나오고 EndDelayedResponse라는 웹 참조 추가 생성 클래스의 다른 함수를 사용하여 응답을 가져옵니다. EndDelayedResponseSoapHttpClientProtocol 클래스의 EndInvoke 메서드에 대한 래퍼 함수이고, 웹 메서드 호출에서 반환된 데이터를 가져오기 위한 메커니즘입니다. Web Service 호출이 완료되었음을 안 후에 사용하는 것이고, 호출을 차단하기 위해 Invoke 메서드에서 반환하는 것과 같은 정보를 반환합니다. Web Service 호출 결과를 가져오기 위해 세 가지 모든 비동기 시나리오에서 EndDelayedResponse 메서드를 사용할 것입니다. 요청이 완료되기 전에 EndDelayedResponse를 호출하면 아무런 의미가 없고, 요청이 완료될 때까지 차단만 할 뿐입니다.

호출이 완료되었는지 확인하기 위해 폴링을 사용할 경우 주의해야 할 문제점 중 하나는 조심하지 않으면 컴퓨터의 많은 CPU 사이클 사용을 종료시킬 수 있다는 점입니다. 예를 들어, while 루프에 코드에 없으면 이 코드를 실행하는 스레드에서 컴퓨터에 있는 대부분의 처리 리소스를 다 써버릴 수 있습니다. 사실 대부분의 처리 시간을 써버리기 때문에 Web Service 요청을 보내고 응답을 받기 위한 기본 코드가 지연될 수 있습니다. 따라서 폴링 사용 방법에 주의를 기울여야 합니다.

Web Service 요청이 완료될 때까지 기다리려면 다음에서 살펴볼 WaitHandle 방법을 사용해야 할 것입니다. 그러나 수행해야 할 작업이 많고 Web Service 호출이 완료되었는지 가끔 확인하려는 경우에는 폴링을 사용하는 것도 나쁜 방법은 아닙니다. 대부분 응용 프로그램에서는 다른 비동기 방법 중 하나와 함께 폴링을 조합해서 사용합니다. 예를 들어, 실행할 일부 백그라운드 작업이 있기 때문에 Web Service 호출을 비동적으로 만들 수 있지만, 백그라운드 작업을 완료하면 Web Service가 완료될 때까지 차단하려고 할 수 있습니다. 이 경우 작업을 실행하면서 가끔 폴링할 수 있습니다. 그런 다음 백그라운드 작업이 완료되면 WaitHandle을 사용하여 결과를 기다릴 수 있습니다.

WaitHandle 사용

WaitHandle은 비동기 호출을 만들어야 하지만 현재 실행 중인 스레드를 릴리스하지 않으려는 시나리오에서 편리합니다. 예를 들어, ASP.NET 응용 프로그램 내에서 비동기 Web Service 호출을 한 다음 ASP.NET 응용 프로그램에 대해 처리 중인 이벤트에서 반환할 경우 사용자에게 반환된 데이터에 Web Service 호출의 데이터를 포함시킬 기회가 없을 수도 있습니다. WaitHandle을 사용하면 Web Service 호출을 만든 후 일부 작업을 처리한 다음 Web Service 호출이 완료될 때까지 차단할 수 있습니다. WaitHandle은 ASP.NET 페이지에서 여러 Web Service 호출을 할 경우에 특히 유용합니다.

BeginDelayedResponse 함수에서 반환된 IAsyncResult에서 WaitHandle 개체에 대한 액세스를 제공합니다. 다음 코드는 WaitHandle 방법을 사용한 간단한 시나리오를 보여줍니다.

' 간단한 WaitHandle 코드 
Dim proxy As New localhost.Service1()
Dim result As IAsyncResult
result = proxy.BeginDelayedResponse(2000, Nothing, Nothing)
'  작업을 처리합니다. 
'       ...
'  작업을 완료합니다.  완료를 기다립니다. 
result.AsyncWaitHandle.WaitOne()
Dim response As String
response = proxy.EndDelayedResponse(result)

위 코드에서는 WaitHandle 개체의 WaitOne 메서드를 사용하여 이 하나의 핸들을 기다립니다. 또한 WaitHandle 클래스에는 WaitAllWaitAny라는 정적 메서드가 있습니다. 이 두 정적 메서드는 WaitHandle의 배열을 매개 변수로 사용하고, 호출한 함수에 따라 모든 호출이 완료되거나 호출 하나가 완료되는 즉시 반환합니다. 별도의 세 가지 Web Service를 호출한다고 가정해 봅시다. 각각의 Web Service를 비동기로 호출하고, 배열에 각각의 WaitHandle을 배치한 다음 완료될 때까지 WaitAll 메서드를 호출할 수 있습니다. 그러면 Web Service 호출을 동시에 실행할 수 있습니다. 이를 동기적으로 실행할 경우 실행 시간이 대략 세 배가 되는 병렬로 실행할 수는 없습니다.

WaitOne, WaitAllWaitAny 메서드 모두에는 시간 제한을 매개 변수로 사용하는 옵션이 있어야 합니다. 이 옵션을 사용하면 Web Service가 완료될 때까지 대기할 시간을 제어할 수 있습니다. 메서드에서 시간 초과되면 False 값을 반환합니다. 그러면 다시 기다리기 전에 더 많은 작업을 하거나 요청을 취소할 수 있는 기회가 제공됩니다.

콜백 사용

비동기 Web Service 호출을 실행할 수 있는 세 번째 방법은 콜백을 사용하는 것입니다. 동시에 Web Service 호출을 많이 만드는 경우에는 콜백을 사용하는 것이 매우 효율적일 수 있습니다. 이 방법은 Web Service 호출에 대한 결과에서 백그라운드 작업을 할 수 있게 해줍니다. 그러나 이 방법은 다른 두 방법보다는 더 복잡합니다. Windows에 대한 메시지 스레드의 차단을 방지하기 때문에 Microsoft Windows 응용 프로그램에서 콜백을 사용하는 것이 특히 좋은 방법입니다.

콜백에서는 Web Service 호출이 완료되었을 때 호출되는 콜백 함수를 만듭니다. 그러나 원래 BeginInvoke 호출을 만드는 스레드의 컨텍스트에서는 콜백 함수를 호출할 수 없습니다. 따라서 Windows Form 응용 프로그램의 컨트롤로 명령을 보내는 문제가 생길 수 있습니다. 특정 창에 대한 메시지 작업을 처리하는 특정 스레드에서 이러한 명령을 호출해야 하기 때문입니다. 다행히도 이 문제를 해결할 수 있는 방법이 있습니다.

다음 코드는 콜백을 사용하고 Web Service 호출 결과를 레이블 컨트롤로 표시하는 간단한 시나리오를 보여 줍니다.

Dim proxy as localhost.Service1
Private Delegate Sub MyDelegate(ByVal response As String)

Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button1.Click
    proxy = New localhost.Service1()
    proxy.BeginDelayedResponse(2000, _
            New AsyncCallback(AddressOf Me.ServiceCallback), _
            Nothing)
End Sub

Private Sub ServiceCallback(ByVal result As IAsyncResult)
    Dim response As String
    response = proxy.EndDelayedResponse(result)
    Label1.Invoke( _
        New MyDelegate(AddressOf Me.DisplayResponse), _
        New Object() {response})
End Sub

Private Sub DisplayResponse(ByVal response As String)
    Label1.Text = response
End Sub

이 코드에서는 Button1_Click 이벤트의 BeginDelayedResponse를 호출한 다음 서브루틴에서 반환합니다. 이 경우 두 번째 매개 변수로 Nothing을 전달하는 대신 AsyncCallback 개체를 전달합니다. 기본적으로 이것은 ServiceCallback이라는 콜백 함수의 주소를 래핑하는 방법입니다. ServiceCallback 함수는 IAsyncResult 형식의 단일 매개 변수를 사용하는 서브루틴이어야 합니다. SoapHttpClientProtocol 클래스에서 이 함수를 호출하고 완료된 Web Service 호출에 해당하는 IAsyncResult 인터페이스 포인터를 제공합니다. 다시 EndDelayedResponse 메서드를 사용하여 결과를 가져오지만 작은 문제가 생깁니다.

콜백이 해당 창의 주 스레드에 있지 않기 때문에 이 창의 레이블에 대한 텍스트를 설정할 수 있게 해주는 다른 Invoke 메서드를 사용해야 합니다. 모든 컨트롤에는 주 메시지 스레드에서 실행되는 함수를 호출하기 위해 호출할 수 있는 Invoke 메서드가 있습니다. 레이블 컨트롤에서 Invoke를 사용하는 것은 이미 살펴본 일부 다른 방법과 유사합니다. Invoke에서 호출하게 할 함수의 주소를 Invoke에 제공하고, 해당 함수에 전달할 매개 변수를 두 번째 매개 변수로 개체 배열에 포함시킵니다. 이 경우 Invoke에서 호출하게 할 함수의 구문을 Invoke 메서드에 알려 주려면 MyDelegate를 호출하는 대리자 형식을 선언해야 합니다. 이 경우 해당 함수는 DisplayResponse라고 하며 Web Service 호출에서 반환된 문자열인 하나의 매개 변수만 갖고 있습니다. DisplayResponse가 label1 컨트롤의 적절한 스레드 내에서 호출되며 응용 프로그램의 컨트롤 텍스트를 설정하는 데는 문제가 없게 됩니다.

고급 문제

지금까지 살펴본 예제는 매우 간단한 것이었습니다. 이러한 예제에서는 Web Service 호출 성공과 같은 사항에 대해 많은 가정을 만들었고, 한 번에 하나의 호출만 하는 것으로 단순화되어 있습니다. 이제 여러 Web Service 호출이 있는 시나리오를 살펴보겠습니다. 이러한 호출에서 생성될 수 있는 오류를 처리하는 방법과 필요한 경우 호출을 취소할 수 있는 방법을 살펴보겠습니다.

asyncState 사용

BeginDelayedResponse 호출에 대한 마지막 매개 변수로 Nothing 외에 다른 것을 전달하는 예제를 살펴보겠습니다. 이것은 호출하는 경우 간단히 개체로만 선언되는 asyncState 매개 변수입니다. 이제 이 매개변수를 사용하여 여러 Web Service 호출을 만들 수 있으므로 응답을 해당하는 요청과 연결시킬 수 있습니다.

살펴보려는 시나리오는 DelayedResponse 웹 메서드에 대해 세 가지 다른 호출을 만드는 시나리오입니다. 그런 다음 이러한 호출 결과를 Windows 응용 프로그램의 세 가지 다른 레이블 컨트롤에 표시합니다. 첫 번째 호출 결과는 첫 번째 레이블에 표시하고, 두 번째 호출 결과는 두 번째 레이블에 표시하고, 세 번째 호출 결과는 세 번째 레이블에 표시해야 합니다. 각각의 Web Service 호출에 대해 동일한 콜백 함수를 사용하려고 합니다. 어떤 레이블이 어떤 호출과 연결되는지 확인하기 위해 레이블 개체를 asyncState 매개 변수에 전달합니다. 더 복잡하게 하기 위해 각 호출이 완료되는 데 걸리는 시간을 임의로 결정했습니다. 이 작업을 위한 코드는 다음과 같습니다.

Dim proxy As localhost.Service1
Private Delegate Sub LabelDelegate( _
    ByVal responseLabel As Label, _
    ByVal response As String)

Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button7.Click
    proxy = New localhost.Service1()
    ClearForm()
    Dim r As New Random()

    proxy.BeginDelayedResponse(r.Next(1, 10000), _
            New AsyncCallback(AddressOf Me.ServiceCallback), _
            Label1)
    proxy.BeginDelayedResponse(r.Next(1, 10000), _
            New AsyncCallback(AddressOf Me.ServiceCallback), _
            Label2)
    proxy.BeginDelayedResponse(r.Next(1, 10000), _
            New AsyncCallback(AddressOf Me.ServiceCallback), _
            Label3)
End Sub

Private Sub ServiceCallback(ByVal result As IAsyncResult)
    Dim response As String
    response = proxy.EndDelayedResponse(result)
    Dim responseLabel As Label = result.AsyncState
    responseLabel.Invoke( _
        New LabelDelegate(AddressOf Me.DisplayResponses), _
        New Object() {responseLabel, response})
End Sub

Private Sub DisplayResponses(ByVal responseLabel As Label, _
                             ByVal response As String)
    responseLabel.Text = response
    Form1.ActiveForm.Refresh()
End Sub

asyncState 매개 변수에 전달된 레이블 개체는 콜백으로 전달된 IAsyncResult 매개 변수를 통해 콜백 함수에서 사용할 수 있습니다. 또한 이전 예제의 대리자도 다른 매개 변수를 사용하도록 수정했습니다. 추가 매개 변수도 레이블이므로 대리자는 텍스트를 설정할 컨트롤을 알 수 있습니다.

종종 asyncState를 통해 단일 개체보다는 더 많은 정보를 전달하려고 할 것입니다. asyncState는 개체로만 선언되기 때문에 사용하려는 개체 배열이나 일부 복잡한 구조 같은 복합 정보를 전달하는 데에도 사용할 수 있습니다. 이 경우에는 하나의 프록시 개체만 사용했지만 일부 시나리오에서는 각 Web Service 호출마다 다른 프록시 개체를 가질 수 있습니다. 그런 경우에는 프록시 개체를 asyncState 데이터에 포함시키려고 할 수도 있습니다. Web Service 호출에 관련된 다른 데이터도 포함시킬 수 있습니다.

오류 파악

동기 Web Service 호출을 만드는 데 익숙한 경우 만들려는 원격 호출을 포함시키는 try...catch 블록을 통해 오류를 파악하는 데에도 익숙할 것입니다. 비동기 호출로 같은 작업을 수행하면 난해해 보일 것입니다. Try...catch 블록으로 BeginDelayedResponse 또는 EndDelayedResponse를 래핑해야 합니까? 두 개 모두 래핑해야할 수도 있습니다.

실제로 일반 SOAP 오류 및 전송 관련 오류의 경우 try...catch 블록으로 EndDelayedResponse 호출만 래핑해야 합니다. BeginDelayedResponse 호출에서는 즉시 반환하고 문제가 있는지 확인하기 위해 기다리지 않기 때문에 BeginDelayedResponse 호출에서 오류를 생성하지 않습니다. 콜백이 호출되거나 Wait 호출이 차단 해제되기를 기다리는 동안 오류가 임의로 발생하지 않습니다. 오류가 있는 경우 발생하는 사항은 IsCompleted 속성이 True로 설정되거나, WaitHandle을 트리거하거나, 콜백을 호출하거나 상관없이 사용 중인 메커니즘을 통해 완료가 트리거된다는 것입니다. 이는 실패했을 수 있는 사항에 대한 정보를 제공하고 오류가 트리거되는 EndDelayedResponse에 대한 호출을 만들 경우에만 해당합니다.

내 응용 프로그램의 오류 가능성에 대해 설명하기 위해 내 EndDelayedResponse 호출을 둘러싼 콜백 함수에 try...catch 블록을 추가했습니다. 오류에 따라 응답 텍스트를 수정했습니다.

Private Sub ServiceCallback(ByVal result As IAsyncResult)
    Dim response As String
    Try
        response = proxy.EndDelayedResponse(result)
    Catch e As Exception
        Response = "실패"
    End Try
    Dim responseLabel As Label = result.AsyncState
    responseLabel.Invoke( _
        New LabelDelegate(AddressOf Me.DisplayResponses), _
        New Object() {responseLabel, response})
End Sub

요청 중단

응용 프로그램에서 비동기 요청을 사용하는 장점 중 하나는 호출이 완료되는 동안 사용자 인터페이스를 잠그지 않아도 된다는 점입니다. 물론 응용 프로그램의 사용자가 응용 프로그램과 계속 상호 작용하도록 허용할 경우 포함시키려는 가장 일반적인 기능이 바로 아직 해결되지 않은 요청을 취소하기 위한 단추입니다. 특정 이유 때문에 Web Service 호출이 완료되는 데 시간이 많이 걸릴 경우 사용자에게 대기할 시간을 결정할 수 있는 옵션을 제공하는 것이 좋습니다.

요청을 중단하는 것은 간단합니다. 웹 참조 추가 옵션을 사용할 때 만들어진 프록시 클래스에서 사용 가능한 Abort 메서드를 사용합니다. 요청 중단에 대한 몇 가지 사항을 기억해야 합니다. Abort 메서드를 호출할 경우 아직 해결되지 않은 요청이 완료되기는 하지만 오류와 함께 완료됩니다. 즉, 콜백을 사용할 경우 아직 해결되지 않은 요청에 대해 콜백 함수가 계속 호출됩니다. EndInvoke 메서드를 호출하거나 이 경우에서처럼 래퍼 함수 EndDelayedResponse를 호출할 경우에는 기본 연결이 닫혔음을 알려주는 오류가 생성됩니다.

동기 호출을 만들기 위해 스레드 생성

비동기 호출에서 제공하는 많은 문제점을 해결하기 위해 사용할 수 있는 다른 옵션이 있습니다. 바로 스레드를 생성하고 동기 호출을 쉽게 코딩할 수 있게 스레드를 만드는 것입니다. 이것은 일부 시나리오에는 적용되지만, 이 방법에도 여러 문제점이 있음을 알아야 합니다.

무엇보다도 이것은 Web Service 호출 코드를 간단하게는 하지만, 적어도 스레드 간의 통신 및 관리를 하는 데 사용한 일부 코드처럼 복잡한 논리를 구현해야할 수도 있다는 것입니다. 많은 Web Service 호출을 할 경우 관리할 스레드로 시스템에 부담을 줄 수도 있습니다. 일반 클라이언트 응용 프로그램의 경우 이것이 대단한 사항은 아닐 수도 있지만, ASP.NET 페이지에서 호출할 경우 시스템을 동시에 사용하는 사용자 수를 고려해야 합니다. ASP.NET 페이지에서 Web Service 호출을 수행하는 두 개의 스레드를 추가하면 큰 부담은 아닌 것처럼 보이지만 200명의 사용자가 동시에 같은 페이지를 사용할 경우 어떤 일이 발생하겠습니까? 이제 400개의 새 스레드에 대해 언급하게 될 것이 분명합니다. 비동기 호출을 수행하기 위한 콜백 메커니즘에서는 콜백을 만들기 위해 추가 스레드를 사용하지만, 가능한한 콜백을 효율적으로 만들 뿐만 아니라 수 백개의 스레드를 동시에 실행하는 문제를 방지하기 위해 스레드 풀을 다시 사용합니다.

Web Service 호출을 만들기 위해 배경 스레드를 생성하는 것이 적당할 경우 대리자와 프로세스 스레드 풀을 사용하여 이러한 스레드를 생성하는 고려해야 합니다. 그런 다음 Web Service 콜백에 사용한 패러다임과 유사한 비동기 패러다임을 사용하고 스레드에서 컨트롤과 상호 작용하기 위해 함수 호출을 불러와서 이러한 메서드를 호출할 수 있습니다.

결론

Web Service 호출을 비동기로 만드는 것은 .NET Framework 응용 프로그램에서 HTTP를 통해 Web Service를 사용하기 위해 제공한 좀 더 유용한 기능 중 하나일 것입니다. 대부분의 실제 응용 프로그램에서는 이 기능을 사용하여 시간이 오래 걸릴 수 있는 네트워크 호출이 완료되는 동안 응용 프로그램을 차단하지 않고 Web Service를 효율적으로 호출하려고 할 것입니다. .NET Framework는 HTTP를 통해 비동기 Web Service 호출을 지원하는 방법에 있어서 융통성이 있고, 호출 완료 처리 방법을 결정하는 데 있어서 개발자에게 많은 제어권을 제공합니다.

 


저자 소개

Matt Powell은 MSDN Architectural Samples 팀의 일원으로 초기 SOAP Toolkit 1.0 개발에 참여했으며 Microsoft Press의 Running Microsoft Internet Information Server(Microsoft Internet Information Server 실행) 공동 저자이며 수 많은 기사를 잡지에 기고하고 있습니다.




최종 수정일: 2002년 11월 5일
페이지 맨 위로 페이지 맨 위로


Microsoft