소년포비의 세계정복!!

비 동기 웹 서비스 호출(Asynchronous WebService) 본문

프로그램 세상/C#

비 동기 웹 서비스 호출(Asynchronous WebService)

소년포비 2009. 10. 6. 06:09

『 비 동기 웹 서비스 호출』

 

.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]

public string HelloWorld(string name)

{

      //고의로 약 2초 정도 지연시간을 준다

System.Threading.Thread.Sleep(2000);

 

return "Hello " + name;

}


 
 

이렇게 웹 메서드가 만들어 지고 난 후 클라이언트 프로그램을 만들어 웹 참조(Web References)를 하도록 한다.

웹 서비스를 참조 하면 아래 그림처럼 클라이언트의 웹 참조 항목아래에 보면 References.cs 라는

클래스가 있다 (References.cs 파일은 모든 파일 표시를 해야 나타난다)

 

 

 

 

 

 

 

 

 

이 파일은 웹 서비스를 원격 호출 가능케 하는 Proxy 클래스인데,

파일을 열어 보면 우리가 작성한 웹 메서드인 HelloWorld 에 관련된 메서드가 총 3개 있음을 알 수 있다.

 

/// <remarks/>

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

public string HelloWorld(string name) {

    object[] results = this.Invoke("HelloWorld", new object[] {name});

    return ((string)(results[0]));

}

       

/// <remarks/>

public System.IAsyncResult BeginHelloWorld(string name, System.AsyncCallback callback, object asyncState) {

    return this.BeginInvoke("HelloWorld", new object[] {name}, callback, asyncState);

}

       

/// <remarks/>

public string EndHelloWorld(System.IAsyncResult asyncResult) {

    object[] results = this.EndInvoke(asyncResult);

    return ((string)(results[0]));

}

 

우리가 작성한 HelloWorld 이외에도 BeginHelloWorld, EndHelloWorld 메서드가 자동으로 추가되어 있다.

이 두 메서드가 바로 1.x 에서 비 동기 웹 서비스 호출을 위해 자동으로 생성되는 메서드 인 것이다.

 

클라이언트에서 비 동기로 웹 서비스를 호출하는 코드를 보자

 

//웹 서비스 객체

private localhost.Service1 proxy;

 

//비동기로 HelloWorld 호출

private void button1_Click(object sender, System.EventArgs e)

{

        this.proxy = new localhost.Service1();

        proxy.BeginHelloWorld("MKEX",new System.AsyncCallback(CallbackMethod),null);

}

 

public void 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 의 코드를 살펴 보자.

 

/// <remarks/>

public event HelloWorldCompletedEventHandler HelloWorldCompleted;

       

/// <remarks/>

 [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

public string HelloWorld(string name) {

    object[] results = this.Invoke("HelloWorld", new object[] {name});

    return ((string)(results[0]));

}

       

/// <remarks/>

public void HelloWorldAsync(string name) {

    this.HelloWorldAsync(name, null);

}

       

/// <remarks/>

public void HelloWorldAsync(string name, object userState) {

    if ((this.HelloWorldOperationCompleted == null)) {

        this.HelloWorldOperationCompleted = new System.Threading.SendOrPostCallback(this.OnHelloWorldOperationCompleted);

    }

    this.InvokeAsync("HelloWorld", new object[] {

                name}, this.HelloWorldOperationCompleted, userState);

}

       

private void OnHelloWorldOperationCompleted(object arg) {

    if ((this.HelloWorldCompleted != null)) {

        System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));

        this.HelloWorldCompleted(this, new HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));

    }

}

 

1.x Reference.cs 와 확연히 달라진 코드임을 알 수 있다.

1.x 에서의 BeginXXX, EndXXX 와 같은 메서드는 없어지고 대신 비 동기 완료를 통지 받기 위한 이벤트(HelloWorldCompletedEventHandler)

비 동기 웹 메서드 코드(HelloWorldAsync), 이벤트 호출 코드(OnHelloWorldOperationComplete) 자동으로 생성된 것을 볼 수 있다.

 

클라이언트에서 비 동기로 웹 서비스를 호출하는 코드를 보자

 

private void 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");

}

 

//비동기 웹 서비스 호출 완료시 수행되는 이벤트 메서드

public void 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");

 

 

여기에 주의사항이 있다.

 

이벤트는 한번만 등록되어야 한다

 

만일 윈폼 응용프로그램과 같이 웹 서비스 프록시 객체를 미리 생성하고 난 뒤 그 객체를 계속적으로 사용할 경우

위 처럼 웹 메서드를 호출할 때 마다 완료 이벤트를 등록하면 중복 등록되게 되는 것이다.

 

따라서 이런 경우라면, 반드시 프록시 객체의 생성하는 곳에서 각 웹 메서드에 해당하는 완료 이벤트를 미리 등록하고 난 뒤

실제 웹 메서드 호출할때는 별도로 등록하지 않도록 해야 한다.