Programming/.NET

웹서비스를 이용하면 SOAP(Simple Object Access Protocol)를 통해 이기종간에 XML통신을 통하여 필요한 정보를 전달할 수 있습니다.

 

웹서비스를 생성하려면 Add New Item 대화상자에서 Web Service(ASMX) 를 선택하고 'Add'버튼을 누릅니다.

 

 

 

웹 서비스를 추가하고 나면 asmx확장자의 파일이 하나 생성되는데 해당 cs파일의 내용은 대략 아래와 같거나 비슷할 것입니다.

 

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}

 

WebService 특성은 네임스페이스를 의미합니다. 예제에는 URL이 기재되어 있는데 URL이 들어간 특별한 이유는 없고 그냥 원하는 내용을 기입하면 됩니다. 중요한건 '유일한 값'이여야 한다는 것인데 대부분 URL을 사용하는 이유는 http://www.cliel.com/tmpnamespace/i 와 같이 기재하면 유일성을 가질 수 있기 때문입니다.(기재된 URL은 그냥 네임스페이스를 의미하는 '값'일뿐 실제 존재하는가는 중요하지 않습니다.)

 

참고로 WebService에는 Name과 Description 특성을 사용할 수도 있는데

 

[WebService(Namespace = "http://tempuri.org/", Name ="test")]

 

여기에는 각각 웹서비스의 이름과 설명을 담을 수 있습니다.

 

WebServiceBinding은 XML웹 서비스가 구현된 버전을 의미하며 WsiProfiles.BasicProfile1_1은 WS-I Basic Profile 1.0을 준수하고 있다는 것을 말해주고 있습니다.

 

하단의 주석처리된 부분은 AJAX 스크립트에 필요한 내용으로서 필요하다면 그냥 주석을 지우면 됩니다.

 

예제에서는 웹서비스 메소드로 HelloWorld 메소드가 구현되어 있는데 이 메소드에는 WebMethod라는 특성이 존재하며 해당 특성에는 다음과 같은 내용의 속성을 지정할 수 있습니다.

 

 BufferResponse

 이 속성을 true로 설정하면 웹서비스의 응답내용이 메모리에 저장되어 클라이언트에 전송됩니다.

 CacheDuration

 응답내용이 캐시처리되는 시간을 설정합니다. 기본값은 0인데 사용하지 않음을 의미합니다. 입력은 초단위이며 int형의 값을 받습니다.

 Description

 웹서비스 메소드의 설명부분입니다.

 EnableSession

 해당 메소드의 세션기능을 사용하고자 하는 경우 true로 설정합니다.

 TransactionOption

 이 속성값을 true로 설정하면 좀 복잡하지만 내부에 또다른 웹서비스를 호출하는 식으로 2개 이상의 웹서비스가 교차적으로 동작할때 도중 장애가 발생하면 각 처리과정이 롤백되도록 트랜잭션기능을 켤 수 있습니다.

 

위와같이 웹서비스를 만들고 나면 이제 클라이언트에서는 해당 웹서비스를 호출하여 원하는 정보를 얻을 수 있게 됩니다. 웹이든 응용이든 상관없이 또 다른 프로젝트를 하나 생성하여 위에서 만들어 놓은 웹서비스를 호출해 보도록 하겠습니다.

 

생성한 프로젝트의 Solution Explorer창에서 해당 프로젝트를 마우스 오른쪽 클릭하여 Add -> Service Reference 항목을 선택합니다.

 

 

 

Address에 접근가능한 웹서비스의 URL을 입력하고 'Go'버튼을 눌러줍니다. 그러면 해당 웹서비스에 존재하는 메소드를 표시하게 됩니다. 메소드가 확인되면 'OK'버튼을 눌러 프로젝트에 웹서비스항목을 추가합니다.

 

private void button2_Click(object sender, EventArgs e)
{
    ServiceReference.testSoapClient test = new ServiceReference.testSoapClient();
    label1.Text = test.HelloWorld();
}

 

지금 예제에서는 응용프로그램 프로젝트를 생성하고 버튼과 Label컨트롤을 배치한뒤 웹서비스를 위와같이 호출하였습니다. 보시는 바와 같이 웹서비스를 호출하는 방법은 아주 간단합니다.

 

이제 웹서비스가 구현된 곳으로 다시 돌아가 보겠습니다. 예제에서는 HelloWorld라는 메소드가 하나 존재했었는데 실제 웹서비스를 구현하다보면 같은 이름의 메소드를 여러개 만들어 이를 오버로드해야할 경우가 발생합니다.

 

[WebMethod]
public string HelloWorld()
{
    return "Hello World";
}

[WebMethod]
public string HelloWorld(string name)
{
    return "Your Name : " + name + "Hello World";
}

 

하지만 위와 같이 하는것만으로는 불가능하고 WebMethod특성에 MessageName속성을 추가하여 해당 속성값을 달리설정해야 합니다.

 

[WebMethod(MessageName ="Hello1")]
public string HelloWorld()
{
    return "Hello World";
}

[WebMethod(MessageName ="Hello2")]
public string HelloWorld(string name)
{
    return "Your Name : " + name + "Hello World";
}

 

이때 하나더 고려해야할 부분이 있습니다. 위와같이 MessageName속성을 추가하고 나면 WebServiceBinding에 표시되어 있는 WS-I Basic Profile 1.0 명세를 제거해야 합니다. 해당 명세는 웹메소드의 오버로드를 허용하지 않기 때문입니다.

 

[WebServiceBinding(ConformsTo = WsiProfiles.None)]

 

웹서비스는 기본적으로 내부의 데이터를 외부에 공개하기 위한 용도로 사용됩니다. 하지만 그렇다 하더라도 특정 클라이언트에 해당하는 사용자만을 대상으로 웹서비스를 공개해야 하는 경우가 생길 수 있습니다. 예를 들어 접근해 오는 클라이언트는 자신만의 아이디와 암호를 사용해 웹서비스를 사용하도록 할때 아이디와 암호를 전달하여 클라이언트의 인증여부를 처리하는 것입니다.

 

이런 경우 우리는 SOAP Header를 사용하여 웹서비스를 구현할 수 있습니다. 우선 SOAP Header를 구현하기 위한 클래스를 다음과 같이 생성합니다.

 

public class tmpSoapHeader : System.Web.Services.Protocols.SoapHeader
{
    public string user_name;
    public string user_password;
}

 

참고로 해당 클래스는 웹서비스영역과 같은 위치에 있어야 하며 SoapHeader클래스를 상속받아야 합니다. 이제 위에서 작성한 클래스는 웹서비스안에 인스턴스로 만들고 SoapHeader특성을 추가하여 해당 인스턴스이름을 전달하도록 합니다. 그러면 실제 코드안에서 인스턴스를 통해 원하는 속성에 접근이 가능합니다.

 

public class WebService : System.Web.Services.WebService
{
    public tmpSoapHeader tsh;

    [WebMethod]
    [SoapHeader("tsh")]
    public string HelloWorld()
    {
        if (tsh == null)
            return "사용자 인증 실패";

        if (tsh.user_name == "administrator" && tsh.user_password == "1234")
            return "사용자 인증 성공";
        else
            return "사용자 인증 실패";
    }
}

public class tmpSoapHeader : System.Web.Services.Protocols.SoapHeader
{
    public string user_name;
    public string user_password;
}

 

클라이언트에서는 기존에 참조한 웹서비스의 형태가 변경되었으므로 그대로 사용할 수 없고 대신 해당 웹서비스를 마우스 오른쪽 클릭하여 'Update Service Reference'를 선택해 웹서비스기능을 업데이트해야 합니다.

 

그러면 웹서비스에서 추가된 Header클래스를 통해 필요한 정보를 대입하고 웹메소드 호출시 해당 헤더정보를 전달할 수 있습니다.

 

private void button2_Click(object sender, EventArgs e)
{
    ServiceReference.tmpSoapHeader tsh = new ServiceReference.tmpSoapHeader();
    ServiceReference.testSoapClient test = new ServiceReference.testSoapClient();

    tsh.user_name = "administrator";
    tsh.user_password = "1234";

    label1.Text = test.HelloWorld(tsh);
}

 

참고로 해당 웹서비스를 비동기로 호출하려고 시도하면 비동기에 필요한 몇몇 메소드가 존재하지 않음을 알 수 있습니다. 이는 웹서비스를 참조할때 일반운영모드로 웹서비스를 참조했기 때문입니다. 웹서비스의 웹메소드를 비동기로 처리하려면 최초참조시 Add Service Reference 대화상자에서 Advenced... 버튼을 눌러 Generate asynchronous operations를 선택하고 참조해야 합니다.

 

ServiceReference.tmpSoapHeader tsh = new ServiceReference.tmpSoapHeader();
ServiceReference.testSoapClient test = new ServiceReference.testSoapClient(); tsh.user_name = "administrator";
tsh.user_password = "1234";

IAsyncResult ar = test.BeginHelloWorld(tsh, null, null);

while (!ar.IsCompleted)
    label1.Text = "대기중...";

label1.Text = test.EndHelloWorld(ar);

 

웹서비스를 비동기로 호출할 수 있도록 참조하고 나면 위와 같이 웹메소드를 비동기로 호출할 수 있게 됩니다.

 

비동기 호출에서는 자동으로 생성되는 Begin-과 End-메소드를 사용하며 IAsyncResult 개체를 통해 대기상태를 판단할 수 있습니다. 이 개체의 IsCompleted속성이 true라면 EndHelloWorld메소드를 호출하여 즉시 메소드수행 결과를 받아올 수 있습니다.

'Programming > .NET' 카테고리의 다른 글

[C#] 이니셜라이저(initializer)  (0) 2016.10.11
[ASP.NET] 설정파일 - 1  (0) 2016.10.04
[ASP.NET] 웹서비스(Web Service)  (0) 2016.09.27
[ASP.NET] URL 매핑 (URL 라우팅)  (0) 2016.09.21
[ASP.NET] TreeView  (0) 2016.09.13
[ASP.NET] WCF - 2  (0) 2016.09.07
0 0