웹 서비스의 비동기 호출 방법에 대해 정리한 글입니다
닷넷 1.x 기반의 비동기 웹 서비스 호출 방법을 알아 본 뒤 2.0 의 이벤트 기반 비동기 호출에 대해 알아 봅니다
아래의 글을 참고해 주세요
———————————————————————————————————
**『 비 동기 웹 서비스 호출』**
** **
.NET Framework 는 파일에 대한 I/O 및 네트워크 통신 등에 비 동기 호출 메커니즘을 지원해 왔다.
또한 ADO.NET 2.0 에서는 데이터베이스 관련 작업에도 비 동기 호출을 지원하기 시작했다.
물론 ASP.NET XML WebService 에서도 비 동기 호출을 지원한다.
이번 글에서는 웹 서비스에서의 비 동기 호출 방법에 대해 알아보도록 한다
우선 알아두어야 할 것이 비 동기 웹 서비스 호출이 .NET Framework 1.x 와 2.0 의 차이점이 있다는 것이다.
즉 .NET Framework 2.0에서는 기존의 1.x 에서의 비 동기 호출 보다 직관적이고 이벤트 지향적으로 변경되었다.
**1. .NET Framework 1.x ****에서의 웹 서비스 비 동기 호출**
****
우선 예전 방식(1.x) 에서의 비 동기 호출 방법에 대해 알아보자.
아래와 같이 간단한 웹 서비스의 HelloWorld 웹 메서드를 만들어 보자.
[WebMethod]
publicstring HelloWorld(string name)
{
//고의로 약 2초 정도 지연시간을 준다
System.Threading.Thread.Sleep(2000);
return “Hello ” + name;
}
|
이렇게 웹 메서드가 만들어 지고 난 후 클라이언트 프로그램을 만들어 웹 참조(Web References)를 하도록 한다.
웹 서비스를 참조 하면 아래 그림처럼 클라이언트의 웹 참조 항목아래에 보면 References.cs라는
클래스가 있다 (References.cs 파일은 ‘모든 파일 표시’를 해야 나타난다)
이 파일은 웹 서비스를 원격 호출 가능케 하는 Proxy 클래스인데,
파일을 열어 보면 우리가 작성한 웹 메서드인 HelloWorld 에 관련된 메서드가 총 3개 있음을 알 수 있다.
///
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(“http://tempuri.org/Hello
World”, RequestNamespace=”http://tempuri.org/”, ResponseNamespace=”http://tempuri.org/
“, Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
publicstring**HelloWorld**(string name) {
object[] results = this.Invoke(“HelloWorld”, newobject[] {name});
return ((string)(results[0]));
}
///
public System.IAsyncResult **BeginHelloWorld**(string name, System.AsyncCallback callback
, object asyncState) {
returnthis.BeginInvoke(“HelloWorld”, newobject[] {name}, callback, asyncState);
}
///
publicstring**EndHelloWorld**(System.IAsyncResult asyncResult) {
object[] results = this.EndInvoke(asyncResult);
return ((string)(results[0]));
}
|
우리가 작성한 HelloWorld 이외에도 **BeginHelloWorld**, **EndHelloWorld**메서드가 자동으로 추가되어 있다.
이 두 메서드가 바로 1.x 에서 비 동기 웹 서비스 호출을 위해 자동으로 생성되는 메서드 인 것이다.
클라이언트에서 비 동기로 웹 서비스를 호출하는 코드를 보자
//웹 서비스 객체
private localhost.Service1 proxy;
//비동기로 HelloWorld 호출
privatevoid button1_Click(object sender, System.EventArgs e)
{
this.proxy = new localhost.Service1();
proxy.**BeginHelloWorld**(“MKEX”,new System.AsyncCallback(CallbackMethod),null);
}
publicvoid CallbackMethod(IAsyncResult ar)
{
string result = proxy.**EndHelloWorld**(ar);
MessageBox.Show(result);
}
|
HelloWorld 웹 메서드를 비 동기로 호출하기 위해서는 **BeginHelloWorld**을 호출해야 한다.
이때 매개변수를 전달하고 비 동기 작업 완료 시 호출 될 Callback 메서드를 지정한다.
Callback 메서드에서는 다시 **EndHelloWorld**를 호출하여 비 동기 작업 상태 및 참조 매개변수를 넘겨준다(있을
경우)
이 샘플 프로젝트를 수행해 보면 웹 메서드를 호출하고 난 뒤 기다리는 시간 동안 블로킹이 되지 않고 다른 작업을
수행할 수 있음을 알 수 있다. 즉 비 동기로 웹 서비스가 호출되는 것이다
**2. .NET Framework 2.0 ****에서의 웹 서비스 비 동기 호출**
****
이제 2.0에서의 비 동기 웹 서비스 호출 방법에 대해 알아보자.
위의 샘플과 동일한 웹 서비스를 만들고 클라이언트에 웹 참조를 한 뒤 **Reference.cs**의 코드를 살펴 보자.
///
publiceventHelloWorldCompletedEventHandler**HelloWorldCompleted**;
///
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(“http://tempuri.org/HelloWo
rld”, RequestNamespace=“http://tempuri.org/”, ResponseNamespace=“http://tempuri.org/”,
Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
publicstring**HelloWorld**(string name) {
object[] results = this.Invoke(“HelloWorld”, newobject[] {name});
return ((string)(results[0]));
}
///
publicvoid**HelloWorldAsync**(string name) {
this.HelloWorldAsync(name, null);
}
///
publicvoid**HelloWorldAsync**(string name, object userState) {
if ((this.HelloWorldOperationCompleted == null)) {
this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);
}
this.InvokeAsync(“HelloWorld”, newobject[] {
name}, this.HelloWorldOperationCompleted, userState);
}
privatevoid**OnHelloWorldOperationCompleted**(object arg) {
if ((this.HelloWorldCompleted != null)) {
System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
this.HelloWorldCompleted(this, newHelloWorldCompletedEventArgs(invokeArgs.
Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
}
}
|
1.x 의 Reference.cs 와 확연히 달라진 코드임을 알 수 있다.
즉 1.x 에서의 BeginXXX, EndXXX 와 같은 메서드는 없어지고 대신 비 동기 완료를 통지 받기 위한 이벤트(**HelloWorldCompletedEventHandler**)와비 동기 웹 메서드코드(**HelloWorldAsync**), 이벤트 호출 코드(**OnHelloWorldOperationComplete**)자동으로 생성된 것을 볼 수 있다.
클라이언트에서 비 동기로 웹 서비스를 호출하는 코드를 보자
privatevoid button3_Click(object sender, EventArgs e)
{
//웹 서비스 객체
localhost.Service1 proxy = new WindowsApplication4.localhost.Service1();
//비동기 완료시 통지받을 이벤트 핸들러 등록
proxy.HelloWorldCompleted +=
new WindowsApplication4.localhost.HelloWorldCompletedEventHandler
(proxy_HelloWorldCompleted);
//비동기로 HelloWorld 호출
proxy.HelloWorldAsync(“MKEX”);
}
//비동기 웹 서비스 호출 완료시 수행되는 이벤트 메서드
publicvoid proxy_HelloWorldCompleted(object sender,localhost.
HelloWorldCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
|
1.x 와는 달리 보다 직관적이고 이벤트 지향적으로 변경되었음을 알 수 있다.
비 동기 작업 완료시 통지받을 이벤트를 등록하고,비동기 웹 메서드를 호출하기 위해
XXXAsync 메서드를 호출한다. 이 이벤트 핸들러 메서드에서는 전달된
매개변수(HelloWorldCompletedEventArgs)를 통해 웹 메서드의 반환값을 가져올 수 있게
되는 것이다.
※ 주의사항
앞서 샘플 코드에서는 비 동기 작업 완료 통지를 받기 위한 이벤트를 웹 메서드 호출할 때
등록했었는데,
아래처럼..
//비동기 완료시 통지받을 이벤트 핸들러 등록
proxy.HelloWorldCompleted += new WindowsApplication4.localhost.HelloWorldCompletedEventHandler(proxy_HelloWorldCompleted);
//비동기로 HelloWorld 호출
proxy.HelloWorldAsync(“MKEX”);
|
여기에 주의사항이 있다.
“이벤트는 한번만 등록되어야 한다*”***
만일 윈폼 응용프로그램과 같이 웹 서비스 프록시 객체를 미리 생성하고 난 뒤 그 객체를
계속적으로 사용할 경우
위 처럼 웹 메서드를 호출할 때 마다 완료 이벤트를 등록하면 중복 등록되게 되는 것이다.
따라서 이런 경우라면, 반드시 프록시 객체의 생성하는 곳에서 각 웹 메서드에 해당하는
완료 이벤트를 미리 등록하고 난 뒤실제 웹 메서드 호출할때는 별도로 등록하지 않도록
해야 한다.
|