방법: 검색 프록시 구현
이 항목에서는 검색 프록시를 구현하는 방법에 대해 설명합니다. WCF(Windows Communication Foundation)의 검색 기능에 대한 자세한 내용은 WCF Discovery 개요를 참조하십시오. 검색 프록시는 DiscoveryProxy 추상 클래스를 확장하는 클래스를 만들어 구현할 수 있습니다. 이 샘플에서는 많은 다른 지원 클래스가 정의되고 사용됩니다. 이러한 클래스에는 OnResolveAsyncResult
, OnFindAsyncResult
및 AsyncResult
가 포함됩니다. 이러한 클래스는 IAsyncResult 인터페이스를 구현합니다. IAsyncResult에 대한 자세한 내용은 System.IAsyncResult 인터페이스를 참조하십시오.
이 항목에서는 검색 프록시 구현을 크게 다음 세 부분으로 나누어서 설명합니다.
데이터 저장소를 포함하고 DiscoveryProxy 추상 클래스를 확장하는 클래스 정의
AsyncResult
도우미 클래스 구현검색 프록시 호스팅
새 콘솔 응용 프로그램 프로젝트를 만들려면
Visual Studio 2010을 시작합니다.
새 콘솔 응용 프로그램 프로젝트를 만듭니다. 프로젝트 이름을
DiscoveryProxy
로 지정하고 솔루션 이름을DiscoveryProxyExample
로 지정합니다.프로젝트에 대한 다음 참조를 추가합니다.
System.ServiceModel.dll
System.Servicemodel.Discovery.dll
주의: 이러한 어셈블리는 4.0 이상 버전이어야 합니다.
ProxyDiscoveryService 클래스를 구현하려면
프로젝트에 새 코드 파일을 추가하고 이름을 DiscoveryProxy.cs로 지정합니다.
DiscoveryProxy.cs에 다음 using 문을 추가합니다.
using System; using System.Collections.Generic; using System.ServiceModel; using System.ServiceModel.Discovery; using System.Xml;
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 { }
DiscoveryProxy
클래스 내에서 등록된 서비스를 저장할 사전을 정의합니다.// Repository to store EndpointDiscoveryMetadata. Dictionary<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;
사전을 초기화하는 생성자를 정의합니다.
public DiscoveryProxyService() { this.onlineServices = new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>(); }
검색 프록시 캐시를 업데이트하는 데 사용되는 메서드를 정의하려면
AddOnlineservice
메서드를 구현하여 캐시에 서비스를 추가합니다. 이 메서드는 프록시가 알림 메시지를 받을 때마다 호출됩니다.void AddOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata) { lock (this.onlineServices) { this.onlineServices[endpointDiscoveryMetadata.Address] = endpointDiscoveryMetadata; } PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Adding"); }
캐시에서 서비스를 제거하는 데 사용되는
RemoveOnlineService
메서드를 구현합니다.void RemoveOnlineService(EndpointDiscoveryMetadata endpointDiscoveryMetadata) { if (endpointDiscoveryMetadata != null) { lock (this.onlineServices) { this.onlineServices.Remove(endpointDiscoveryMetadata.Address); } PrintDiscoveryMetadata(endpointDiscoveryMetadata, "Removing"); } }
서비스와 사전의 서비스를 일치시킬
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; }
검색 프록시가 수행하는 작업을 콘솔에 텍스트로 출력하는
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"); }
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; } }
검색 프록시 기능을 구현하는 메서드를 정의하려면
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); }
OnEndOnlineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 알림 메시지 처리를 완료할 때 호출됩니다.
protected override void OnEndOnlineAnnouncement(IAsyncResult result) { OnOnlineAnnouncementAsyncResult.End(result); }
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); }
OnEndOfflineAnnouncement 메서드를 재정의합니다. 이 메서드는 검색 프록시가 오프라인 알림 메시지 처리를 완료할 때 호출됩니다.
protected override void OnEndOfflineAnnouncement(IAsyncResult result) { OnOfflineAnnouncementAsyncResult.End(result); }
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); }
OnEndFind 메서드를 재정의합니다. 이 메서드는 검색 프록시가 찾기 요청 처리를 완료할 때 호출됩니다.
protected override void OnEndFind(IAsyncResult result) { OnFindAsyncResult.End(result); }
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); }
OnEndResolve 메서드를 재정의합니다. 이 메서드는 검색 프록시가 확인 메시지 처리를 완료할 때 호출됩니다.
protected override EndpointDiscoveryMetadata OnEndResolve(IAsyncResult result) { return OnResolveAsyncResult.End(result); }
OnBegin.. / OnEnd.. 메서드는 후속 검색 작업에 대한 논리를 제공합니다. 예를 들어 OnBeginFind 및 OnEndFind 메서드는 검색 프록시에 대한 찾기 논리를 구현합니다. 검색 프록시가 프로브 메시지를 받으면 클라이언트에 응답을 보내기 위해 이러한 메서드가 실행됩니다. 찾기 논리는 원하는 대로 수정할 수 있습니다. 예를 들어 찾기 작업의 일부로 알고리즘 또는 응용 프로그램별 XML 메타데이터 구문 분석을 통해 사용자 지정 범위 일치를 통합할 수 있습니다.
AsyncResult 클래스를 구현하려면
다양한 비동기 결과 클래스를 파생시키는 데 사용되는 추상 기본 클래스 AsyncResult를 정의합니다.
AsyncResult.cs라는 새 코드 파일을 만듭니다.
AsyncResult.cs에 다음
using
문을 추가합니다.using System; using System.Threading;
다음 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를 호스팅하려면
DiscoveryProxyExample 프로젝트에서 Program.cs 파일을 엽니다.
다음
using
문을 추가합니다.using System; using System.ServiceModel; using System.ServiceModel.Discovery;
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());
다음 코드를 추가하여 검색 끝점 및 알림 끝점을 추가합니다.
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();
}
}
}
}
참고 항목
작업
방법: 검색 프록시에 등록할 검색 가능한 서비스 구현
방법: 검색 프록시를 사용하여 서비스를 찾는 클라이언트 응용 프로그램 구현
방법: 검색 프록시 테스트