다음을 통해 공유


방법: 검색 프록시 구현

이 항목에서는 검색 프록시를 구현하는 방법에 대해 설명합니다. WCF(Windows Communication Foundation)의 검색 기능에 대한 자세한 내용은 WCF Discovery 개요를 참조하십시오. 검색 프록시는 DiscoveryProxy 추상 클래스를 확장하는 클래스를 만들어 구현할 수 있습니다. 이 샘플에서는 많은 다른 지원 클래스가 정의되고 사용됩니다. 이러한 클래스에는 OnResolveAsyncResult, OnFindAsyncResultAsyncResult가 포함됩니다. 이러한 클래스는 IAsyncResult 인터페이스를 구현합니다. IAsyncResult에 대한 자세한 내용은 System.IAsyncResult 인터페이스를 참조하십시오.

이 항목에서는 검색 프록시 구현을 크게 다음 세 부분으로 나누어서 설명합니다.

  • 데이터 저장소를 포함하고 DiscoveryProxy 추상 클래스를 확장하는 클래스 정의

  • AsyncResult 도우미 클래스 구현

  • 검색 프록시 호스팅

새 콘솔 응용 프로그램 프로젝트를 만들려면

  1. Visual Studio 2010을 시작합니다.

  2. 새 콘솔 응용 프로그램 프로젝트를 만듭니다. 프로젝트 이름을 DiscoveryProxy로 지정하고 솔루션 이름을 DiscoveryProxyExample로 지정합니다.

  3. 프로젝트에 대한 다음 참조를 추가합니다.

    1. System.ServiceModel.dll

    2. System.Servicemodel.Discovery.dll

    Dd456787.Caution(ko-kr,VS.100).gif주의:
    이러한 어셈블리는 4.0 이상 버전이어야 합니다.

ProxyDiscoveryService 클래스를 구현하려면

  1. 프로젝트에 새 코드 파일을 추가하고 이름을 DiscoveryProxy.cs로 지정합니다.

  2. DiscoveryProxy.cs에 다음 using 문을 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.ServiceModel.Discovery;
    using System.Xml;
    
  3. DiscoveryProxy에서 DiscoveryProxyService를 파생시킵니다. 다음 예제와 같이 이 클래스에 ServiceBehavior 특성을 적용합니다.

    // Implement DiscoveryProxy by extending the DiscoveryProxy class and overriding the abstract methods
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class DiscoveryProxyService : DiscoveryProxy
    {
    }
    
  4. DiscoveryProxy 클래스 내에서 등록된 서비스를 저장할 사전을 정의합니다.

    // Repository to store EndpointDiscoveryMetadata. 
    Dictionary<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;
    
  5. 사전을 초기화하는 생성자를 정의합니다.

    public DiscoveryProxyService()
            {
                this.onlineServices = new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>();
            }
    

검색 프록시 캐시를 업데이트하는 데 사용되는 메서드를 정의하려면

  1. AddOnlineservice 메서드를 구현하여 캐시에 서비스를 추가합니다. 이 메서드는 프록시가 알림 메시지를 받을 때마다 호출됩니다.

    void AddOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata)
            {
                lock (this.onlineServices)
                {
                    this.onlineServices[endpointDiscoveryMetadata.Address] = endpointDiscoveryMetadata;                
                }
    
                PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Adding");
            }
    
  2. 캐시에서 서비스를 제거하는 데 사용되는 RemoveOnlineService 메서드를 구현합니다.

    void RemoveOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata)
            {
                if (endpointDiscoveryMetadata != null)
                {
                    lock (this.onlineServices)
                    {
                        this.onlineServices.Remove(endpointDiscoveryMetadata.Address);                    
                    }
    
                    PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Removing");
                }    
            }
    
  3. 서비스와 사전의 서비스를 일치시킬 MatchFromOnlineService 메서드를 구현합니다.

        void MatchFromOnlineService(FindRequestContext findRequestContext)
                {
                    lock (this.onlineServices)
                    {
                        foreach (EndpointDiscoveryMetadata endpointDiscoveryMetadata in this.onlineServices.Values)
                        {
                            if (findRequestContext.Criteria.IsMatch(endpointDiscoveryMetadata))
                            {
                                findRequestContext.AddMatchingEndpoint(endpointDiscoveryMetadata);
                            }
                        }
                    }
                }
    
        EndpointDiscoveryMetadata MatchFromOnlineService(ResolveCriteria criteria)
                {
                    EndpointDiscoveryMetadata matchingEndpoint = null;
                    lock (this.onlineServices)
                    {
                        foreach (EndpointDiscoveryMetadata endpointDiscoveryMetadata in this.onlineServices.Values)
                        {
                            if (criteria.Address == endpointDiscoveryMetadata.Address)
                            {
                                matchingEndpoint = endpointDiscoveryMetadata;
                            }
                        }
                    }
                    return matchingEndpoint;
                }
    
  4. 검색 프록시가 수행하는 작업을 콘솔에 텍스트로 출력하는 PrintDiscoveryMetadata 메서드를 구현합니다.

    void PrintDiscoveryMetadata(EndpointDiscoveryMetadata endpointDiscoveryMetadata, string verb)
            {
                Console.WriteLine("\n**** " + verb + " service of the following type from cache. ");
                foreach (XmlQualifiedName contractName in endpointDiscoveryMetadata.ContractTypeNames)
                {
                    Console.WriteLine("** " + contractName.ToString());
                    break;
                }
                Console.WriteLine("**** Operation Completed");
            }
    
  5. DiscoveryProxyService에 다음 AsyncResult 클래스를 추가합니다. 이러한 클래스는 다양한 비동기 작업 결과를 구별하는 데 사용합니다.

    sealed class OnOnlineAnnouncementAsyncResult : AsyncResult
            {
                public OnOnlineAnnouncementAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
    
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnOnlineAnnouncementAsyncResult>(result);
                }
            }
    
            sealed class OnOfflineAnnouncementAsyncResult : AsyncResult
            {
                public OnOfflineAnnouncementAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
    
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnOfflineAnnouncementAsyncResult>(result);
                }
            }
    
            sealed class OnFindAsyncResult : AsyncResult
            {
                public OnFindAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
    
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnFindAsyncResult>(result);
                }
            }
    
            sealed class OnResolveAsyncResult : AsyncResult
            {
                EndpointDiscoveryMetadata matchingEndpoint;
    
                public OnResolveAsyncResult(EndpointDiscoveryMetadata matchingEndpoint, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.matchingEndpoint = matchingEndpoint;
                    this.Complete(true);
                }
    
                public static EndpointDiscoveryMetadata End(IAsyncResult result)
                {
                    OnResolveAsyncResult thisPtr = AsyncResult.End<OnResolveAsyncResult>(result);
                    return thisPtr.matchingEndpoint;
                }
            }
    

검색 프록시 기능을 구현하는 메서드를 정의하려면

  1. OnBeginOnlineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 온라인 알림 메시지를 받을 때 호출됩니다.

    // OnBeginOnlineAnnouncement method is called when a Hello message is received by the Proxy
            protected override IAsyncResult OnBeginOnlineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
            {        
                this.AddOnlineService(endpointDiscoveryMetadata);
                return new OnOnlineAnnouncementAsyncResult(callback, state);
            }
    
  2. OnEndOnlineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 알림 메시지 처리를 완료할 때 호출됩니다.

    protected override void OnEndOnlineAnnouncement(IAsyncResult result)
            {
                OnOnlineAnnouncementAsyncResult.End(result);
            }
    
  3. OnBeginOfflineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 오프라인 알림 메시지를 받을 때 호출됩니다.

    // OnBeginOfflineAnnouncement method is called when a Bye message is received by the Proxy
            protected override IAsyncResult OnBeginOfflineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
            {
                this.RemoveOnlineService(endpointDiscoveryMetadata);
                return new OnOfflineAnnouncementAsyncResult(callback, state);
            }
    
  4. OnEndOfflineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 오프라인 알림 메시지 처리를 완료할 때 호출됩니다.

    protected override void OnEndOfflineAnnouncement(IAsyncResult result)
            {
                OnOfflineAnnouncementAsyncResult.End(result);
            }
    
  5. OnBeginFind 메서드를 재정의합니다. 이 메서드는 검색 프록시가 찾기 요청을 받을 때 호출됩니다.

    // OnBeginFind method is called when a Probe request message is received by the Proxy
            protected override IAsyncResult OnBeginFind(FindRequestContext findRequestContext, AsyncCallback callback, object state)
            {
                this.MatchFromOnlineService(findRequestContext);
                return new OnFindAsyncResult(callback, state);
            }
    protected override IAsyncResult OnBeginFind(FindRequest findRequest, AsyncCallback callback, object state)
    {
        Collection<EndpointDiscoveryMetadata> matchingEndpoints = MatchFromCache(findRequest.Criteria);
        return new OnFindAsyncResult(
                    matchingEndpoints,
                    callback,
                    state);
    }
    
  6. OnEndFind 메서드를 재정의합니다. 이 메서드는 검색 프록시가 찾기 요청 처리를 완료할 때 호출됩니다.

    protected override void OnEndFind(IAsyncResult result)
            {
                OnFindAsyncResult.End(result);
            }
    
  7. OnBeginResolve 메서드를 재정의합니다. 이 메서드는 검색 프록시가 확인 메시지를 받을 때 호출됩니다.

    // OnBeginFind method is called when a Resolve request message is received by the Proxy
            protected override IAsyncResult OnBeginResolve(ResolveCriteria resolveCriteria, AsyncCallback callback, object state)
            {
                return new OnResolveAsyncResult(this.MatchFromOnlineService(resolveCriteria), callback, state);
            }
    protected override IAsyncResult OnBeginResolve(ResolveRequest resolveRequest, AsyncCallback callback, object state)
    {
        return new OnResolveAsyncResult(
            this.proxy.MatchFromOnlineService(resolveRequest.Criteria),
            callback,
            state);
    }
    
  8. OnEndResolve 메서드를 재정의합니다. 이 메서드는 검색 프록시가 확인 메시지 처리를 완료할 때 호출됩니다.

            protected override EndpointDiscoveryMetadata OnEndResolve(IAsyncResult result)
            {
                return OnResolveAsyncResult.End(result);
            }
    

OnBegin.. / OnEnd.. 메서드는 후속 검색 작업에 대한 논리를 제공합니다. 예를 들어 OnBeginFindOnEndFind 메서드는 검색 프록시에 대한 찾기 논리를 구현합니다. 검색 프록시가 프로브 메시지를 받으면 클라이언트에 응답을 보내기 위해 이러한 메서드가 실행됩니다. 찾기 논리는 원하는 대로 수정할 수 있습니다. 예를 들어 찾기 작업의 일부로 알고리즘 또는 응용 프로그램별 XML 메타데이터 구문 분석을 통해 사용자 지정 범위 일치를 통합할 수 있습니다.

AsyncResult 클래스를 구현하려면

  1. 다양한 비동기 결과 클래스를 파생시키는 데 사용되는 추상 기본 클래스 AsyncResult를 정의합니다.

  2. AsyncResult.cs라는 새 코드 파일을 만듭니다.

  3. AsyncResult.cs에 다음 using 문을 추가합니다.

    using System;
    using System.Threading;
    
  4. 다음 AsyncResult 클래스를 추가합니다.

    abstract class AsyncResult : IAsyncResult
        {
            AsyncCallback callback;
            bool completedSynchronously;
            bool endCalled;
            Exception exception;
            bool isCompleted;
            ManualResetEvent manualResetEvent;
            object state;
            object thisLock;
    
            protected AsyncResult(AsyncCallback callback, object state)
            {
                this.callback = callback;
                this.state = state;
                this.thisLock = new object();
            }
    
            public object AsyncState
            {
                get
                {
                    return state;
                }
            }
    
            public WaitHandle AsyncWaitHandle
            {
                get
                {
                    if (manualResetEvent != null)
                    {
                        return manualResetEvent;
                    }
                    lock (ThisLock)
                    {
                        if (manualResetEvent == null)
                        {
                            manualResetEvent = new ManualResetEvent(isCompleted);
                        }
                    }
                    return manualResetEvent;
                }
            }
    
            public bool CompletedSynchronously
            {
                get
                {
                    return completedSynchronously;
                }
            }
    
            public bool IsCompleted
            {
                get
                {
                    return isCompleted;
                }
            }
    
            object ThisLock
            {
                get
                {
                    return this.thisLock;
                }
            }
    
            protected static TAsyncResult End<TAsyncResult>(IAsyncResult result)
                where TAsyncResult : AsyncResult
            {
                if (result == null)
                {
                    throw new ArgumentNullException("result");
                }
    
                TAsyncResult asyncResult = result as TAsyncResult;
    
                if (asyncResult == null)
                {
                    throw new ArgumentException("Invalid async result.", "result");
                }
    
                if (asyncResult.endCalled)
                {
                    throw new InvalidOperationException("Async object already ended.");
                }
    
                asyncResult.endCalled = true;
    
                if (!asyncResult.isCompleted)
                {
                    asyncResult.AsyncWaitHandle.WaitOne();
                }
    
                if (asyncResult.manualResetEvent != null)
                {
                    asyncResult.manualResetEvent.Close();
                }
    
                if (asyncResult.exception != null)
                {
                    throw asyncResult.exception;
                }
    
                return asyncResult;
            }
    
            protected void Complete(bool completedSynchronously)
            {
                if (isCompleted)
                {
                    throw new InvalidOperationException("This async result is already completed.");
                }
    
                this.completedSynchronously = completedSynchronously;
    
                if (completedSynchronously)
                {
                    this.isCompleted = true;
                }
                else
                {
                    lock (ThisLock)
                    {
                        this.isCompleted = true;
                        if (this.manualResetEvent != null)
                        {
                            this.manualResetEvent.Set();
                        }
                    }
                }
    
                if (callback != null)
                {
                    callback(this);
                }
            }
    
            protected void Complete(bool completedSynchronously, Exception exception)
            {
                this.exception = exception;
                Complete(completedSynchronously);
            }
        }
    

DiscoveryProxy를 호스팅하려면

  1. DiscoveryProxyExample 프로젝트에서 Program.cs 파일을 엽니다.

  2. 다음 using 문을 추가합니다.

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Discovery;
    
  3. Main() 메서드 안에서 다음 코드를 추가합니다. 그러면 DiscoveryProxy 클래스의 인스턴스가 만들어집니다.

    Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");
                Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");
    
                // Host the DiscoveryProxy service
                ServiceHost proxyServiceHost = new ServiceHost(new DiscoveryProxyService());
    
  4. 다음 코드를 추가하여 검색 끝점 및 알림 끝점을 추가합니다.

      try
                {                
                    // Add DiscoveryEndpoint to receive Probe and Resolve messages
                    DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));
                    discoveryEndpoint.IsSystemEndpoint = false;
    
                    // Add AnnouncementEndpoint to receive Hello and Bye announcement messages
                    AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));                
    
                    proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);
                    proxyServiceHost.AddServiceEndpoint(announcementEndpoint);
    
                    proxyServiceHost.Open();
    
                    Console.WriteLine("Proxy Service started.");
                    Console.WriteLine();
                    Console.WriteLine("Press <ENTER> to terminate the service.");
                    Console.WriteLine();
                    Console.ReadLine();
    
                    proxyServiceHost.Close();
                }
                catch (CommunicationException e)
                {
                    Console.WriteLine(e.Message);
                }
                catch (TimeoutException e)
                {
                    Console.WriteLine(e.Message);
                }   
    
                if (proxyServiceHost.State != CommunicationState.Closed)
                {
                    Console.WriteLine("Aborting the service...");
                    proxyServiceHost.Abort();
                }
    

검색 프록시의 구현을 완료했습니다. 방법: 검색 프록시에 등록할 검색 가능한 서비스 구현으로 이동하십시오.

예제

다음은 이 항목에서 사용되는 전체 코드 목록입니다.

    // DiscoveryProxy.cs
    //----------------------------------------------------------------
    // Copyright (c) Microsoft Corporation.  All rights reserved.
    //----------------------------------------------------------------
    
    using System;
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.ServiceModel.Discovery;
    using System.Xml;
    
    namespace Microsoft.Samples.Discovery
    {
        // Implement DiscoveryProxy by extending the DiscoveryProxy class and overriding the abstract methods
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
        public class DiscoveryProxyService : DiscoveryProxy
        {
            // Repository to store EndpointDiscoveryMetadata. A database or a flat file could also be used instead.
            Dictionary<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;
    
            public DiscoveryProxyService()
            {
                this.onlineServices = new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>();
            }
    
            // OnBeginOnlineAnnouncement method is called when a Hello message is received by the Proxy
            protected override IAsyncResult OnBeginOnlineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
            {        
                this.AddOnlineService(endpointDiscoveryMetadata);
                return new OnOnlineAnnouncementAsyncResult(callback, state);
            }
    
            protected override void OnEndOnlineAnnouncement(IAsyncResult result)
            {
                OnOnlineAnnouncementAsyncResult.End(result);
            }
    
            // OnBeginOfflineAnnouncement method is called when a Bye message is received by the Proxy
            protected override IAsyncResult OnBeginOfflineAnnouncement(DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata endpointDiscoveryMetadata, AsyncCallback callback, object state)
            {
                this.RemoveOnlineService(endpointDiscoveryMetadata);
                return new OnOfflineAnnouncementAsyncResult(callback, state);
            }
    
            protected override void OnEndOfflineAnnouncement(IAsyncResult result)
            {
                OnOfflineAnnouncementAsyncResult.End(result);
            }
    
            // OnBeginFind method is called when a Probe request message is received by the Proxy
            protected override IAsyncResult OnBeginFind(FindRequestContext findRequestContext, AsyncCallback callback, object state)
            {
                this.MatchFromOnlineService(findRequestContext);
                return new OnFindAsyncResult(callback, state);
            }
    
            protected override void OnEndFind(IAsyncResult result)
            {
                OnFindAsyncResult.End(result);
            }
    
            // OnBeginFind method is called when a Resolve request message is received by the Proxy
            protected override IAsyncResult OnBeginResolve(ResolveCriteria resolveCriteria, AsyncCallback callback, object state)
            {
                return new OnResolveAsyncResult(this.MatchFromOnlineService(resolveCriteria), callback, state);
            }
    
            protected override EndpointDiscoveryMetadata OnEndResolve(IAsyncResult result)
            {
                return OnResolveAsyncResult.End(result);
            }
    
            // The following are helper methods required by the Proxy implementation
            void AddOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata)
            {
                lock (this.onlineServices)
                {
                    this.onlineServices[endpointDiscoveryMetadata.Address] = endpointDiscoveryMetadata;                
                }
    
                PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Adding");
            }
    
            void RemoveOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata)
            {
                if (endpointDiscoveryMetadata != null)
                {
                    lock (this.onlineServices)
                    {
                        this.onlineServices.Remove(endpointDiscoveryMetadata.Address);                    
                    }
    
                    PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Removing");
                }    
            }
    
            void MatchFromOnlineService(FindRequestContext findRequestContext)
            {
                lock (this.onlineServices)
                {
                    foreach (EndpointDiscoveryMetadata endpointDiscoveryMetadata in this.onlineServices.Values)
                    {
                        if (findRequestContext.Criteria.IsMatch(endpointDiscoveryMetadata))
                        {
                            findRequestContext.AddMatchingEndpoint(endpointDiscoveryMetadata);
                        }
                    }
                }
            }
    
            EndpointDiscoveryMetadata MatchFromOnlineService(ResolveCriteria criteria)
            {
                EndpointDiscoveryMetadata matchingEndpoint = null;
                lock (this.onlineServices)
                {
                    foreach (EndpointDiscoveryMetadata endpointDiscoveryMetadata in this.onlineServices.Values)
                    {
                        if (criteria.Address == endpointDiscoveryMetadata.Address)
                        {
                            matchingEndpoint = endpointDiscoveryMetadata;
                        }
                    }
                }
                return matchingEndpoint;
            }
    
            void PrintDiscoveryMetadata(EndpointDiscoveryMetadata endpointDiscoveryMetadata, string verb)
            {
                Console.WriteLine("\n**** " + verb + " service of the following type from cache. ");
                foreach (XmlQualifiedName contractName in endpointDiscoveryMetadata.ContractTypeNames)
                {
                    Console.WriteLine("** " + contractName.ToString());
                    break;
                }
                Console.WriteLine("**** Operation Completed");
            }
    
            sealed class OnOnlineAnnouncementAsyncResult : AsyncResult
            {
                public OnOnlineAnnouncementAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
    
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnOnlineAnnouncementAsyncResult>(result);
                }
            }
    
            sealed class OnOfflineAnnouncementAsyncResult : AsyncResult
            {
                public OnOfflineAnnouncementAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
    
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnOfflineAnnouncementAsyncResult>(result);
                }
            }
    
            sealed class OnFindAsyncResult : AsyncResult
            {
                public OnFindAsyncResult(AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.Complete(true);
                }
        
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<OnFindAsyncResult>(result);
                }
            }
        
            sealed class OnResolveAsyncResult : AsyncResult
            {
                EndpointDiscoveryMetadata matchingEndpoint;
        
                public OnResolveAsyncResult(EndpointDiscoveryMetadata matchingEndpoint, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.matchingEndpoint = matchingEndpoint;
                    this.Complete(true);
                }
        
                public static EndpointDiscoveryMetadata End(IAsyncResult result)
                {
                    OnResolveAsyncResult thisPtr = AsyncResult.End<OnResolveAsyncResult>(result);
                    return thisPtr.matchingEndpoint;
                }
            }
        }
    }
    // AsyncResult.cs
    //----------------------------------------------------------------
    // Copyright (c) Microsoft Corporation.  All rights reserved.
    //----------------------------------------------------------------
    
    using System;
    using System.Threading;
    
    namespace Microsoft.Samples.Discovery
    {
        abstract class AsyncResult : IAsyncResult
        {
            AsyncCallback callback;
            bool completedSynchronously;
            bool endCalled;
            Exception exception;
            bool isCompleted;
            ManualResetEvent manualResetEvent;
            object state;
            object thisLock;
    
            protected AsyncResult(AsyncCallback callback, object state)
            {
                this.callback = callback;
                this.state = state;
                this.thisLock = new object();
            }
    
            public object AsyncState
            {
                get
                {
                    return state;
                }
            }
    
            public WaitHandle AsyncWaitHandle
            {
                get
                {
                    if (manualResetEvent != null)
                    {
                        return manualResetEvent;
                    }
                    lock (ThisLock)
                    {
                        if (manualResetEvent == null)
                        {
                            manualResetEvent = new ManualResetEvent(isCompleted);
                        }
                    }
                    return manualResetEvent;
                }
            }
    
            public bool CompletedSynchronously
            {
                get
                {
                    return completedSynchronously;
                }
            }
    
            public bool IsCompleted
            {
                get
                {
                    return isCompleted;
                }
            }
    
            object ThisLock
            {
                get
                {
                    return this.thisLock;
                }
            }
    
            protected static TAsyncResult End<TAsyncResult>(IAsyncResult result)
                where TAsyncResult : AsyncResult
            {
                if (result == null)
                {
                    throw new ArgumentNullException("result");
                }
    
                TAsyncResult asyncResult = result as TAsyncResult;
    
                if (asyncResult == null)
                {
                    throw new ArgumentException("Invalid async result.", "result");
                }
    
                if (asyncResult.endCalled)
                {
                    throw new InvalidOperationException("Async object already ended.");
                }
    
                asyncResult.endCalled = true;
    
                if (!asyncResult.isCompleted)
                {
                    asyncResult.AsyncWaitHandle.WaitOne();
                }
    
                if (asyncResult.manualResetEvent != null)
                {
                    asyncResult.manualResetEvent.Close();
                }
    
                if (asyncResult.exception != null)
                {
                    throw asyncResult.exception;
                }
    
                return asyncResult;
            }
    
            protected void Complete(bool completedSynchronously)
            {
                if (isCompleted)
                {
                    throw new InvalidOperationException("This async result is already completed.");
                }
    
                this.completedSynchronously = completedSynchronously;
    
                if (completedSynchronously)
                {
                    this.isCompleted = true;
                }
                else
                {
                    lock (ThisLock)
                    {
                        this.isCompleted = true;
                        if (this.manualResetEvent != null)
                        {
                            this.manualResetEvent.Set();
                        }
                    }
                }
    
                if (callback != null)
                {
                    callback(this);
                }
            }
    
            protected void Complete(bool completedSynchronously, Exception exception)
            {
                this.exception = exception;
                Complete(completedSynchronously);
            }
        }
    }
// program.cs
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------

using System;
using System.ServiceModel;
using System.ServiceModel.Discovery;

namespace Microsoft.Samples.Discovery
{
    class Program
    {
        public static void Main()
        {
            Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");
            Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");

            // Host the DiscoveryProxy service
            ServiceHost proxyServiceHost = new ServiceHost(new DiscoveryProxyService());

            try
            {                
                // Add DiscoveryEndpoint to receive Probe and Resolve messages
                DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));
                discoveryEndpoint.IsSystemEndpoint = false;

                // Add AnnouncementEndpoint to receive Hello and Bye announcement messages
                AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));                

                proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);
                proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

                proxyServiceHost.Open();

                Console.WriteLine("Proxy Service started.");
                Console.WriteLine();
                Console.WriteLine("Press <ENTER> to terminate the service.");
                Console.WriteLine();
                Console.ReadLine();

                proxyServiceHost.Close();
            }
            catch (CommunicationException e)
            {
                Console.WriteLine(e.Message);
            }
            catch (TimeoutException e)
            {
                Console.WriteLine(e.Message);
            }   

            if (proxyServiceHost.State != CommunicationState.Closed)
            {
                Console.WriteLine("Aborting the service...");
                proxyServiceHost.Abort();
            }
        }
    }
}

참고 항목

작업

방법: 검색 프록시에 등록할 검색 가능한 서비스 구현
방법: 검색 프록시를 사용하여 서비스를 찾는 클라이언트 응용 프로그램 구현
방법: 검색 프록시 테스트

개념

WCF Discovery 개요