ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WCF] 3. 이중계약으로 콜백기능 구현하기
    .NET/개념 및 유용한 팁 2015. 4. 5. 16:35
    반응형
    WCF는 .NET Core 및 새로운 .NET 에서 소개하는 gRPC로 대체되었습니다. 유지보수 외 신규 개발에선 추천하지 않습니다.
    참조 : https://docs.microsoft.com/ko-kr/aspnet/core/grpc/why-migrate-wcf-to-dotnet-grpc?view=aspnetcore-5.0#grpc-as-a-migration-path-for-wcf-to-net-core-and-net-5

     

    HelloWorld 예제에선 WCF 클라이언트가 계약으로 구성된 서비스 클라이언트 객체를 통해 서비스를 호출함으로서 WCF 기능을 사용하였다. 그렇다면 반대로 서비스에서 브로드캐스팅 목적으로 클라이언트에게 전파해야 할 필요성이 있을땐 어떻게 해야할까?

    WCF 시스템 바인딩에서는 이를 해결하기위한 '이중 계약' 바인딩을 제공한다. 이중계약이 가능한 바인딩은 아래와 같다.

     

    - WSDualHttpBinding

    - NetTcpBinding

    - NetNamedPipeBinding

    - NetPeerTcpBinding

    https://msdn.microsoft.com/ko-kr/library/vstudio/ms731092(v=vs.100).aspx 에서 더 확인할 수 있다.

     

    이중에서 WSDualHttpBinding을 통해 이중계약을 구성하여 서버가 클라이언트에게 직접 메시지를 남기는 프로그램을 제작해 보도록 하겠다.

     

    [Service 프로그램의 IWCFService.cs]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ServiceModel;
    
    namespace WCF_Helloworld_Service.Services
    {
        interface IWCFCallback // 콜백 인터페이스
        {
            [OperationContract(IsOneWay=true)]
            void OnCallback(string serverMsg); // 클라이언트에서 구현한다.
        }
    
        [ServiceContract(CallbackContract=typeof(IWCFCallback))]
        interface IWCFService // 계약(Contract) 원형
        {
            [OperationContract]
            string sayHi();
            
        }
    
        class WCFService : IWCFService // 구현된 계약(Contract)
        {
            public static Dictionary<string, OperationContext> clients = new Dictionary<string, OperationContext>();
            public string sayHi() 
            {
                clients[OperationContext.Current.SessionId] = OperationContext.Current;
                return "Hello WCF!";
            }
        }
    
    }
    

    기존 HelloWorld에서 IWCFCallback 인터페이스가 새로 선언되었다. 그리고 IWCFService의 ServiceContract 속성에서 CallbackContract를 해당 인터페이스 타입으로 선언해주었다. 그리고 WCFService 클래스에 static 형으로 clients 라는 이름의 Dictionary를 생성하였다. 이는 서비스에서 sayHi를 호출 중인 클라이언트를 의미하는OperationContext.Current 를 저장하기 위함으로서, 서비스에서 클라이언트로 메시지 전달이 필요로 할때, 해당 Dictionary를 통해 연결되어있는 클라이언트에 메시지를 전달할 것이다. 이 것으로 계약(Contract) 부분의 구성은 끝이다.

    (IsOneWay는 메소드에 return 이 있는지 여부를 설정하는 것으로 생략해도 무방하다.)

     

    다음으로 바인딩(Binding) 부분이다.

     

    [Service 프로그램의 Program.cs]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    
    using WCF_Helloworld_Service.Services;
    
    namespace WCF_Helloworld_Service
    {
        class Program
        {
            static void Main(string[] args)
            {
                ServiceHost host = new ServiceHost(typeof(WCFService)); // 클라이언트가 서비스에 접근하게 할 Base 주소
                host.AddServiceEndpoint(
                    typeof(IWCFService),
                    new WSDualHttpBinding(), // http 기반 바인딩
                    new Uri("http://localhost/wcf/"));// client에선 해당 서비스를 http://localhost/wcf/ 에서 가져오게된다.
                host.Description.Behaviors.Add(new ServiceMetadataBehavior() { 
                    HttpGetEnabled = true, 
                    HttpGetUrl = new Uri("http://localhost/wcf/") }); // 이게 없으면 Visual Studio 에서 서비스 참조 추가 기능사용이 안된다.
                host.Open();
                for (; ; )
                {
                    var readStr = Console.ReadLine(); // 서비스 콘솔에서 글자를 입력받는다.
                    foreach (var client in WCFService.clients)
                    {
                        client.Value.GetCallbackChannel().OnCallback(readStr); // 입력받은 글자를 클라이언트에 전달한다.
                    }
                }
            }
        }
    }
    
    

    HttpBasicBinding 부분에서 WSDualHttpBinding으로 변경되었다. WSDualHttpBinding 도 주소체계는 http 이기때문에 기존 주소대로 사용한다. 이밖에도 서비스 종점 선언 부분과 ServiceMetaDataBehavior 부분이 HelloWorld와 차이점이 있는데 이는 소스 정리 및 서비스 참조 추가 기능 부분 확인을 위한 수정일 뿐, 이중계약과는 무관하다.

    서비스 Open 한 후 For문을 무한으로 돌리는데 내부를 보면 문자열을 읽을때마다 계약(Contract) 부분에서 콜백으로 선언했던 OnCallback 메소드를 실행하고 있다. 이 부분이 수행되면 연결되어 있는 클라이언트에서 파라메터로 받은 readStr을 이용해 어떤 작업을 수행하게 된다.

    이상이 없다면 검은 콘솔화면의 프로그램이 실행될 것이다.

    이로서 서비스 부분은 끝났다. 이번엔 클라이언트 프로젝트를 열도록 하자. 기존의 HelloWorld 클라이언트를 수정하고자 한다면 서비스 참조 레퍼런스에 마우스 오른쪽 버튼을 눌러 '서비스 참조 업데이트(A)'를 실행하면 자동적으로 app.config가 수정된다.
    (이때 반드시 서비스는 실행되어 있어야 한다.)

     


    [그림 1] 서비스 참조 업데이트

     

     

    [Client의 자동수정된 app.config]

    <!--?xml version="1.0" encoding="utf-8" ?-->
    <configuration>
        <startup> 
            <supportedruntime version="v4.0" sku=".NETFramework,Version=v4.5">
        </supportedruntime></startup>
        <system.servicemodel>
            <bindings>
                <wsdualhttpbinding>
                    <binding name="WSDualHttpBinding_IWCFService">
                </binding></wsdualhttpbinding>
            </bindings>
            <client>
                <endpoint name="WSDualHttpBinding_IWCFService" bindingconfiguration="WSDualHttpBinding_IWCFService" address="http://localhost/wcf/" binding="wsDualHttpBinding" contract="ServiceReference1.IWCFService">
                    <identity>
                        <userprincipalname value="DDOCHEA-PC\ddochea"> <!-- 해당 부분은 PC 환경에 따라 달라질 수 있다. -->
                    </userprincipalname></identity>
                </endpoint>
            </client>
        </system.servicemodel>
    </configuration>

    클라이언트 소스는 아래와 같이 수정하도록 하자.

    [Client 프로그램의 Program.cs]

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Channels;
    using WCF_Helloworld_Client.ServiceReference1;
    
    namespace WCF_Helloworld_Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                WCFServiceClient client = new WCFServiceClient(new InstanceContext(new CallbackClass()));
                Console.WriteLine(client.sayHi());
                Console.Read();
            }
        }
    
        ///
        /// 서비스 콜백 인터페이스를 구현한 콜백 클래스
        /// 
        class CallbackClass : ServiceReference1.IWCFServiceCallback
        {
            public void OnCallback(string serverMsg)
            {
                Console.WriteLine(serverMsg); // 서비스에서 받은 글자를 콘솔로 표시한다.
            }
        }
    }
    

    이로서 모든 소스 작업이 완료되었다. 이제 클라이언트를 실행하여 서비스 연결을 기다려보자. 서비스가 연결되면 콘솔화면에 "Hello WCF!"가 나타나게 될 것이다.

     

    [그림 2] 완성된 프로그램 실행결과

     

    서버에서 아무 문자열이나 입력해보자. 이상이 없다면 클라이언트에서도 동일한 문자열이 표시될 것이다.

     

    [그림 3] 서비스에서 입력한 문자열이 클라이언트에 표시되는 모습

     

     

    이상으로 이중계약 바인딩을 통한 콜백기능 구현을 연습해보았다.

     

     

     

    소스 :

    WCF_Example.zip
    다운로드

     

     

     

    반응형

    댓글

Designed by Tistory.